From 95bfe3c137bf3c8cceed2877ff35c7d563c7e750 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 12:39:54 -0800 Subject: [PATCH 001/245] Italicizing the required fields sentence --- src/registrar/templates/includes/required_fields.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/includes/required_fields.html b/src/registrar/templates/includes/required_fields.html index 58612a284..c710644c5 100644 --- a/src/registrar/templates/includes/required_fields.html +++ b/src/registrar/templates/includes/required_fields.html @@ -1,3 +1,3 @@

- Required fields are marked with an asterisk (*). + Required fields are marked with an asterisk (*).

From faa2eaa40a256640e5a0f82e84dedd38b74761ef Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 13:20:19 -0800 Subject: [PATCH 002/245] Changed urbanization label --- src/registrar/forms/application_wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index a70c23e52..bccc9179b 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -268,7 +268,7 @@ class OrganizationContactForm(RegistrarForm): ) urbanization = forms.CharField( required=False, - label="Urbanization (Puerto Rico only)", + label="Urbanization (required for Puerto Rico only)", ) def clean_federal_agency(self): From 61475f6cb05653273359318b336278ac1ed1547c Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 13:25:30 -0800 Subject: [PATCH 003/245] Changed urbanization label --- ...omainapplication_more_organization_information_and_more.py | 2 +- src/registrar/migrations/0018_domaininformation.py | 2 +- .../0027_alter_domaininformation_address_line1_and_more.py | 4 ++-- src/registrar/models/domain_application.py | 2 +- src/registrar/models/domain_information.py | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py index 49df16fbb..4fdcdfeaf 100644 --- a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py +++ b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py @@ -106,7 +106,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domainapplication", name="urbanization", - field=models.TextField(blank=True, help_text="Urbanization (Puerto Rico only)", null=True), + field=models.TextField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), ), migrations.AlterField( model_name="domainapplication", diff --git a/src/registrar/migrations/0018_domaininformation.py b/src/registrar/migrations/0018_domaininformation.py index 582a6e244..931d99d4a 100644 --- a/src/registrar/migrations/0018_domaininformation.py +++ b/src/registrar/migrations/0018_domaininformation.py @@ -146,7 +146,7 @@ class Migration(migrations.Migration): "urbanization", models.TextField( blank=True, - help_text="Urbanization (Puerto Rico only)", + help_text="Urbanization (required for Puerto Rico only)", null=True, ), ), diff --git a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py index 9f362c956..97912334e 100644 --- a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py +++ b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py @@ -45,9 +45,9 @@ class Migration(migrations.Migration): name="urbanization", field=models.TextField( blank=True, - help_text="Urbanization (Puerto Rico only)", + help_text="Urbanization (required for Puerto Rico only)", null=True, - verbose_name="Urbanization (Puerto Rico only)", + verbose_name="Urbanization (required for Puerto Rico only)", ), ), ] diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 86b8a0f7a..5045311b3 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -465,7 +465,7 @@ class DomainApplication(TimeStampedModel): urbanization = models.TextField( null=True, blank=True, - help_text="Urbanization (Puerto Rico only)", + help_text="Urbanization (required for Puerto Rico only)", ) about_your_organization = models.TextField( diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index d2bc5c53d..4080f357b 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -131,8 +131,8 @@ class DomainInformation(TimeStampedModel): urbanization = models.TextField( null=True, blank=True, - help_text="Urbanization (Puerto Rico only)", - verbose_name="Urbanization (Puerto Rico only)", + help_text="Urbanization (required for Puerto Rico only)", + verbose_name="Urbanization (required for Puerto Rico only)", ) about_your_organization = models.TextField( From 94adf2246dc4b3c832dfb758c20b6beb1a3c44a2 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 14:34:51 -0800 Subject: [PATCH 004/245] Added optional to name server labels above 2 --- src/registrar/views/domain.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 88fad1567..9a0e2ea68 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -253,6 +253,7 @@ class DomainNameserversView(DomainFormBaseView): form.fields["server"].required = True else: form.fields["server"].required = False + form.fields["server"].label += f" (optional)" form.fields["domain"].initial = self.object.name return formset From 7b9bbb939056ea1c27490c7a7ea24756847c7c2c Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 14:50:38 -0800 Subject: [PATCH 005/245] fix python syntax --- src/registrar/views/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 9a0e2ea68..3aa7cc9df 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -253,7 +253,7 @@ class DomainNameserversView(DomainFormBaseView): form.fields["server"].required = True else: form.fields["server"].required = False - form.fields["server"].label += f" (optional)" + form.fields["server"].label += " (optional)" form.fields["domain"].initial = self.object.name return formset From 3f1ac333f8716da6463ad62d4461aa283019f9e1 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 14:59:29 -0800 Subject: [PATCH 006/245] added "(optional)" to instances of Street address 2 fields --- src/registrar/forms/application_wizard.py | 2 +- ...omainapplication_more_organization_information_and_more.py | 2 +- src/registrar/migrations/0018_domaininformation.py | 2 +- .../0026_alter_domainapplication_address_line2_and_more.py | 4 ++-- .../0027_alter_domaininformation_address_line1_and_more.py | 4 ++-- src/registrar/models/domain_application.py | 2 +- src/registrar/models/domain_information.py | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index bccc9179b..972aa42c6 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -244,7 +244,7 @@ class OrganizationContactForm(RegistrarForm): ) address_line2 = forms.CharField( required=False, - label="Street address line 2", + label="Street address line 2 (optional)", ) city = forms.CharField( label="City", diff --git a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py index 4fdcdfeaf..c48d95188 100644 --- a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py +++ b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py @@ -31,7 +31,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domainapplication", name="address_line2", - field=models.CharField(blank=True, help_text="Street address line 2", max_length=15, null=True), + field=models.CharField(blank=True, help_text="Street address line 2 (optional)", max_length=15, null=True), ), migrations.AlterField( model_name="domainapplication", diff --git a/src/registrar/migrations/0018_domaininformation.py b/src/registrar/migrations/0018_domaininformation.py index 931d99d4a..3d1a1f9b3 100644 --- a/src/registrar/migrations/0018_domaininformation.py +++ b/src/registrar/migrations/0018_domaininformation.py @@ -117,7 +117,7 @@ class Migration(migrations.Migration): "address_line2", models.CharField( blank=True, - help_text="Street address line 2", + help_text="Street address line 2 (optional)", max_length=15, null=True, ), diff --git a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py index 77da9e79c..ccc897500 100644 --- a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py +++ b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py @@ -12,11 +12,11 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domainapplication", name="address_line2", - field=models.TextField(blank=True, help_text="Street address line 2", null=True), + field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True), ), migrations.AlterField( model_name="domaininformation", name="address_line2", - field=models.TextField(blank=True, help_text="Street address line 2", null=True), + field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True), ), ] diff --git a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py index 97912334e..e4f87702a 100644 --- a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py +++ b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py @@ -24,9 +24,9 @@ class Migration(migrations.Migration): name="address_line2", field=models.TextField( blank=True, - help_text="Street address line 2", + help_text="Street address line 2 (optional)", null=True, - verbose_name="Street address line 2", + verbose_name="Street address line 2 (optional)", ), ), migrations.AlterField( diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 5045311b3..6418ff308 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -442,7 +442,7 @@ class DomainApplication(TimeStampedModel): address_line2 = models.TextField( null=True, blank=True, - help_text="Street address line 2", + help_text="Street address line 2 (optional)", ) city = models.TextField( null=True, diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 4080f357b..6e20f4c5e 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -106,8 +106,8 @@ class DomainInformation(TimeStampedModel): address_line2 = models.TextField( null=True, blank=True, - help_text="Street address line 2", - verbose_name="Street address line 2", + help_text="Street address line 2 (optional)", + verbose_name="Street address line 2 (optional)", ) city = models.TextField( null=True, From 78aa47771930a39d04755d3e4711402db26308f1 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 15:10:27 -0800 Subject: [PATCH 007/245] added "(optional)" to instances of Middle name fields --- src/registrar/forms/application_wizard.py | 6 +++--- src/registrar/migrations/0001_initial.py | 2 +- ...tiondomain_email_transitiondomain_first_name_and_more.py | 2 +- src/registrar/models/contact.py | 2 +- src/registrar/models/transition_domain.py | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 972aa42c6..247700ac6 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -331,7 +331,7 @@ class AuthorizingOfficialForm(RegistrarForm): ) middle_name = forms.CharField( required=False, - label="Middle name", + label="Middle name (optional)", ) last_name = forms.CharField( label="Last name / family name", @@ -529,7 +529,7 @@ class YourContactForm(RegistrarForm): ) middle_name = forms.CharField( required=False, - label="Middle name", + label="Middle name (optional)", ) last_name = forms.CharField( label="Last name / family name", @@ -558,7 +558,7 @@ class OtherContactsForm(RegistrarForm): ) middle_name = forms.CharField( required=False, - label="Middle name", + label="Middle name (optional)", ) last_name = forms.CharField( label="Last name / family name", diff --git a/src/registrar/migrations/0001_initial.py b/src/registrar/migrations/0001_initial.py index 8c50c750d..052fd0628 100644 --- a/src/registrar/migrations/0001_initial.py +++ b/src/registrar/migrations/0001_initial.py @@ -135,7 +135,7 @@ class Migration(migrations.Migration): ), ( "middle_name", - models.TextField(blank=True, help_text="Middle name", null=True), + models.TextField(blank=True, help_text="Middle name (optional)", null=True), ), ( "last_name", diff --git a/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py b/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py index 4fcb66713..68633dccc 100644 --- a/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py +++ b/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py @@ -33,7 +33,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="transitiondomain", name="middle_name", - field=models.TextField(blank=True, help_text="Middle name", null=True), + field=models.TextField(blank=True, help_text="Middle name (optional)", null=True), ), migrations.AddField( model_name="transitiondomain", diff --git a/src/registrar/models/contact.py b/src/registrar/models/contact.py index 41ed9f2c5..0a7ba4fa1 100644 --- a/src/registrar/models/contact.py +++ b/src/registrar/models/contact.py @@ -26,7 +26,7 @@ class Contact(TimeStampedModel): middle_name = models.TextField( null=True, blank=True, - help_text="Middle name", + help_text="Middle name (optional)", ) last_name = models.TextField( null=True, diff --git a/src/registrar/models/transition_domain.py b/src/registrar/models/transition_domain.py index 3f1c8d641..3679320a7 100644 --- a/src/registrar/models/transition_domain.py +++ b/src/registrar/models/transition_domain.py @@ -83,7 +83,7 @@ class TransitionDomain(TimeStampedModel): middle_name = models.TextField( null=True, blank=True, - help_text="Middle name", + help_text="Middle name (optional)", ) last_name = models.TextField( null=True, From e58586bb18ee50f00ebb468cfc0877cf5f4f0483 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 17:10:59 -0800 Subject: [PATCH 008/245] Added (optional) to security email form label --- src/registrar/forms/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py index 6cb5b338f..c99ab48ea 100644 --- a/src/registrar/forms/domain.py +++ b/src/registrar/forms/domain.py @@ -152,7 +152,7 @@ class ContactForm(forms.ModelForm): class DomainSecurityEmailForm(forms.Form): """Form for adding or editing a security email to a domain.""" - security_email = forms.EmailField(label="Security email", required=False) + security_email = forms.EmailField(label="Security email (optional)", required=False) class DomainOrgNameAddressForm(forms.ModelForm): From 6fc513ed54f6b57ff9c130bfcefbbdf7e9104c37 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 17:56:04 -0800 Subject: [PATCH 009/245] updated domain app pages' required fields sentence --- .../templates/application_about_your_organization.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/registrar/templates/application_about_your_organization.html b/src/registrar/templates/application_about_your_organization.html index f1b843b7a..867a48dee 100644 --- a/src/registrar/templates/application_about_your_organization.html +++ b/src/registrar/templates/application_about_your_organization.html @@ -13,7 +13,10 @@ {% endblock %} {% block form_required_fields_help_text %} -

*This question is required.

+

+ Required fields are marked with an asterisk (*). +

{% endblock %} {% block form_fields %} From cd9c4878e4fad1aef7fae63e6d36e9a2063419f1 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 17 Nov 2023 18:10:00 -0800 Subject: [PATCH 010/245] updated domain app pages' required fields sentence --- src/registrar/templates/application_dotgov_domain.html | 5 ++++- src/registrar/templates/application_org_election.html | 5 ++++- src/registrar/templates/application_org_federal.html | 5 ++++- src/registrar/templates/application_org_type.html | 5 ++++- src/registrar/templates/application_purpose.html | 6 +++++- 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/registrar/templates/application_dotgov_domain.html b/src/registrar/templates/application_dotgov_domain.html index 0d11203ad..47c109acc 100644 --- a/src/registrar/templates/application_dotgov_domain.html +++ b/src/registrar/templates/application_dotgov_domain.html @@ -47,7 +47,10 @@ these initial checks, we’ll verify that it meets all of our requirements once you complete and submit the rest of this form.

-

* This question is required.

+

+ Required fields are marked with an asterisk (*). +

{% with attr_aria_describedby="domain_instructions domain_instructions2" %} {# attr_validate / validate="domain" invokes code in get-gov.js #} diff --git a/src/registrar/templates/application_org_election.html b/src/registrar/templates/application_org_election.html index 45776af5c..ee41f9eae 100644 --- a/src/registrar/templates/application_org_election.html +++ b/src/registrar/templates/application_org_election.html @@ -13,7 +13,10 @@ {% endblock %} {% block form_required_fields_help_text %} -

* This question is required.

+

+ Required fields are marked with an asterisk (*). +

{% endblock %} {% block form_fields %} diff --git a/src/registrar/templates/application_org_federal.html b/src/registrar/templates/application_org_federal.html index 28cabadd0..c9924929d 100644 --- a/src/registrar/templates/application_org_federal.html +++ b/src/registrar/templates/application_org_federal.html @@ -8,7 +8,10 @@ {% endblock %} {% block form_required_fields_help_text %} -

* This question is required.

+

+ Required fields are marked with an asterisk (*). +

{% endblock %} diff --git a/src/registrar/templates/application_org_type.html b/src/registrar/templates/application_org_type.html index 80d599920..7538bed8d 100644 --- a/src/registrar/templates/application_org_type.html +++ b/src/registrar/templates/application_org_type.html @@ -9,7 +9,10 @@ {% endblock %} {% block form_required_fields_help_text %} -

* This question is required.

+

+ Required fields are marked with an asterisk (*). +

{% endblock %} diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/application_purpose.html index 5135e6678..93d6a9429 100644 --- a/src/registrar/templates/application_purpose.html +++ b/src/registrar/templates/application_purpose.html @@ -13,7 +13,11 @@ Read about * This question is required.

+

+ Required fields are marked with an asterisk (*). +

+ {% endblock %} From 1a57a3e26da2c3c90f4e638e3ecfd3f5baab1737 Mon Sep 17 00:00:00 2001 From: Erin <121973038+erinysong@users.noreply.github.com> Date: Mon, 20 Nov 2023 12:18:06 -0800 Subject: [PATCH 011/245] Revert migration data and create migration for optional text --- src/registrar/migrations/0001_initial.py | 2 +- ..._more_organization_information_and_more.py | 2 +- .../migrations/0018_domaininformation.py | 2 +- ...omainapplication_address_line2_and_more.py | 2 +- ...omaininformation_address_line1_and_more.py | 4 +- ...il_transitiondomain_first_name_and_more.py | 2 +- ...0047_alter_contact_middle_name_and_more.py | 37 +++++++++++++++++++ 7 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 src/registrar/migrations/0047_alter_contact_middle_name_and_more.py diff --git a/src/registrar/migrations/0001_initial.py b/src/registrar/migrations/0001_initial.py index 052fd0628..8c50c750d 100644 --- a/src/registrar/migrations/0001_initial.py +++ b/src/registrar/migrations/0001_initial.py @@ -135,7 +135,7 @@ class Migration(migrations.Migration): ), ( "middle_name", - models.TextField(blank=True, help_text="Middle name (optional)", null=True), + models.TextField(blank=True, help_text="Middle name", null=True), ), ( "last_name", diff --git a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py index c48d95188..4fdcdfeaf 100644 --- a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py +++ b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py @@ -31,7 +31,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domainapplication", name="address_line2", - field=models.CharField(blank=True, help_text="Street address line 2 (optional)", max_length=15, null=True), + field=models.CharField(blank=True, help_text="Street address line 2", max_length=15, null=True), ), migrations.AlterField( model_name="domainapplication", diff --git a/src/registrar/migrations/0018_domaininformation.py b/src/registrar/migrations/0018_domaininformation.py index 3d1a1f9b3..931d99d4a 100644 --- a/src/registrar/migrations/0018_domaininformation.py +++ b/src/registrar/migrations/0018_domaininformation.py @@ -117,7 +117,7 @@ class Migration(migrations.Migration): "address_line2", models.CharField( blank=True, - help_text="Street address line 2 (optional)", + help_text="Street address line 2", max_length=15, null=True, ), diff --git a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py index ccc897500..798d5c476 100644 --- a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py +++ b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py @@ -12,7 +12,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domainapplication", name="address_line2", - field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True), + field=models.TextField(blank=True, help_text="Street address line 2", null=True), ), migrations.AlterField( model_name="domaininformation", diff --git a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py index e4f87702a..97912334e 100644 --- a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py +++ b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py @@ -24,9 +24,9 @@ class Migration(migrations.Migration): name="address_line2", field=models.TextField( blank=True, - help_text="Street address line 2 (optional)", + help_text="Street address line 2", null=True, - verbose_name="Street address line 2 (optional)", + verbose_name="Street address line 2", ), ), migrations.AlterField( diff --git a/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py b/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py index 68633dccc..4fcb66713 100644 --- a/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py +++ b/src/registrar/migrations/0046_transitiondomain_email_transitiondomain_first_name_and_more.py @@ -33,7 +33,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name="transitiondomain", name="middle_name", - field=models.TextField(blank=True, help_text="Middle name (optional)", null=True), + field=models.TextField(blank=True, help_text="Middle name", null=True), ), migrations.AddField( model_name="transitiondomain", diff --git a/src/registrar/migrations/0047_alter_contact_middle_name_and_more.py b/src/registrar/migrations/0047_alter_contact_middle_name_and_more.py new file mode 100644 index 000000000..acd3355fe --- /dev/null +++ b/src/registrar/migrations/0047_alter_contact_middle_name_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 4.2.7 on 2023-11-20 20:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0046_transitiondomain_email_transitiondomain_first_name_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="contact", + name="middle_name", + field=models.TextField(blank=True, help_text="Middle name (optional)", null=True), + ), + migrations.AlterField( + model_name="domainapplication", + name="address_line2", + field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True), + ), + migrations.AlterField( + model_name="domaininformation", + name="address_line2", + field=models.TextField( + blank=True, + help_text="Street address line 2 (optional)", + null=True, + verbose_name="Street address line 2 (optional)", + ), + ), + migrations.AlterField( + model_name="transitiondomain", + name="middle_name", + field=models.TextField(blank=True, help_text="Middle name (optional)", null=True), + ), + ] From 79c1fd63efac649430b9fd1bccd7ff0dca0faf6a Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 20 Nov 2023 14:09:38 -0800 Subject: [PATCH 012/245] update label for Contact Form --- src/registrar/forms/domain.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py index c99ab48ea..14522512e 100644 --- a/src/registrar/forms/domain.py +++ b/src/registrar/forms/domain.py @@ -147,6 +147,9 @@ class ContactForm(forms.ModelForm): for field_name in self.required: self.fields[field_name].required = True + + # Set custom form label + self.fields["middle_name"].label = "Middle name (optional)" class DomainSecurityEmailForm(forms.Form): From e1ca58a623dcef4bd9af5ca9b98f693f8f9f4244 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 20 Nov 2023 14:46:32 -0800 Subject: [PATCH 013/245] undo erroneous changes to migration files --- ...omainapplication_more_organization_information_and_more.py | 2 +- src/registrar/migrations/0018_domaininformation.py | 2 +- .../0026_alter_domainapplication_address_line2_and_more.py | 2 +- .../0027_alter_domaininformation_address_line1_and_more.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py index 4fdcdfeaf..49df16fbb 100644 --- a/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py +++ b/src/registrar/migrations/0007_domainapplication_more_organization_information_and_more.py @@ -106,7 +106,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domainapplication", name="urbanization", - field=models.TextField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), + field=models.TextField(blank=True, help_text="Urbanization (Puerto Rico only)", null=True), ), migrations.AlterField( model_name="domainapplication", diff --git a/src/registrar/migrations/0018_domaininformation.py b/src/registrar/migrations/0018_domaininformation.py index 931d99d4a..582a6e244 100644 --- a/src/registrar/migrations/0018_domaininformation.py +++ b/src/registrar/migrations/0018_domaininformation.py @@ -146,7 +146,7 @@ class Migration(migrations.Migration): "urbanization", models.TextField( blank=True, - help_text="Urbanization (required for Puerto Rico only)", + help_text="Urbanization (Puerto Rico only)", null=True, ), ), diff --git a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py index 798d5c476..77da9e79c 100644 --- a/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py +++ b/src/registrar/migrations/0026_alter_domainapplication_address_line2_and_more.py @@ -17,6 +17,6 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domaininformation", name="address_line2", - field=models.TextField(blank=True, help_text="Street address line 2 (optional)", null=True), + field=models.TextField(blank=True, help_text="Street address line 2", null=True), ), ] diff --git a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py index 97912334e..ac1255f22 100644 --- a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py +++ b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py @@ -45,9 +45,9 @@ class Migration(migrations.Migration): name="urbanization", field=models.TextField( blank=True, - help_text="Urbanization (required for Puerto Rico only)", + verbose_name="Urbanization (Puerto Rico only)", null=True, - verbose_name="Urbanization (required for Puerto Rico only)", + verbose_name="Urbanization (Puerto Rico only)", ), ), ] From e2542023ec8586e5839b5baeebad4693dc7d0616 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 20 Nov 2023 14:48:14 -0800 Subject: [PATCH 014/245] undo erroneous changes to migration files --- .../0027_alter_domaininformation_address_line1_and_more.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py index ac1255f22..9f362c956 100644 --- a/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py +++ b/src/registrar/migrations/0027_alter_domaininformation_address_line1_and_more.py @@ -45,7 +45,7 @@ class Migration(migrations.Migration): name="urbanization", field=models.TextField( blank=True, - verbose_name="Urbanization (Puerto Rico only)", + help_text="Urbanization (Puerto Rico only)", null=True, verbose_name="Urbanization (Puerto Rico only)", ), From e52954f984b109cc048d36e06d2b5ab950184755 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 20 Nov 2023 16:20:37 -0700 Subject: [PATCH 015/245] Implement API --- src/api/report_views.py | 32 ++++++++++++++++++++++++++++++++ src/registrar/config/urls.py | 3 +++ 2 files changed, 35 insertions(+) create mode 100644 src/api/report_views.py diff --git a/src/api/report_views.py b/src/api/report_views.py new file mode 100644 index 000000000..2e479a8a1 --- /dev/null +++ b/src/api/report_views.py @@ -0,0 +1,32 @@ +"""Internal API views""" +from django.apps import apps +from django.views.decorators.http import require_http_methods +from django.http import FileResponse, JsonResponse + +import requests + + +from registrar.utility import csv_export +from login_required import login_not_required + +@require_http_methods(["GET"]) +@login_not_required +def get_current_full(request): + # Generate the CSV file + with open("current-full.csv", "w") as file: + csv_export.export_data_full_to_csv(file) + + # Serve the CSV file + response = FileResponse(open('current-full.csv', 'rb')) + return response + +@require_http_methods(["GET"]) +@login_not_required +def get_current_federal(request): + # Generate the CSV file + with open("current-federal.csv", "w") as file: + csv_export.export_data_federal_to_csv(file) + + # Serve the CSV file + response = FileResponse(open('current-federal.csv', 'rb')) + return response diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index c00d1c589..e71f1388e 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -12,6 +12,7 @@ from registrar import views from registrar.views.application import Step from registrar.views.utility import always_404 from api.views import available +from api.report_views import get_current_federal, get_current_full APPLICATION_NAMESPACE = views.ApplicationWizard.URL_NAMESPACE application_urls = [ @@ -73,6 +74,8 @@ urlpatterns = [ path("openid/", include("djangooidc.urls")), path("register/", include((application_urls, APPLICATION_NAMESPACE))), path("api/v1/available/", available, name="available"), + path("api/v1/get-report/current-federal", get_current_federal, name="get-current-federal"), + path("api/v1/get-report/current-full", get_current_full, name="get-current-full"), path( "todo", lambda r: always_404(r, "We forgot to include this link, sorry."), From 1f309584ff5b50a6546e16a017769c3fe2f06df6 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 20 Nov 2023 17:02:42 -0800 Subject: [PATCH 016/245] update .gov domain page --- src/registrar/templates/application_dotgov_domain.html | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/registrar/templates/application_dotgov_domain.html b/src/registrar/templates/application_dotgov_domain.html index 47c109acc..9037c70cf 100644 --- a/src/registrar/templates/application_dotgov_domain.html +++ b/src/registrar/templates/application_dotgov_domain.html @@ -38,8 +38,7 @@
-

What .gov domain do you want? *

+

What .gov domain do you want?

After you enter your domain, we’ll make sure it’s @@ -47,11 +46,6 @@ these initial checks, we’ll verify that it meets all of our requirements once you complete and submit the rest of this form.

-

- Required fields are marked with an asterisk (*). -

- {% with attr_aria_describedby="domain_instructions domain_instructions2" %} {# attr_validate / validate="domain" invokes code in get-gov.js #} {% with append_gov=True attr_validate="domain" add_label_class="usa-sr-only" %} @@ -69,7 +63,7 @@
-

Alternative domains

+

Alternative domains (optional)

Are there other domains you’d like if we can’t give From bac2d94b75d0668993adc4737846b44098b7c500 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 20 Nov 2023 17:20:32 -0800 Subject: [PATCH 017/245] update .gov domain page --- src/registrar/forms/application_wizard.py | 1 - src/registrar/templates/application_dotgov_domain.html | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 247700ac6..094b3815f 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -405,7 +405,6 @@ class AlternativeDomainForm(RegistrarForm): alternative_domain = forms.CharField( required=False, - label="Alternative domain", ) diff --git a/src/registrar/templates/application_dotgov_domain.html b/src/registrar/templates/application_dotgov_domain.html index 9037c70cf..bd3c4a473 100644 --- a/src/registrar/templates/application_dotgov_domain.html +++ b/src/registrar/templates/application_dotgov_domain.html @@ -67,7 +67,7 @@

Are there other domains you’d like if we can’t give - you your first choice? Entering alternative domains is optional.

+ you your first choice?

{% with attr_aria_describedby="alt_domain_instructions" %} {# attr_validate / validate="domain" invokes code in get-gov.js #} From c342fdf2a6f71c3970bbd3fd60eb672bc1d47435 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 20 Nov 2023 17:53:33 -0800 Subject: [PATCH 018/245] update .gov domain page --- src/registrar/forms/application_wizard.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 094b3815f..aa763b534 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -405,6 +405,7 @@ class AlternativeDomainForm(RegistrarForm): alternative_domain = forms.CharField( required=False, + label="", ) From f96af00a5188d0c6542c2ca076bf6678318ddad7 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 10:35:54 -0800 Subject: [PATCH 019/245] got rid of the required fields line in the purpose app page --- src/registrar/templates/application_purpose.html | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/application_purpose.html index 93d6a9429..3a225b880 100644 --- a/src/registrar/templates/application_purpose.html +++ b/src/registrar/templates/application_purpose.html @@ -12,16 +12,6 @@ Read about
- Required fields are marked with an asterisk (*). -

- -{% endblock %} - - - {% block form_fields %} {% with attr_maxlength=1000 add_label_class="usa-sr-only" %} {% input_with_errors forms.0.purpose %} From 07d9bd76cd7dd7b5a8be2d931d24f994d2402a60 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 12:04:51 -0800 Subject: [PATCH 020/245] got rid of required fields line in one-field forms --- src/registrar/templates/application_org_election.html | 9 +-------- src/registrar/templates/application_org_type.html | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/registrar/templates/application_org_election.html b/src/registrar/templates/application_org_election.html index ee41f9eae..7d3e092cb 100644 --- a/src/registrar/templates/application_org_election.html +++ b/src/registrar/templates/application_org_election.html @@ -3,7 +3,7 @@ {% block form_instructions %}

- Is your organization an election office? * + Is your organization an election office?

An election office is a government entity whose primary responsibility is overseeing elections and/or conducting voter registration.

@@ -12,13 +12,6 @@ {% endblock %} -{% block form_required_fields_help_text %} -

- Required fields are marked with an asterisk (*). -

-{% endblock %} - {% block form_fields %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} {% input_with_errors forms.0.is_election_board %} diff --git a/src/registrar/templates/application_org_type.html b/src/registrar/templates/application_org_type.html index 7538bed8d..801079647 100644 --- a/src/registrar/templates/application_org_type.html +++ b/src/registrar/templates/application_org_type.html @@ -3,18 +3,11 @@ {% block form_instructions %}

- What kind of U.S.-based government organization do you represent? * + What kind of U.S.-based government organization do you represent?

{% endblock %} -{% block form_required_fields_help_text %} -

- Required fields are marked with an asterisk (*). -

-{% endblock %} - {% block form_fields %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} From d3cf1ea01da18d00369019cb8369bbdaf31e3ad0 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 12:36:50 -0800 Subject: [PATCH 021/245] got rid of more required form fields --- .../templates/application_about_your_organization.html | 7 ------- src/registrar/templates/application_org_federal.html | 9 +-------- src/registrar/templates/application_org_type.html | 3 +++ 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/registrar/templates/application_about_your_organization.html b/src/registrar/templates/application_about_your_organization.html index 867a48dee..4bf9d21f2 100644 --- a/src/registrar/templates/application_about_your_organization.html +++ b/src/registrar/templates/application_about_your_organization.html @@ -12,13 +12,6 @@

{% endblock %} -{% block form_required_fields_help_text %} -

- Required fields are marked with an asterisk (*). -

-{% endblock %} - {% block form_fields %} {% with attr_maxlength=1000 add_label_class="usa-sr-only" %} {% input_with_errors forms.0.about_your_organization %} diff --git a/src/registrar/templates/application_org_federal.html b/src/registrar/templates/application_org_federal.html index c9924929d..6c8851af2 100644 --- a/src/registrar/templates/application_org_federal.html +++ b/src/registrar/templates/application_org_federal.html @@ -3,17 +3,10 @@ {% block form_instructions %}

- Which federal branch is your organization in? * + Which federal branch is your organization in?

{% endblock %} -{% block form_required_fields_help_text %} -

- Required fields are marked with an asterisk (*). -

-{% endblock %} - {% block form_fields %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} diff --git a/src/registrar/templates/application_org_type.html b/src/registrar/templates/application_org_type.html index 801079647..ef3fb82f7 100644 --- a/src/registrar/templates/application_org_type.html +++ b/src/registrar/templates/application_org_type.html @@ -8,6 +8,9 @@ {% endblock %} +{% block form_required_fields_help_text %} +{# commented out so it does not appear on this page #} +{% endblock %} {% block form_fields %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} From bca311b8ca2717d5d5ddce5a6e923ae215daab62 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:28:31 -0700 Subject: [PATCH 022/245] Scripts to generate the file and api update to grab what exists --- .github/workflows/daily-csv-upload.yaml | 49 +++++++++++++++++++ src/api/report_views.py | 32 ------------ src/api/views.py | 25 +++++++++- src/registrar/config/urls.py | 4 +- .../generate_current_federal_report.py | 35 +++++++++++++ .../commands/generate_current_full_report.py | 35 +++++++++++++ 6 files changed, 145 insertions(+), 35 deletions(-) create mode 100644 .github/workflows/daily-csv-upload.yaml delete mode 100644 src/api/report_views.py create mode 100644 src/registrar/management/commands/generate_current_federal_report.py create mode 100644 src/registrar/management/commands/generate_current_full_report.py diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml new file mode 100644 index 000000000..729b5bd16 --- /dev/null +++ b/.github/workflows/daily-csv-upload.yaml @@ -0,0 +1,49 @@ +name: Upload current-full.csv and current-federal.csv + +on: + push: + paths-ignore: + - 'docs/**' + - '**.md' + - '.gitignore' + branches: + - rjm + pull_request: + paths-ignore: + - 'docs/**' + - '**.md' + - '.gitignore' + branches: + - rjm + schedule: + # Runs every day at 5 AM UTC + - cron: '0 5 * * *' + +jobs: + upload_reports: + runs-on: ubuntu-latest + if: github.event_name == 'schedule' + steps: + - uses: actions/checkout@v3 + + - name: Install CF CLI + run: | + curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx + sudo mv cf /usr/local/bin + + - name: Login to cloud.gov + run: | + cf api https://api.fr.cloud.gov + cf auth ${{ secrets.CF_USERNAME }} ${{ secrets.CF_PASSWORD }} + cf target -o ${{ secrets.CF_ORG }} -s ${{ secrets.CF_SPACE }} + + - name: Run task + run: cf run-task my-app "/tmp/lifecycle/shell -c './manage.py generate_current_full_and_federal_reports.py'" + + - name: Commit and push CSV files + run: | + git config --global user.name 'GitHub Actions' + git config --global user.email 'actions@github.com' + git add current-full.csv current-federal.csv + git commit -m "Update CSV files" + git push \ No newline at end of file diff --git a/src/api/report_views.py b/src/api/report_views.py deleted file mode 100644 index 2e479a8a1..000000000 --- a/src/api/report_views.py +++ /dev/null @@ -1,32 +0,0 @@ -"""Internal API views""" -from django.apps import apps -from django.views.decorators.http import require_http_methods -from django.http import FileResponse, JsonResponse - -import requests - - -from registrar.utility import csv_export -from login_required import login_not_required - -@require_http_methods(["GET"]) -@login_not_required -def get_current_full(request): - # Generate the CSV file - with open("current-full.csv", "w") as file: - csv_export.export_data_full_to_csv(file) - - # Serve the CSV file - response = FileResponse(open('current-full.csv', 'rb')) - return response - -@require_http_methods(["GET"]) -@login_not_required -def get_current_federal(request): - # Generate the CSV file - with open("current-federal.csv", "w") as file: - csv_export.export_data_federal_to_csv(file) - - # Serve the CSV file - response = FileResponse(open('current-federal.csv', 'rb')) - return response diff --git a/src/api/views.py b/src/api/views.py index 2cb23a9b2..1ed8a0888 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,7 +1,7 @@ """Internal API views""" from django.apps import apps from django.views.decorators.http import require_http_methods -from django.http import JsonResponse +from django.http import FileResponse, HttpResponse, JsonResponse import requests @@ -89,3 +89,26 @@ def available(request, domain=""): return JsonResponse({"available": False, "message": DOMAIN_API_MESSAGES["unavailable"]}) except Exception: return JsonResponse({"available": False, "message": DOMAIN_API_MESSAGES["error"]}) + +@require_http_methods(["GET"]) +@login_not_required +def get_current_full(request): + # Open the CSV file + file_path = './migrationData/current-full.csv' + return serve_file(file_path) + +@require_http_methods(["GET"]) +@login_not_required +def get_current_federal(request): + # Open the CSV file + file_path = './migrationData/current-federal.csv' + return serve_file(file_path) + +def serve_file(file_path): + """Downloads a file based on a given filepath. Returns a 404 if not found.""" + if os.path.exists(file_path): + # Serve the CSV file + response = FileResponse(open(file_path, 'rb')) + return response + else: + return HttpResponse("File not found", status=404) \ No newline at end of file diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index e71f1388e..6ded44913 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -11,8 +11,8 @@ from django.views.generic import RedirectView from registrar import views from registrar.views.application import Step from registrar.views.utility import always_404 -from api.views import available -from api.report_views import get_current_federal, get_current_full +from api.views import available, get_current_federal, get_current_full + APPLICATION_NAMESPACE = views.ApplicationWizard.URL_NAMESPACE application_urls = [ diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py new file mode 100644 index 000000000..f07a35c65 --- /dev/null +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -0,0 +1,35 @@ +"""Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" +import glob +import logging + +import os +import shutil + +from django.core.management import BaseCommand + +from registrar.management.commands.utility.terminal_helper import TerminalHelper +from registrar.utility import csv_export + + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = "" + + def add_arguments(self, parser): + """Add our two filename arguments.""" + parser.add_argument("--directory", default="migrationdata", help="Desired directory") + + def handle(self, **options): + # Ensures a slash is added + directory = os.path.join(options.get("directory"), "") + logger.info("Generating report...") + self.generate_current_federal_report(directory) + logger.info(f"Success! Created {directory}current-federal.csv") + + def generate_current_federal_report(self, directory): + """Creates a current-full.csv file under the migrationdata/ directory""" + file_path = os.path.join(directory, "current-federal.csv") + with open(file_path, "w") as file: + csv_export.export_data_federal_to_csv(file) diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py new file mode 100644 index 000000000..49f2127a8 --- /dev/null +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -0,0 +1,35 @@ +"""Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" +import glob +import logging + +import os +import shutil + +from django.core.management import BaseCommand + +from registrar.management.commands.utility.terminal_helper import TerminalHelper +from registrar.utility import csv_export + + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = "" + + def add_arguments(self, parser): + """Add our two filename arguments.""" + parser.add_argument("--directory", default="migrationdata", help="Desired directory") + + def handle(self, **options): + # Ensures a slash is added + directory = os.path.join(options.get("directory"), "") + logger.info("Generating report...") + self.generate_current_full_report(directory) + logger.info(f"Success! Created {directory}current-full.csv") + + def generate_current_full_report(self, directory): + """Creates a current-full.csv file under the migrationdata/ directory""" + file_path = os.path.join(directory, "current-full.csv") + with open(file_path, "w") as file: + csv_export.export_data_full_to_csv(file) From 6779c2ab0b0f9ab4fde2bd87e117d17b48eba584 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 13:29:09 -0800 Subject: [PATCH 023/245] got rid of required line text the right way --- .../templates/application_about_your_organization.html | 4 ++++ src/registrar/templates/application_org_election.html | 4 ++++ src/registrar/templates/application_org_federal.html | 3 +++ src/registrar/templates/application_purpose.html | 4 ++++ src/registrar/templates/application_requirements.html | 4 ++++ 5 files changed, 19 insertions(+) diff --git a/src/registrar/templates/application_about_your_organization.html b/src/registrar/templates/application_about_your_organization.html index 4bf9d21f2..0d384b4f5 100644 --- a/src/registrar/templates/application_about_your_organization.html +++ b/src/registrar/templates/application_about_your_organization.html @@ -12,6 +12,10 @@

{% endblock %} +{% block form_required_fields_help_text %} +{# commented out so it does not appear on this page #} +{% endblock %} + {% block form_fields %} {% with attr_maxlength=1000 add_label_class="usa-sr-only" %} {% input_with_errors forms.0.about_your_organization %} diff --git a/src/registrar/templates/application_org_election.html b/src/registrar/templates/application_org_election.html index 7d3e092cb..ce79f5b22 100644 --- a/src/registrar/templates/application_org_election.html +++ b/src/registrar/templates/application_org_election.html @@ -12,6 +12,10 @@ {% endblock %} +{% block form_required_fields_help_text %} +{# commented out so it does not appear on this page #} +{% endblock %} + {% block form_fields %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} {% input_with_errors forms.0.is_election_board %} diff --git a/src/registrar/templates/application_org_federal.html b/src/registrar/templates/application_org_federal.html index 6c8851af2..8a5a574b0 100644 --- a/src/registrar/templates/application_org_federal.html +++ b/src/registrar/templates/application_org_federal.html @@ -7,6 +7,9 @@ {% endblock %} +{% block form_required_fields_help_text %} +{# commented out so it does not appear on this page #} +{% endblock %} {% block form_fields %} {% with add_class="usa-radio__input--tile" add_legend_class="usa-sr-only" %} diff --git a/src/registrar/templates/application_purpose.html b/src/registrar/templates/application_purpose.html index 3a225b880..8747a34c7 100644 --- a/src/registrar/templates/application_purpose.html +++ b/src/registrar/templates/application_purpose.html @@ -12,6 +12,10 @@ Read about
We understand the critical importance of the availability of .gov domains. Suspending or terminating a .gov domain is reserved for prolonged, unresolved, serious violations where the registrant is non-responsive. We'll make extensive efforts to contact registrants and to identify potential solutions. We'll make reasonable accommodations for remediation timelines based on the severity of the issue.

{% endblock %} +{% block form_required_fields_help_text %} +{# commented out so it does not appear on this page #} +{% endblock %} + {% block form_fields %}
From d52359d1c58ea1f37efaf7b4425296b5a9c9831e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 21 Nov 2023 14:45:23 -0700 Subject: [PATCH 024/245] Yaml stub --- .github/workflows/daily-csv-upload.yaml | 39 ++++++------------------- src/api/views.py | 1 + 2 files changed, 10 insertions(+), 30 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 729b5bd16..3863c36c4 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -1,28 +1,17 @@ name: Upload current-full.csv and current-federal.csv on: - push: - paths-ignore: - - 'docs/**' - - '**.md' - - '.gitignore' - branches: - - rjm - pull_request: - paths-ignore: - - 'docs/**' - - '**.md' - - '.gitignore' - branches: - - rjm schedule: # Runs every day at 5 AM UTC - cron: '0 5 * * *' + jobs: upload_reports: runs-on: ubuntu-latest - if: github.event_name == 'schedule' + env: + CF_USERNAME: CF_${{ github.event.inputs.environment }}_USERNAME + CF_PASSWORD: CF_${{ github.event.inputs.environment }}_PASSWORD steps: - uses: actions/checkout@v3 @@ -31,19 +20,9 @@ jobs: curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx sudo mv cf /usr/local/bin - - name: Login to cloud.gov - run: | - cf api https://api.fr.cloud.gov - cf auth ${{ secrets.CF_USERNAME }} ${{ secrets.CF_PASSWORD }} - cf target -o ${{ secrets.CF_ORG }} -s ${{ secrets.CF_SPACE }} - - - name: Run task - run: cf run-task my-app "/tmp/lifecycle/shell -c './manage.py generate_current_full_and_federal_reports.py'" + - name: Generate current-federal.csv + run: cf run-task getgov-za "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" + - - name: Commit and push CSV files - run: | - git config --global user.name 'GitHub Actions' - git config --global user.email 'actions@github.com' - git add current-full.csv current-federal.csv - git commit -m "Update CSV files" - git push \ No newline at end of file + - name: Generate current-full.csv + run: cf run-task getgov-za "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report.py'" diff --git a/src/api/views.py b/src/api/views.py index 1ed8a0888..9653a906e 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,4 +1,5 @@ """Internal API views""" +import os from django.apps import apps from django.views.decorators.http import require_http_methods from django.http import FileResponse, HttpResponse, JsonResponse From 3d177198ea0f1f785bdc90ae547fea8bf4b9d0dd Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 17:20:53 -0800 Subject: [PATCH 025/245] testing way to get rid of asterisk --- src/registrar/templates/django/forms/label.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index da90a372a..7f4e0e784 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,6 +8,8 @@ {{ field.label }} {% endif %} {% if widget.attrs.required %} - * + {% if widget.label != "I read and agree to the requirements for operating .gov domains." %} + * + {% endif %} {% endif %} From d5e662a78d1578b70ba5081e8dd3c035c8bcd708 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 17:30:42 -0800 Subject: [PATCH 026/245] trying another way of getting rid of asterisk --- src/registrar/templates/django/forms/label.html | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 7f4e0e784..17d528d4e 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -7,9 +7,4 @@ {% else %} {{ field.label }} {% endif %} - {% if widget.attrs.required %} - {% if widget.label != "I read and agree to the requirements for operating .gov domains." %} - * - {% endif %} - {% endif %} From b3be667183f7cdcd5814bcfe1e93e6d94571f815 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 18:31:47 -0800 Subject: [PATCH 027/245] trying another way to get rid of asterisk in one-field forms --- src/registrar/forms/application_wizard.py | 6 +++++- src/registrar/templates/django/forms/label.html | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index aa763b534..ee0c19605 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -170,10 +170,14 @@ class TribalGovernmentForm(RegistrarForm): ) tribe_name = forms.CharField( - label="What is the name of the tribe you represent?", + label1="What is the name of the tribe you represent? " + label2="*", + label={label1+label2} error_messages={"required": "Enter the tribe you represent."}, ) + tribe_name.widget.attrs.update({"class": "no_asterisk"}) + def clean(self): """Needs to be either state or federally recognized.""" if not (self.cleaned_data["federally_recognized_tribe"] or self.cleaned_data["state_recognized_tribe"]): diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 17d528d4e..9a6fcad69 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -7,4 +7,9 @@ {% else %} {{ field.label }} {% endif %} + From eaaf8e16d46a3c1679aa96c0b4262aeaffa08cb9 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 18:34:33 -0800 Subject: [PATCH 028/245] forgot comma --- src/registrar/forms/application_wizard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index ee0c19605..7312fafc4 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -170,9 +170,9 @@ class TribalGovernmentForm(RegistrarForm): ) tribe_name = forms.CharField( - label1="What is the name of the tribe you represent? " + label1="What is the name of the tribe you represent? ", label2="*", - label={label1+label2} + label={label1+label2}, error_messages={"required": "Enter the tribe you represent."}, ) From 9773abe12794c94819ea7eecbccf7f8d011c5382 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 18:42:27 -0800 Subject: [PATCH 029/245] trying another way to get rid of asterisk in one-field forms --- src/registrar/forms/application_wizard.py | 6 +----- src/registrar/templates/django/forms/label.html | 7 ++++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 7312fafc4..8aa528d3d 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -170,14 +170,10 @@ class TribalGovernmentForm(RegistrarForm): ) tribe_name = forms.CharField( - label1="What is the name of the tribe you represent? ", - label2="*", - label={label1+label2}, + label="What is the name of the tribe you represent? ", error_messages={"required": "Enter the tribe you represent."}, ) - tribe_name.widget.attrs.update({"class": "no_asterisk"}) - def clean(self): """Needs to be either state or federally recognized.""" if not (self.cleaned_data["federally_recognized_tribe"] or self.cleaned_data["state_recognized_tribe"]): diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 9a6fcad69..6924c1155 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -7,9 +7,10 @@ {% else %} {{ field.label }} {% endif %} - + From e619939ff27d289f145c9af35c96f9f007b8dd12 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 19:05:18 -0800 Subject: [PATCH 030/245] trying another way to get rid of asterisk in one-field forms --- src/registrar/forms/application_wizard.py | 1 + src/registrar/templates/django/forms/label.html | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 8aa528d3d..28220bd6b 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -638,3 +638,4 @@ class RequirementsForm(RegistrarForm): "required": ("Check the box if you read and agree to the requirements for operating .gov domains.") }, ) + diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 6924c1155..05ca21795 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,7 +8,7 @@ {{ field.label }} {% endif %} {% if widget.attrs.required %} - {% if widget.label != "What is the name of the tribe you represent? " %} + {% if widget.attrs.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From 508b1c8c4863a72d9e526349beed8e3160906b78 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 19:13:01 -0800 Subject: [PATCH 031/245] trying another way to get rid of asterisk in one-field forms --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 05ca21795..9ad4b021e 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,7 +8,7 @@ {{ field.label }} {% endif %} {% if widget.attrs.required %} - {% if widget.attrs.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From ddc1298651dc3c02a7b755669dbfd7c941c1bcd8 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 19:30:36 -0800 Subject: [PATCH 032/245] get rid of asterisk in no other contacts page --- src/registrar/forms/application_wizard.py | 5 ++--- src/registrar/templates/django/forms/label.html | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 28220bd6b..89d77e811 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -610,8 +610,7 @@ class NoOtherContactsForm(RegistrarForm): required=True, # label has to end in a space to get the label_suffix to show label=( - "Please explain why there are no other employees from your organization" - " we can contact to help us assess your eligibility for a .gov domain." + "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." ), widget=forms.Textarea(), ) @@ -638,4 +637,4 @@ class RequirementsForm(RegistrarForm): "required": ("Check the box if you read and agree to the requirements for operating .gov domains.") }, ) - + diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 9ad4b021e..1ada1b089 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -9,7 +9,10 @@ {% endif %} {% if widget.attrs.required %} {% if field.label != "I read and agree to the requirements for operating .gov domains." %} - * + {% if field.label != "Please explain why there are no other employees from your organization we can contact to help us assess your + eligibility for a .gov domain." %} + * + {% endif %} {% endif %} {% endif %} From dff6e91ac8e4a49210a29379fb6e92e49a2c344e Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 19:36:59 -0800 Subject: [PATCH 033/245] undoing last push --- src/registrar/templates/django/forms/label.html | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 1ada1b089..af62e0605 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -9,10 +9,7 @@ {% endif %} {% if widget.attrs.required %} {% if field.label != "I read and agree to the requirements for operating .gov domains." %} - {% if field.label != "Please explain why there are no other employees from your organization we can contact to help us assess your - eligibility for a .gov domain." %} * - {% endif %} {% endif %} {% endif %} From 717ff7c3765ca468673735c1bce2368b8879a4b6 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 19:42:52 -0800 Subject: [PATCH 034/245] get rid of asterisk in no other contacts page --- src/registrar/templates/django/forms/label.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index af62e0605..9cf18bd49 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,7 +8,8 @@ {{ field.label }} {% endif %} {% if widget.attrs.required %} - {% if field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != "I read and agree to the requirements for operating .gov domains." or field.label != "Please explain why there are no other employees from your organization we can contact to help us assess your + eligibility for a .gov domain." %} * {% endif %} {% endif %} From 7cc6731a61d214b9ac1cd4aede14401bfeeb4544 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 19:50:50 -0800 Subject: [PATCH 035/245] undoing last push --- src/registrar/templates/django/forms/label.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 9cf18bd49..af62e0605 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,8 +8,7 @@ {{ field.label }} {% endif %} {% if widget.attrs.required %} - {% if field.label != "I read and agree to the requirements for operating .gov domains." or field.label != "Please explain why there are no other employees from your organization we can contact to help us assess your - eligibility for a .gov domain." %} + {% if field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From 6bd61743fbb687bfe7254d5cf31aee5c3090e28b Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 21 Nov 2023 19:59:36 -0800 Subject: [PATCH 036/245] get rid of asterisk in no other contacts page --- src/registrar/forms/application_wizard.py | 3 ++- src/registrar/templates/django/forms/label.html | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 89d77e811..7e88b49da 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -610,7 +610,8 @@ class NoOtherContactsForm(RegistrarForm): required=True, # label has to end in a space to get the label_suffix to show label=( - "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." + "Please explain why there are no other employees from your organization " + "we can contact to help us assess your eligibility for a .gov domain." ), widget=forms.Textarea(), ) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index af62e0605..beb09c17c 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -9,7 +9,9 @@ {% endif %} {% if widget.attrs.required %} {% if field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != "Please explain why there are no other employees from your organization" %} * + {% endif %} {% endif %} {% endif %} From d405d4ca7927bdff44ed46ad37b3e324814d3395 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:16:34 -0700 Subject: [PATCH 037/245] Test yaml --- .github/workflows/daily-csv-upload.yaml | 64 +++++++++++++++++++++---- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 3863c36c4..daf1fff19 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -1,28 +1,72 @@ name: Upload current-full.csv and current-federal.csv +run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: schedule: # Runs every day at 5 AM UTC - - cron: '0 5 * * *' - + # TODO: - cron: '0 5 * * *' + - cron: '*/5 * * * *' jobs: - upload_reports: + variables: + if: | + startsWith(github.head_ref, 'ab/') + || startsWith(github.head_ref, 'bl/') + || startsWith(github.head_ref, 'rjm/') + || startsWith(github.head_ref, 'rb/') + || startsWith(github.head_ref, 'ko/') + || startsWith(github.head_ref, 'gd/') + || startsWith(github.head_ref, 'za/') + || startsWith(github.head_ref, 'rh/') + || startsWith(github.head_ref, 'nl/') + || startsWith(github.head_ref, 'dk/') + || startsWith(github.head_ref, 'es/') + || startsWith(github.head_ref, 'ky/') + outputs: + environment: ${{ steps.var.outputs.environment}} + runs-on: "ubuntu-latest" + steps: + - name: Setting global variables + uses: actions/github-script@v6 + id: var + with: + script: | + core.setOutput('environment', '${{ github.head_ref }}'.split("/")[0]); + deploy: runs-on: ubuntu-latest - env: - CF_USERNAME: CF_${{ github.event.inputs.environment }}_USERNAME - CF_PASSWORD: CF_${{ github.event.inputs.environment }}_PASSWORD + needs: [variables] steps: - uses: actions/checkout@v3 - - - name: Install CF CLI + - name: Install CF CLI run: | curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx sudo mv cf /usr/local/bin - name: Generate current-federal.csv - run: cf run-task getgov-za "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" + uses: 18f/cg-deploy-action@main + with: + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_org: cisa-dotgov + cf_space: ${{ github.event.inputs.environment }} + full_command: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" - - name: Generate current-full.csv run: cf run-task getgov-za "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report.py'" + + comment: + runs-on: ubuntu-latest + needs: [variables, deploy] + steps: + - uses: actions/github-script@v6 + env: + ENVIRONMENT: ${{ needs.variables.outputs.environment }} + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: '🥳 Successfully uploaded CSVs to **[${{ env.ENVIRONMENT }}](https://getgov-${{ env.ENVIRONMENT }}.app.cloud.gov/)**.' + }) From 9a872d200587fdda48eed383efb98429dd4a9888 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:23:07 -0700 Subject: [PATCH 038/245] Fix syntax error --- .github/workflows/daily-csv-upload.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index daf1fff19..68cbb53eb 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -37,7 +37,8 @@ jobs: needs: [variables] steps: - uses: actions/checkout@v3 - - name: Install CF CLI + + - name: Install CF CLI run: | curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx sudo mv cf /usr/local/bin From 45542f12f6208c0e79c6c74b140b2b2e390820a3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:36:53 -0700 Subject: [PATCH 039/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 68cbb53eb..9dc185ea8 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,10 +2,12 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: + pull_request: + schedule: # Runs every day at 5 AM UTC # TODO: - cron: '0 5 * * *' - - cron: '*/5 * * * *' + - cron: '*/2 * * * *' jobs: variables: @@ -37,7 +39,7 @@ jobs: needs: [variables] steps: - uses: actions/checkout@v3 - + - name: Install CF CLI run: | curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx From e2473f337d16776073c3541e95e4bcf5282694d3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:42:24 -0700 Subject: [PATCH 040/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 9dc185ea8..5e5226d15 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -47,11 +47,16 @@ jobs: - name: Generate current-federal.csv uses: 18f/cg-deploy-action@main + env: + DEPLOY_NOW: thanks + ENVIRONMENT: ${{ needs.variables.outputs.environment }} + CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME + CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD with: cf_username: ${{ secrets[env.CF_USERNAME] }} cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov - cf_space: ${{ github.event.inputs.environment }} + cf_space: ${{ env.ENVIRONMENT }} full_command: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" - name: Generate current-full.csv From f9b54a5a8df0165fa1b72bc5c0d93a1802db8a6c Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 22 Nov 2023 09:43:25 -0800 Subject: [PATCH 041/245] correcting syntax mistake --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index beb09c17c..991f4d846 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -9,7 +9,7 @@ {% endif %} {% if widget.attrs.required %} {% if field.label != "I read and agree to the requirements for operating .gov domains." %} - {% if field.label != "Please explain why there are no other employees from your organization" %} + {% if field.label != "Please explain why there are no other employees from your organization " %} * {% endif %} {% endif %} From 61cb536ef800bda19850d14342cac396485c5db7 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:51:08 -0700 Subject: [PATCH 042/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 5e5226d15..0b61a0339 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -34,7 +34,20 @@ jobs: with: script: | core.setOutput('environment', '${{ github.head_ref }}'.split("/")[0]); - deploy: + wait_for_deploy: + runs-on: ubuntu-latest + steps: + - name: Wait for deploy to complete + uses: fountainhead/action-wait-for-check@v1.0.0 + id: wait-for-deploy + with: + token: ${{ secrets.GITHUB_TOKEN }} + checkName: "deploy" # replace with the name of the deploy job + ref: ${{ github.event.pull_request.head.sha }} # the commit SHA of the head commit of the PR + timeoutSeconds: 600 # the maximum time to wait for the check to complete, in seconds + intervalSeconds: 10 # the time to wait between checks, in seconds + + upload_reports: runs-on: ubuntu-latest needs: [variables] steps: @@ -57,10 +70,10 @@ jobs: cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ env.ENVIRONMENT }} - full_command: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" + run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" - name: Generate current-full.csv - run: cf run-task getgov-za "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report.py'" + run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report.py'" comment: runs-on: ubuntu-latest From c490cec333962c83dc7933719f918070d982e662 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 22 Nov 2023 09:51:19 -0800 Subject: [PATCH 043/245] undoing what I just did --- src/registrar/forms/application_wizard.py | 3 +-- src/registrar/templates/django/forms/label.html | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 7e88b49da..89d77e811 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -610,8 +610,7 @@ class NoOtherContactsForm(RegistrarForm): required=True, # label has to end in a space to get the label_suffix to show label=( - "Please explain why there are no other employees from your organization " - "we can contact to help us assess your eligibility for a .gov domain." + "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." ), widget=forms.Textarea(), ) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 991f4d846..9ad4b021e 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -9,9 +9,7 @@ {% endif %} {% if widget.attrs.required %} {% if field.label != "I read and agree to the requirements for operating .gov domains." %} - {% if field.label != "Please explain why there are no other employees from your organization " %} - * - {% endif %} + * {% endif %} {% endif %} From 161e2583cb8d657d977ac3d611558a92335f29e9 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:53:30 -0700 Subject: [PATCH 044/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 0b61a0339..60f75cb5b 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -59,17 +59,6 @@ jobs: sudo mv cf /usr/local/bin - name: Generate current-federal.csv - uses: 18f/cg-deploy-action@main - env: - DEPLOY_NOW: thanks - ENVIRONMENT: ${{ needs.variables.outputs.environment }} - CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME - CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - with: - cf_username: ${{ secrets[env.CF_USERNAME] }} - cf_password: ${{ secrets[env.CF_PASSWORD] }} - cf_org: cisa-dotgov - cf_space: ${{ env.ENVIRONMENT }} run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" - name: Generate current-full.csv From 3ad42bf42e80d3659471c189c50215b5aaa54320 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 22 Nov 2023 09:59:22 -0800 Subject: [PATCH 045/245] trying another way to get rid of asterisk in one-field forms --- src/registrar/forms/application_wizard.py | 3 ++- src/registrar/templates/django/forms/label.html | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 89d77e811..7e88b49da 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -610,7 +610,8 @@ class NoOtherContactsForm(RegistrarForm): required=True, # label has to end in a space to get the label_suffix to show label=( - "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." + "Please explain why there are no other employees from your organization " + "we can contact to help us assess your eligibility for a .gov domain." ), widget=forms.Textarea(), ) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 9ad4b021e..aa7f68032 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -7,10 +7,11 @@ {% else %} {{ field.label }} {% endif %} - {% if widget.attrs.required %} - {% if field.label != "I read and agree to the requirements for operating .gov domains." %} - * - {% endif %} + + {% if widget.attrs.required %} + {% if field.label == "I read and agree to the requirements for operating .gov domains." %} + * {% endif %} + {% endif %} From 95273284cc0bee7bfd7f110a13a427ad20f6803f Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:00:40 -0700 Subject: [PATCH 046/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 60f75cb5b..99eff3ee0 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -66,7 +66,7 @@ jobs: comment: runs-on: ubuntu-latest - needs: [variables, deploy] + needs: [variables, upload_reports] steps: - uses: actions/github-script@v6 env: From d14da1460f00794772f56aed1107db86be2de3c6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:06:49 -0700 Subject: [PATCH 047/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 99eff3ee0..1036c251c 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -49,7 +49,7 @@ jobs: upload_reports: runs-on: ubuntu-latest - needs: [variables] + needs: [variables, wait_for_deploy] steps: - uses: actions/checkout@v3 @@ -58,6 +58,19 @@ jobs: curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx sudo mv cf /usr/local/bin + - name: Set login credentials + uses: 18f/cg-deploy-action@main + env: + DEPLOY_NOW: thanks + ENVIRONMENT: ${{ needs.variables.outputs.environment }} + CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME + CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD + with: + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_org: cisa-dotgov + cf_space: ${{ env.ENVIRONMENT }} + - name: Generate current-federal.csv run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" From 328e1fca956168b54939000855b394238b39cb6b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:10:48 -0700 Subject: [PATCH 048/245] Remove deploy now --- .github/workflows/daily-csv-upload.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 1036c251c..c73437cca 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -61,7 +61,6 @@ jobs: - name: Set login credentials uses: 18f/cg-deploy-action@main env: - DEPLOY_NOW: thanks ENVIRONMENT: ${{ needs.variables.outputs.environment }} CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD From dffca3b5879cac832038e4d090e537eef08e2cb2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:08:30 -0700 Subject: [PATCH 049/245] Test --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index c73437cca..e5af53f05 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -34,6 +34,7 @@ jobs: with: script: | core.setOutput('environment', '${{ github.head_ref }}'.split("/")[0]); + wait_for_deploy: runs-on: ubuntu-latest steps: @@ -59,7 +60,6 @@ jobs: sudo mv cf /usr/local/bin - name: Set login credentials - uses: 18f/cg-deploy-action@main env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME From 06835dbf44b2fcca05277dc4de6e2003e2272817 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:14:16 -0700 Subject: [PATCH 050/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index e5af53f05..4137b314c 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -60,6 +60,7 @@ jobs: sudo mv cf /usr/local/bin - name: Set login credentials + uses: 18f/cg-deploy-action@main env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME From 862339cd32a2ae99bb03cf25d89ec1167c562bff Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:24:32 -0700 Subject: [PATCH 051/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 4137b314c..370fd6ac1 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -60,16 +60,14 @@ jobs: sudo mv cf /usr/local/bin - name: Set login credentials - uses: 18f/cg-deploy-action@main + run: | + cf api https://api.fr.cloud.gov + cf auth ${{ secrets[env.CF_USERNAME] }} ${{ secrets[env.CF_PASSWORD] }} + cf target -o cisa-dotgov -s ${{ env.ENVIRONMENT }} env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - with: - cf_username: ${{ secrets[env.CF_USERNAME] }} - cf_password: ${{ secrets[env.CF_PASSWORD] }} - cf_org: cisa-dotgov - cf_space: ${{ env.ENVIRONMENT }} - name: Generate current-federal.csv run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" From 91cdd44d7f92c4260dd7e8e27b330b260627f90c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:30:24 -0700 Subject: [PATCH 052/245] Upload files --- .github/workflows/daily-csv-upload.yaml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 370fd6ac1..ef7e1e669 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -71,10 +71,14 @@ jobs: - name: Generate current-federal.csv run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" - + env: + ENVIRONMENT: ${{ needs.variables.outputs.environment }} + - name: Generate current-full.csv run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report.py'" - + env: + ENVIRONMENT: ${{ needs.variables.outputs.environment }} + comment: runs-on: ubuntu-latest needs: [variables, upload_reports] From 2de28edcc4b4abcda2d541fbaa934f0ab0cd8cb4 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 22 Nov 2023 11:39:46 -0800 Subject: [PATCH 053/245] fixing linting errors --- src/registrar/forms/application_wizard.py | 1 - src/registrar/forms/domain.py | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 7e88b49da..a862afc6c 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -638,4 +638,3 @@ class RequirementsForm(RegistrarForm): "required": ("Check the box if you read and agree to the requirements for operating .gov domains.") }, ) - diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py index e6cdba1b4..44d752199 100644 --- a/src/registrar/forms/domain.py +++ b/src/registrar/forms/domain.py @@ -153,7 +153,7 @@ class ContactForm(forms.ModelForm): for field_name in self.required: self.fields[field_name].required = True - + # Set custom form label self.fields["middle_name"].label = "Middle name (optional)" @@ -195,7 +195,6 @@ class AuthorizingOfficialContactForm(ContactForm): class DomainSecurityEmailForm(forms.Form): """Form for adding or editing a security email to a domain.""" - security_email = forms.EmailField( label="Security email (optional)", required=False, @@ -205,7 +204,6 @@ class DomainSecurityEmailForm(forms.Form): ) - class DomainOrgNameAddressForm(forms.ModelForm): """Form for updating the organization name and mailing address.""" From ff4773f8c71ab5ee1397511629e28603d4928ed9 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 12:51:03 -0700 Subject: [PATCH 054/245] Test command --- .github/workflows/daily-csv-upload.yaml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index ef7e1e669..2564d7188 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -43,10 +43,12 @@ jobs: id: wait-for-deploy with: token: ${{ secrets.GITHUB_TOKEN }} - checkName: "deploy" # replace with the name of the deploy job - ref: ${{ github.event.pull_request.head.sha }} # the commit SHA of the head commit of the PR - timeoutSeconds: 600 # the maximum time to wait for the check to complete, in seconds - intervalSeconds: 10 # the time to wait between checks, in seconds + checkName: "deploy" + ref: ${{ github.event.pull_request.head.sha }} + # the maximum time to wait for the check to complete, in seconds + timeoutSeconds: 600 + # the time to wait between checks, in seconds + intervalSeconds: 10 upload_reports: runs-on: ubuntu-latest @@ -70,7 +72,7 @@ jobs: CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - name: Generate current-federal.csv - run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report.py'" + run: cf run-task getgov-${{ env.ENVIRONMENT }} --wait --command "python manage.py generate_current_full_report.py --name current_full" env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} From 8e9dc8219028584a30a071c325a5a5cab63df3f2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:00:00 -0700 Subject: [PATCH 055/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 2564d7188..9c9bfacd8 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -72,7 +72,7 @@ jobs: CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - name: Generate current-federal.csv - run: cf run-task getgov-${{ env.ENVIRONMENT }} --wait --command "python manage.py generate_current_full_report.py --name current_full" + run: cf run-task getgov-${{ env.ENVIRONMENT }} "python manage.py generate_current_full_report.py" env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} From c070651a8de2181eac4d5b95ec34122d5839ad66 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:12:08 -0700 Subject: [PATCH 056/245] Fix incorrect paths --- .github/workflows/daily-csv-upload.yaml | 4 ++-- src/api/views.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 9c9bfacd8..d4cc0a700 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -72,12 +72,12 @@ jobs: CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - name: Generate current-federal.csv - run: cf run-task getgov-${{ env.ENVIRONMENT }} "python manage.py generate_current_full_report.py" + run: cf run-task getgov-${{ env.ENVIRONMENT }} "python manage.py generate_current_full_report" env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} - name: Generate current-full.csv - run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report.py'" + run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report'" env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} diff --git a/src/api/views.py b/src/api/views.py index 9653a906e..594ba3f22 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -95,14 +95,14 @@ def available(request, domain=""): @login_not_required def get_current_full(request): # Open the CSV file - file_path = './migrationData/current-full.csv' + file_path = '../migrationdata/current-full.csv' return serve_file(file_path) @require_http_methods(["GET"]) @login_not_required def get_current_federal(request): # Open the CSV file - file_path = './migrationData/current-federal.csv' + file_path = '../migrationdata/current-federal.csv' return serve_file(file_path) def serve_file(file_path): From 1cf841013f60bf00a73b9785ee6e37be9226be24 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 22 Nov 2023 12:40:21 -0800 Subject: [PATCH 057/245] fixing migration issue --- ...e_and_more.py => 0048_alter_contact_middle_name_and_more.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/registrar/migrations/{0047_alter_contact_middle_name_and_more.py => 0048_alter_contact_middle_name_and_more.py} (92%) diff --git a/src/registrar/migrations/0047_alter_contact_middle_name_and_more.py b/src/registrar/migrations/0048_alter_contact_middle_name_and_more.py similarity index 92% rename from src/registrar/migrations/0047_alter_contact_middle_name_and_more.py rename to src/registrar/migrations/0048_alter_contact_middle_name_and_more.py index acd3355fe..271264fc7 100644 --- a/src/registrar/migrations/0047_alter_contact_middle_name_and_more.py +++ b/src/registrar/migrations/0048_alter_contact_middle_name_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0046_transitiondomain_email_transitiondomain_first_name_and_more"), + ("registrar", "0047_transitiondomain_address_line_transitiondomain_city_and_more"), ] operations = [ From 7772a13834a4ea508daa174a0001d73f23cd63ea Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:45:52 -0700 Subject: [PATCH 058/245] Fix broken api --- src/api/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/views.py b/src/api/views.py index 594ba3f22..298e5fb8c 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -95,14 +95,14 @@ def available(request, domain=""): @login_not_required def get_current_full(request): # Open the CSV file - file_path = '../migrationdata/current-full.csv' + file_path = 'migrationdata/current-full.csv' return serve_file(file_path) @require_http_methods(["GET"]) @login_not_required def get_current_federal(request): # Open the CSV file - file_path = '../migrationdata/current-federal.csv' + file_path = 'migrationdata/current-federal.csv' return serve_file(file_path) def serve_file(file_path): From a97d891b7d28d3eb12eceaf6fd3e1546e666d1a6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:48:24 -0700 Subject: [PATCH 059/245] Test cron schedule --- .github/workflows/daily-csv-upload.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index d4cc0a700..0a408073c 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,12 +2,10 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: - pull_request: - schedule: # Runs every day at 5 AM UTC # TODO: - cron: '0 5 * * *' - - cron: '*/2 * * * *' + - cron: '*/1 * * * *' jobs: variables: From 339f9770e4c4e20b7f513c9277d2a1cb0c726c8f Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 22 Nov 2023 12:49:17 -0800 Subject: [PATCH 060/245] migrations --- ...domainapplication_urbanization_and_more.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/registrar/migrations/0049_alter_domainapplication_urbanization_and_more.py diff --git a/src/registrar/migrations/0049_alter_domainapplication_urbanization_and_more.py b/src/registrar/migrations/0049_alter_domainapplication_urbanization_and_more.py new file mode 100644 index 000000000..36a32cb25 --- /dev/null +++ b/src/registrar/migrations/0049_alter_domainapplication_urbanization_and_more.py @@ -0,0 +1,27 @@ +# Generated by Django 4.2.7 on 2023-11-22 20:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0048_alter_contact_middle_name_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="urbanization", + field=models.TextField(blank=True, help_text="Urbanization (required for Puerto Rico only)", null=True), + ), + migrations.AlterField( + model_name="domaininformation", + name="urbanization", + field=models.TextField( + blank=True, + help_text="Urbanization (required for Puerto Rico only)", + null=True, + verbose_name="Urbanization (required for Puerto Rico only)", + ), + ), + ] From f050618872ccdb99d6682c59a0b21ef3206cac5c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:53:25 -0700 Subject: [PATCH 061/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 0a408073c..d96012564 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -4,8 +4,7 @@ run-name: Upload current-full.csv and current-federal.csv for branch ${{ github. on: schedule: # Runs every day at 5 AM UTC - # TODO: - cron: '0 5 * * *' - - cron: '*/1 * * * *' + cron: '0 5 * * *' jobs: variables: @@ -93,5 +92,5 @@ jobs: issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: '🥳 Successfully uploaded CSVs to **[${{ env.ENVIRONMENT }}](https://getgov-${{ env.ENVIRONMENT }}.app.cloud.gov/)**.' + body: '🥳 Successfully uploaded current-full.csv and current-federal.csv to **[${{ env.ENVIRONMENT }}](https://getgov-${{ env.ENVIRONMENT }}.app.cloud.gov/)**.' }) From 1d70c5058a2520cc3f4473c83b7193f36f83b533 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 13:54:05 -0700 Subject: [PATCH 062/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index d96012564..76624fac6 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -4,7 +4,7 @@ run-name: Upload current-full.csv and current-federal.csv for branch ${{ github. on: schedule: # Runs every day at 5 AM UTC - cron: '0 5 * * *' + - cron: '0 5 * * *' jobs: variables: From bcf5c6bc5b733b695ff5ee331e46235d27440fb6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:00:06 -0700 Subject: [PATCH 063/245] Linting + fix tests --- src/api/views.py | 11 +++++++---- src/registrar/tests/test_url_auth.py | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/api/views.py b/src/api/views.py index 298e5fb8c..a565504df 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -91,25 +91,28 @@ def available(request, domain=""): except Exception: return JsonResponse({"available": False, "message": DOMAIN_API_MESSAGES["error"]}) + @require_http_methods(["GET"]) @login_not_required def get_current_full(request): # Open the CSV file - file_path = 'migrationdata/current-full.csv' + file_path = "migrationdata/current-full.csv" return serve_file(file_path) + @require_http_methods(["GET"]) @login_not_required def get_current_federal(request): # Open the CSV file - file_path = 'migrationdata/current-federal.csv' + file_path = "migrationdata/current-federal.csv" return serve_file(file_path) + def serve_file(file_path): """Downloads a file based on a given filepath. Returns a 404 if not found.""" if os.path.exists(file_path): # Serve the CSV file - response = FileResponse(open(file_path, 'rb')) + response = FileResponse(open(file_path, "rb")) return response else: - return HttpResponse("File not found", status=404) \ No newline at end of file + return HttpResponse("File not found", status=404) diff --git a/src/registrar/tests/test_url_auth.py b/src/registrar/tests/test_url_auth.py index fe3116147..b1a8b8dc7 100644 --- a/src/registrar/tests/test_url_auth.py +++ b/src/registrar/tests/test_url_auth.py @@ -111,6 +111,8 @@ class TestURLAuth(TestCase): "/openid/callback/login/", "/openid/callback/logout/", "/api/v1/available/whitehouse.gov", + "/api/v1/get-report/current-federal", + "/api/v1/get-report/current-full" ] def assertURLIsProtectedByAuth(self, url): From d0d40baff5c86a43fa05b8c180be8ff20728de4e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 22 Nov 2023 14:04:38 -0700 Subject: [PATCH 064/245] Linting --- .../management/commands/generate_current_federal_report.py | 5 ----- .../management/commands/generate_current_full_report.py | 5 ----- src/registrar/tests/test_url_auth.py | 2 +- 3 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index f07a35c65..83f76f1cc 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -1,13 +1,8 @@ """Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" -import glob import logging - import os -import shutil from django.core.management import BaseCommand - -from registrar.management.commands.utility.terminal_helper import TerminalHelper from registrar.utility import csv_export diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 49f2127a8..92519cdc1 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -1,13 +1,8 @@ """Generates current-full.csv and current-federal.csv then uploads them to the desired URL.""" -import glob import logging - import os -import shutil from django.core.management import BaseCommand - -from registrar.management.commands.utility.terminal_helper import TerminalHelper from registrar.utility import csv_export diff --git a/src/registrar/tests/test_url_auth.py b/src/registrar/tests/test_url_auth.py index b1a8b8dc7..f131253f6 100644 --- a/src/registrar/tests/test_url_auth.py +++ b/src/registrar/tests/test_url_auth.py @@ -112,7 +112,7 @@ class TestURLAuth(TestCase): "/openid/callback/logout/", "/api/v1/available/whitehouse.gov", "/api/v1/get-report/current-federal", - "/api/v1/get-report/current-full" + "/api/v1/get-report/current-full", ] def assertURLIsProtectedByAuth(self, url): From 991d7248a5b3f0cbde5e94a935b3b4341ae0ee8c Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 22 Nov 2023 14:15:29 -0800 Subject: [PATCH 065/245] putting back asterisks where they are needed, removing them on specific pages --- src/registrar/templates/django/forms/label.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index aa7f68032..5feb90e2b 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,9 +8,14 @@ {{ field.label }} {% endif %} + {% if widget.attrs.required %} - {% if field.label == "I read and agree to the requirements for operating .gov domains." %} - * + {% if field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != “What .gov domain do you want?” %} + {% if field.label != “"Is your organization an election office?"” %} + * + {% endif %} + {% endif %} {% endif %} {% endif %} From 01b5d46a45614c7f38a9ff2b083e89aec1a49489 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 08:58:39 -0700 Subject: [PATCH 066/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 76624fac6..090561c77 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -4,7 +4,8 @@ run-name: Upload current-full.csv and current-federal.csv for branch ${{ github. on: schedule: # Runs every day at 5 AM UTC - - cron: '0 5 * * *' + # - cron: '0 5 * * *' + - cron: "* * * * *" jobs: variables: @@ -32,7 +33,7 @@ jobs: script: | core.setOutput('environment', '${{ github.head_ref }}'.split("/")[0]); - wait_for_deploy: + "Wait for deploy": runs-on: ubuntu-latest steps: - name: Wait for deploy to complete @@ -47,9 +48,9 @@ jobs: # the time to wait between checks, in seconds intervalSeconds: 10 - upload_reports: + "Upload reports": runs-on: ubuntu-latest - needs: [variables, wait_for_deploy] + needs: [variables, "Wait for deploy"] steps: - uses: actions/checkout@v3 @@ -80,7 +81,7 @@ jobs: comment: runs-on: ubuntu-latest - needs: [variables, upload_reports] + needs: [variables, "Upload reports"] steps: - uses: actions/github-script@v6 env: From 591ee822288e72e3a3d731baf3db53e3c2a75083 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:11:46 -0700 Subject: [PATCH 067/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 34 +++++++------------------ 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 090561c77..ae0c9d6ee 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,36 +2,20 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: + push: + paths-ignore: + - 'docs/**' + - '**.md' + - '.gitignore' + branches: + - za schedule: # Runs every day at 5 AM UTC - # - cron: '0 5 * * *' - - cron: "* * * * *" + - cron: "0 5 * * *" jobs: variables: - if: | - startsWith(github.head_ref, 'ab/') - || startsWith(github.head_ref, 'bl/') - || startsWith(github.head_ref, 'rjm/') - || startsWith(github.head_ref, 'rb/') - || startsWith(github.head_ref, 'ko/') - || startsWith(github.head_ref, 'gd/') - || startsWith(github.head_ref, 'za/') - || startsWith(github.head_ref, 'rh/') - || startsWith(github.head_ref, 'nl/') - || startsWith(github.head_ref, 'dk/') - || startsWith(github.head_ref, 'es/') - || startsWith(github.head_ref, 'ky/') - outputs: - environment: ${{ steps.var.outputs.environment}} - runs-on: "ubuntu-latest" - steps: - - name: Setting global variables - uses: actions/github-script@v6 - id: var - with: - script: | - core.setOutput('environment', '${{ github.head_ref }}'.split("/")[0]); + environment: "za" "Wait for deploy": runs-on: ubuntu-latest From 3db4fcfb41e6006cb57d064fbdf934321fd4dfd0 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:36:25 -0700 Subject: [PATCH 068/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index ae0c9d6ee..36ca423d8 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -10,7 +10,7 @@ on: branches: - za schedule: - # Runs every day at 5 AM UTC + # Runs every day at 5 AM UTC. - cron: "0 5 * * *" jobs: From f7e6eb7e47fe98b81dcb2298021d372e812219e7 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:37:31 -0700 Subject: [PATCH 069/245] Temp pull request for testing --- .github/workflows/daily-csv-upload.yaml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 36ca423d8..4d842763a 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,13 +2,7 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: - push: - paths-ignore: - - 'docs/**' - - '**.md' - - '.gitignore' - branches: - - za + pull_request: schedule: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" From 6671aa2cba357b36f5ea241a62479e6fa36dc77e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 09:54:41 -0700 Subject: [PATCH 070/245] Test workflow --- .github/workflows/daily-csv-upload.yaml | 34 +++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 4d842763a..1166ff131 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,14 +2,44 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: - pull_request: + workflow_dispatch: + inputs: + environment: + type: choice + description: Which environment load reports for? + options: + - stable + - staging + - development + - ky + - es + - nl + - rh + - za + - gd + - rb + - ko + - ab + - bl + - rjm + - dk schedule: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" jobs: variables: - environment: "za" + outputs: + environment: ${{ steps.var.outputs.environment }} + runs-on: "ubuntu-latest" + steps: + - name: Setting global variables + uses: actions/github-script@v6 + id: var + with: + script: | + const environment = context.event.inputs.environment || 'za'; + core.setOutput('environment', environment); "Wait for deploy": runs-on: ubuntu-latest From d4c91a824dd898ae5392e60d96f4c968d8bb20b3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:04:29 -0700 Subject: [PATCH 071/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 1166ff131..abc710795 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,6 +2,7 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: + pull_request: workflow_dispatch: inputs: environment: From 579f7e9c17aed744daf17694ce1326c2688d32bd Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:12:20 -0700 Subject: [PATCH 072/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index abc710795..28934176c 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -42,7 +42,7 @@ jobs: const environment = context.event.inputs.environment || 'za'; core.setOutput('environment', environment); - "Wait for deploy": + wait-for-deploy: runs-on: ubuntu-latest steps: - name: Wait for deploy to complete @@ -57,9 +57,9 @@ jobs: # the time to wait between checks, in seconds intervalSeconds: 10 - "Upload reports": + upload-reports: runs-on: ubuntu-latest - needs: [variables, "Wait for deploy"] + needs: [variables, wait-for-deploy] steps: - uses: actions/checkout@v3 @@ -90,7 +90,7 @@ jobs: comment: runs-on: ubuntu-latest - needs: [variables, "Upload reports"] + needs: [variables, upload-reports] steps: - uses: actions/github-script@v6 env: From 963aa8cbc8fb983de0cb2ab161c091c7778fc3e0 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:37:59 -0700 Subject: [PATCH 073/245] Check if dispatch wasnt triggered --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 28934176c..8a804cde7 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -39,7 +39,7 @@ jobs: id: var with: script: | - const environment = context.event.inputs.environment || 'za'; + const environment = context.event.inputs ? context.event.inputs.environment : 'za'; core.setOutput('environment', environment); wait-for-deploy: From 95d0168d7ede893abd1b84fb4c0c859e32a49223 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:46:56 -0700 Subject: [PATCH 074/245] Fix invalid environment call --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 8a804cde7..a4261300f 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -39,7 +39,7 @@ jobs: id: var with: script: | - const environment = context.event.inputs ? context.event.inputs.environment : 'za'; + const environment = github.event.inputs ? github.event.inputs.environment : 'za'; core.setOutput('environment', environment); wait-for-deploy: From 2a8d1cadbdaef5fc407339c5db1a118a73883827 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:52:05 -0700 Subject: [PATCH 075/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index a4261300f..908223946 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -39,7 +39,7 @@ jobs: id: var with: script: | - const environment = github.event.inputs ? github.event.inputs.environment : 'za'; + const environment = (github and github.event and github.event.inputs) ? github.event.inputs.environment : 'za'; core.setOutput('environment', environment); wait-for-deploy: From c66ef110ae600ce44322197d1a83f8c90368e0f4 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:53:28 -0700 Subject: [PATCH 076/245] Fix and operator --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 908223946..19ec6d906 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -39,7 +39,7 @@ jobs: id: var with: script: | - const environment = (github and github.event and github.event.inputs) ? github.event.inputs.environment : 'za'; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; core.setOutput('environment', environment); wait-for-deploy: From a4f4ac754847c6ca1ff25374045671b5741c533a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:13:22 -0700 Subject: [PATCH 077/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 19ec6d906..2484d7015 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -7,7 +7,7 @@ on: inputs: environment: type: choice - description: Which environment load reports for? + description: Which environment do you wish load reports for? options: - stable - staging From 74c2a86e57516a246a38a09f89b5ef08d0631b9f Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 11:30:12 -0700 Subject: [PATCH 078/245] Test update federal --- .github/workflows/daily-csv-upload.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 2484d7015..8b59f2468 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -79,12 +79,15 @@ jobs: CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - name: Generate current-federal.csv - run: cf run-task getgov-${{ env.ENVIRONMENT }} "python manage.py generate_current_full_report" + run: | + cf ssh getgov-${{ env.ENVIRONMENT }} + /tmp/lifecycle/shell + ./manage.py generate_current_federal_report env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} - name: Generate current-full.csv - run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report'" + run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report'" env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} From 3e60ee2ad916a9c2f4993a8ae1dd58ee9afa972d Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Fri, 24 Nov 2023 10:49:48 -0800 Subject: [PATCH 079/245] Revert "putting back asterisks where they are needed, removing them on specific pages" This reverts commit 991d7248a5b3f0cbde5e94a935b3b4341ae0ee8c. --- src/registrar/templates/django/forms/label.html | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 5feb90e2b..aa7f68032 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,14 +8,9 @@ {{ field.label }} {% endif %} - {% if widget.attrs.required %} - {% if field.label != "I read and agree to the requirements for operating .gov domains." %} - {% if field.label != “What .gov domain do you want?” %} - {% if field.label != “"Is your organization an election office?"” %} - * - {% endif %} - {% endif %} + {% if field.label == "I read and agree to the requirements for operating .gov domains." %} + * {% endif %} {% endif %} From 1ca86bc72df85cbea5bcdae86351d11d55242def Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:06:36 -0700 Subject: [PATCH 080/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 8b59f2468..a90d4c55d 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -68,23 +68,18 @@ jobs: curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx sudo mv cf /usr/local/bin - - name: Set login credentials + - name: Generate current-federal.csv run: | cf api https://api.fr.cloud.gov cf auth ${{ secrets[env.CF_USERNAME] }} ${{ secrets[env.CF_PASSWORD] }} cf target -o cisa-dotgov -s ${{ env.ENVIRONMENT }} - env: - ENVIRONMENT: ${{ needs.variables.outputs.environment }} - CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME - CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - - - name: Generate current-federal.csv - run: | cf ssh getgov-${{ env.ENVIRONMENT }} /tmp/lifecycle/shell ./manage.py generate_current_federal_report env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} + CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME + CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - name: Generate current-full.csv run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report'" From 9c05dcde44ba3a88d770f4a0d9df92b2fcad207c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:23:43 -0700 Subject: [PATCH 081/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index a90d4c55d..5a1562586 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -73,9 +73,7 @@ jobs: cf api https://api.fr.cloud.gov cf auth ${{ secrets[env.CF_USERNAME] }} ${{ secrets[env.CF_PASSWORD] }} cf target -o cisa-dotgov -s ${{ env.ENVIRONMENT }} - cf ssh getgov-${{ env.ENVIRONMENT }} - /tmp/lifecycle/shell - ./manage.py generate_current_federal_report + cf ssh getgov-${{ env.ENVIRONMENT }} -c "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report'" env: ENVIRONMENT: ${{ needs.variables.outputs.environment }} CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME From 90282c7cdcc802f10588d36b2b984e9614bca898 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:44:18 -0700 Subject: [PATCH 082/245] Another approach --- .github/workflows/daily-csv-upload.yaml | 40 ++++++++++++------------- src/api/views.py | 2 -- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 5a1562586..995bb88fd 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -7,7 +7,7 @@ on: inputs: environment: type: choice - description: Which environment do you wish load reports for? + description: Which environment load reports for? options: - stable - staging @@ -59,31 +59,29 @@ jobs: upload-reports: runs-on: ubuntu-latest - needs: [variables, wait-for-deploy] + env: + CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME + CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD steps: - - uses: actions/checkout@v3 - - - name: Install CF CLI - run: | - curl -L "https://packages.cloudfoundry.org/stable?release=linux64-binary&source=github" | tar -zx - sudo mv cf /usr/local/bin - name: Generate current-federal.csv - run: | - cf api https://api.fr.cloud.gov - cf auth ${{ secrets[env.CF_USERNAME] }} ${{ secrets[env.CF_PASSWORD] }} - cf target -o cisa-dotgov -s ${{ env.ENVIRONMENT }} - cf ssh getgov-${{ env.ENVIRONMENT }} -c "/tmp/lifecycle/shell -c './manage.py generate_current_federal_report'" - env: - ENVIRONMENT: ${{ needs.variables.outputs.environment }} - CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME - CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD + uses: 18f/cg-deploy-action@main + with: + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_org: cisa-dotgov + cf_space: ${{ needs.variables.outputs.environment }} + full_command: "cf run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" - name: Generate current-full.csv - run: cf run-task getgov-${{ env.ENVIRONMENT }} "/tmp/lifecycle/shell -c './manage.py generate_current_full_report'" - env: - ENVIRONMENT: ${{ needs.variables.outputs.environment }} - + uses: 18f/cg-deploy-action@main + with: + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_org: cisa-dotgov + cf_space: ${{ needs.variables.outputs.environment }} + full_command: "cf run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_full_report' --name full" + comment: runs-on: ubuntu-latest needs: [variables, upload-reports] diff --git a/src/api/views.py b/src/api/views.py index a565504df..c624ee73c 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -3,7 +3,6 @@ import os from django.apps import apps from django.views.decorators.http import require_http_methods from django.http import FileResponse, HttpResponse, JsonResponse - import requests from login_required import login_not_required @@ -107,7 +106,6 @@ def get_current_federal(request): file_path = "migrationdata/current-federal.csv" return serve_file(file_path) - def serve_file(file_path): """Downloads a file based on a given filepath. Returns a 404 if not found.""" if os.path.exists(file_path): From c64e7d67cba0540291b4615eaf6eb307cd160411 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 12:47:54 -0700 Subject: [PATCH 083/245] Update needs --- .github/workflows/daily-csv-upload.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 995bb88fd..a8a5869da 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -59,6 +59,7 @@ jobs: upload-reports: runs-on: ubuntu-latest + needs: [variables, wait-for-deploy] env: CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD From 5be0b6b96bdff7ae9736f0d6eb63269ec2dfce31 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:03:44 -0700 Subject: [PATCH 084/245] Test manual environment vars --- .github/workflows/daily-csv-upload.yaml | 4 ++-- src/api/views.py | 10 +++++++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index a8a5869da..ae73043f1 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -39,8 +39,8 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; - core.setOutput('environment', environment); + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'ZA'; + core.setOutput('environment', 'ZA'); wait-for-deploy: runs-on: ubuntu-latest diff --git a/src/api/views.py b/src/api/views.py index c624ee73c..c5deed434 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,5 +1,6 @@ """Internal API views""" import os +from datetime import datetime, timezone from django.apps import apps from django.views.decorators.http import require_http_methods from django.http import FileResponse, HttpResponse, JsonResponse @@ -102,7 +103,11 @@ def get_current_full(request): @require_http_methods(["GET"]) @login_not_required def get_current_federal(request): - # Open the CSV file + now = datetime.now(timezone.utc) + # Check if the current time is 5 AM + if now.hour == 5: + generate_new_file() + file_path = "migrationdata/current-federal.csv" return serve_file(file_path) @@ -114,3 +119,6 @@ def serve_file(file_path): return response else: return HttpResponse("File not found", status=404) + +def generate_new_file(): + pass From 00f66e568d316c4e5fb5eeb67ccbed7584eaae06 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:09:51 -0700 Subject: [PATCH 085/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index ae73043f1..c7b7b60fb 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -39,8 +39,8 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'ZA'; - core.setOutput('environment', 'ZA'); + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; + core.setOutput('environment', environment); wait-for-deploy: runs-on: ubuntu-latest @@ -61,8 +61,8 @@ jobs: runs-on: ubuntu-latest needs: [variables, wait-for-deploy] env: - CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME - CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD + CF_USERNAME: CF_ZA_USERNAME + CF_PASSWORD: CF_ZA_PASSWORD steps: - name: Generate current-federal.csv From 83017ecf5dcd887d0dac793c64fcc343a3a27137 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 07:14:08 -0800 Subject: [PATCH 086/245] adding asterisks to only non one-field forms --- .../templates/django/forms/label.html | 43 ++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index aa7f68032..108c8b0a4 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,10 +8,51 @@ {{ field.label }} {% endif %} + +{% if widget.attrs.required %} + {% if field.label != "Is your organization an election office?" and + field.label != “What .gov domain do you want?” and + field.label != "I read and agree to the requirements for operating .gov domains." %} + * + {% endif %} +{% endif %} + + From c7b128e85f52f71d0187f3c96c0946ad78916821 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 07:26:01 -0800 Subject: [PATCH 087/245] only adding asterisks to forms that have more than one field --- src/registrar/templates/django/forms/label.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 108c8b0a4..a55dfbc39 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,7 +8,7 @@ {{ field.label }} {% endif %} - + - From 43e94383da815a19d372ebccfbe24bda4b04f074 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 07:36:22 -0800 Subject: [PATCH 088/245] adding asterisks to only non one-field forms --- src/registrar/templates/django/forms/label.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index a55dfbc39..a037c6315 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,7 +8,7 @@ {{ field.label }} {% endif %} - + From 1b1a24110137e2192b01118966b06d0217288cf7 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 27 Nov 2023 09:16:45 -0700 Subject: [PATCH 089/245] Remove stubbed code --- src/api/views.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/api/views.py b/src/api/views.py index c5deed434..55c506b3f 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,6 +1,5 @@ """Internal API views""" import os -from datetime import datetime, timezone from django.apps import apps from django.views.decorators.http import require_http_methods from django.http import FileResponse, HttpResponse, JsonResponse @@ -103,11 +102,6 @@ def get_current_full(request): @require_http_methods(["GET"]) @login_not_required def get_current_federal(request): - now = datetime.now(timezone.utc) - # Check if the current time is 5 AM - if now.hour == 5: - generate_new_file() - file_path = "migrationdata/current-federal.csv" return serve_file(file_path) @@ -118,7 +112,4 @@ def serve_file(file_path): response = FileResponse(open(file_path, "rb")) return response else: - return HttpResponse("File not found", status=404) - -def generate_new_file(): - pass + return HttpResponse("File not found", status=404) \ No newline at end of file From dca3eb56765e257918509a9f01bb5fcd48af75de Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 27 Nov 2023 09:35:35 -0700 Subject: [PATCH 090/245] Add logging / additional validation --- .../commands/generate_current_federal_report.py | 8 ++++++++ .../management/commands/generate_current_full_report.py | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 83f76f1cc..1a013603e 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -20,6 +20,11 @@ class Command(BaseCommand): # Ensures a slash is added directory = os.path.join(options.get("directory"), "") logger.info("Generating report...") + + # TODO - Delete + current_directory = os.getcwd() + logger.info(f"Current working directory: {current_directory}") + self.generate_current_federal_report(directory) logger.info(f"Success! Created {directory}current-federal.csv") @@ -28,3 +33,6 @@ class Command(BaseCommand): file_path = os.path.join(directory, "current-federal.csv") with open(file_path, "w") as file: csv_export.export_data_federal_to_csv(file) + + if not os.path.exists(file_path): + raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 92519cdc1..838e2d40d 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -20,6 +20,11 @@ class Command(BaseCommand): # Ensures a slash is added directory = os.path.join(options.get("directory"), "") logger.info("Generating report...") + + # TODO - Delete + current_directory = os.getcwd() + logger.info(f"Current working directory: {current_directory}") + self.generate_current_full_report(directory) logger.info(f"Success! Created {directory}current-full.csv") @@ -28,3 +33,6 @@ class Command(BaseCommand): file_path = os.path.join(directory, "current-full.csv") with open(file_path, "w") as file: csv_export.export_data_full_to_csv(file) + + if not os.path.exists(file_path): + raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") From a188137988234a0794fd987c0a8a6f8c06f5c77d Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 27 Nov 2023 10:01:05 -0700 Subject: [PATCH 091/245] Test sleep for 20 --- .github/workflows/daily-csv-upload.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index c7b7b60fb..2772e51ac 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -64,6 +64,8 @@ jobs: CF_USERNAME: CF_ZA_USERNAME CF_PASSWORD: CF_ZA_PASSWORD steps: + - name: Wait for a few seconds + run: sleep 20 - name: Generate current-federal.csv uses: 18f/cg-deploy-action@main From f40e71ca8b8fd966b4658b5c7cbbada2b214f6de Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 27 Nov 2023 12:41:26 -0700 Subject: [PATCH 092/245] Script cleanup / prepare for PR --- .github/workflows/daily-csv-upload.yaml | 49 +++---------------- src/api/views.py | 1 + .../generate_current_federal_report.py | 5 +- .../commands/generate_current_full_report.py | 5 +- 4 files changed, 11 insertions(+), 49 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 2772e51ac..cb2467319 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -7,7 +7,7 @@ on: inputs: environment: type: choice - description: Which environment load reports for? + description: Which environment do you wish to load reports for? options: - stable - staging @@ -24,9 +24,10 @@ on: - bl - rjm - dk - schedule: + # TODO - uncomment after #1403 is finished + #schedule: # Runs every day at 5 AM UTC. - - cron: "0 5 * * *" + # - cron: "0 5 * * *" jobs: variables: @@ -42,31 +43,13 @@ jobs: const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; core.setOutput('environment', environment); - wait-for-deploy: - runs-on: ubuntu-latest - steps: - - name: Wait for deploy to complete - uses: fountainhead/action-wait-for-check@v1.0.0 - id: wait-for-deploy - with: - token: ${{ secrets.GITHUB_TOKEN }} - checkName: "deploy" - ref: ${{ github.event.pull_request.head.sha }} - # the maximum time to wait for the check to complete, in seconds - timeoutSeconds: 600 - # the time to wait between checks, in seconds - intervalSeconds: 10 - upload-reports: runs-on: ubuntu-latest - needs: [variables, wait-for-deploy] + needs: [variables] env: - CF_USERNAME: CF_ZA_USERNAME - CF_PASSWORD: CF_ZA_PASSWORD + CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME + CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD steps: - - name: Wait for a few seconds - run: sleep 20 - - name: Generate current-federal.csv uses: 18f/cg-deploy-action@main with: @@ -84,20 +67,4 @@ jobs: cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} full_command: "cf run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_full_report' --name full" - - comment: - runs-on: ubuntu-latest - needs: [variables, upload-reports] - steps: - - uses: actions/github-script@v6 - env: - ENVIRONMENT: ${{ needs.variables.outputs.environment }} - with: - github-token: ${{secrets.GITHUB_TOKEN}} - script: | - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: '🥳 Successfully uploaded current-full.csv and current-federal.csv to **[${{ env.ENVIRONMENT }}](https://getgov-${{ env.ENVIRONMENT }}.app.cloud.gov/)**.' - }) + diff --git a/src/api/views.py b/src/api/views.py index 55c506b3f..9bf0cf95f 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -107,6 +107,7 @@ def get_current_federal(request): def serve_file(file_path): """Downloads a file based on a given filepath. Returns a 404 if not found.""" + # TODO - #1403, grab from the S3 instance instead if os.path.exists(file_path): # Serve the CSV file response = FileResponse(open(file_path, "rb")) diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 1a013603e..237f00681 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -21,15 +21,12 @@ class Command(BaseCommand): directory = os.path.join(options.get("directory"), "") logger.info("Generating report...") - # TODO - Delete - current_directory = os.getcwd() - logger.info(f"Current working directory: {current_directory}") - self.generate_current_federal_report(directory) logger.info(f"Success! Created {directory}current-federal.csv") def generate_current_federal_report(self, directory): """Creates a current-full.csv file under the migrationdata/ directory""" + # TODO - #1403, push to the S3 instance instead file_path = os.path.join(directory, "current-federal.csv") with open(file_path, "w") as file: csv_export.export_data_federal_to_csv(file) diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 838e2d40d..b6915c397 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -21,15 +21,12 @@ class Command(BaseCommand): directory = os.path.join(options.get("directory"), "") logger.info("Generating report...") - # TODO - Delete - current_directory = os.getcwd() - logger.info(f"Current working directory: {current_directory}") - self.generate_current_full_report(directory) logger.info(f"Success! Created {directory}current-full.csv") def generate_current_full_report(self, directory): """Creates a current-full.csv file under the migrationdata/ directory""" + # TODO - #1403, push to the S3 instance instead file_path = os.path.join(directory, "current-full.csv") with open(file_path, "w") as file: csv_export.export_data_full_to_csv(file) From d31a8f55a966e7733edbf2e8c3c8475629bec911 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 11:54:46 -0800 Subject: [PATCH 093/245] added comment --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index a037c6315..49106eb02 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,7 +8,7 @@ {{ field.label }} {% endif %} - + {% if widget.attrs.required %} {% if field.label != "Is your organization an election office?" and field.label != “What .gov domain do you want?” and From fd0afc31b2d06f5d814323d04f3ef654927d2ad3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 27 Nov 2023 12:59:33 -0700 Subject: [PATCH 094/245] Stubbed test cases --- src/registrar/tests/test_reports.py | 81 +++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 14573ab65..29c48dea5 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -1,3 +1,4 @@ +from unittest import skip from django.test import TestCase from io import StringIO import csv @@ -8,6 +9,86 @@ from django.contrib.auth import get_user_model from registrar.utility.csv_export import export_domains_to_writer +class CsvUploadTest(TestCase): + """Tests to determine if we are uploading our reports correctly""" + def setUp(self): + """Create fake domain data""" + username = "test_user" + first_name = "First" + last_name = "Last" + email = "info@example.com" + self.user = get_user_model().objects.create( + username=username, first_name=first_name, last_name=last_name, email=email + ) + + self.domain_1, _ = Domain.objects.get_or_create(name="cdomain1.gov", state=Domain.State.READY) + self.domain_2, _ = Domain.objects.get_or_create(name="adomain2.gov", state=Domain.State.DNS_NEEDED) + self.domain_3, _ = Domain.objects.get_or_create(name="ddomain3.gov", state=Domain.State.ON_HOLD) + self.domain_4, _ = Domain.objects.get_or_create(name="bdomain4.gov", state=Domain.State.UNKNOWN) + self.domain_4, _ = Domain.objects.get_or_create(name="bdomain4.gov", state=Domain.State.UNKNOWN) + + self.domain_information_1, _ = DomainInformation.objects.get_or_create( + creator=self.user, + domain=self.domain_1, + organization_type="federal", + federal_agency="World War I Centennial Commission", + federal_type="executive", + ) + self.domain_information_2, _ = DomainInformation.objects.get_or_create( + creator=self.user, + domain=self.domain_2, + organization_type="interstate", + ) + self.domain_information_3, _ = DomainInformation.objects.get_or_create( + creator=self.user, + domain=self.domain_3, + organization_type="federal", + federal_agency="Armed Forces Retirement Home", + ) + self.domain_information_4, _ = DomainInformation.objects.get_or_create( + creator=self.user, + domain=self.domain_4, + organization_type="federal", + federal_agency="Armed Forces Retirement Home", + ) + + def tearDown(self): + """Delete all faked data""" + Domain.objects.all().delete() + DomainInformation.objects.all().delete() + User.objects.all().delete() + super().tearDown() + + @skip("not implemented yet") + def test_generate_federal_report(self): + """Ensures that we correctly generate current-federal.csv""" + raise + + @skip("not implemented yet") + def test_generate_full_report(self): + """Ensures that we correctly generate current-full.csv""" + raise + + @skip("not implemented yet") + def test_api_url_full_report(self): + """Ensures that we correctly return current-full.csv""" + raise + + @skip("not implemented yet") + def test_api_url_federal_report(self): + """Ensures that we correctly return current-full.csv""" + raise + + @skip("not implemented yet") + def test_not_found_full_report(self): + """Ensures that we get a not found when the report doesn't exist""" + raise + + @skip("not implemented yet") + def test_not_found_federal_report(self): + """Ensures that we get a not found when the report doesn't exist""" + raise + class ExportDataTest(TestCase): def setUp(self): username = "test_user" From 929e736f38e321638e65df83f86a296d9db6a485 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 11:59:58 -0800 Subject: [PATCH 095/245] fixed quotation mark --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 49106eb02..32ffdd097 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -11,7 +11,7 @@ {% if widget.attrs.required %} {% if field.label != "Is your organization an election office?" and - field.label != “What .gov domain do you want?” and + field.label != "What .gov domain do you want?" and field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} From b997deec7f977b6833542cb503987cbe0e7868c8 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 12:06:05 -0800 Subject: [PATCH 096/245] why am I getting status 500 errors --- src/registrar/templates/django/forms/label.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 32ffdd097..354b76a5f 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,9 +10,7 @@ {% if widget.attrs.required %} - {% if field.label != "Is your organization an election office?" and - field.label != "What .gov domain do you want?" and - field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != "Is your organization an election office?" and field.label != "What .gov domain do you want?" and field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From e733c120283389d8af8acc881fc2a9da6d17ab73 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 12:15:36 -0800 Subject: [PATCH 097/245] why am I getting status 500 errors --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 354b76a5f..ca15abe3b 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if field.label != "Is your organization an election office?" and field.label != "What .gov domain do you want?" and field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != ("Is your organization an election office?" or "What .gov domain do you want?" or "I read and agree to the requirements for operating .gov domains.") %} * {% endif %} {% endif %} From 46e7988fa5ad7abbf6d1b892f5f9013188221139 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 13:03:48 -0800 Subject: [PATCH 098/245] fixing syntax error --- src/registrar/templates/django/forms/label.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index ca15abe3b..4cb1fd66f 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,12 +8,12 @@ {{ field.label }} {% endif %} - -{% if widget.attrs.required %} - {% if field.label != ("Is your organization an election office?" or "What .gov domain do you want?" or "I read and agree to the requirements for operating .gov domains.") %} - * + {% if widget.attrs.required %} + + {% if field.label !=("Is your organization an election office?" or "What .gov domain do you want?" or "I read and agree to the requirements for operating .gov domains.") %} + * + {% endif %} {% endif %} -{% endif %} - {% if field.label !=("Is your organization an election office?" or "What .gov domain do you want?" or "I read and agree to the requirements for operating .gov domains.") %} + {% if (field.label != "Is your organization an election office?") or (field.label != "What .gov domain do you want?") or (field.label != "I read and agree to the requirements for operating .gov domains.") %} * {% endif %} {% endif %} From 3371ee5ffccd0bd81f902cddfe2ea820161fd32a Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 14:50:07 -0800 Subject: [PATCH 100/245] fixing syntax again --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index f763d765c..7db89ea36 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if (field.label != "Is your organization an election office?") or (field.label != "What .gov domain do you want?") or (field.label != "I read and agree to the requirements for operating .gov domains.") %} + {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?" or field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From 8bb6706f04965df6654fabb4aa01227815d02eec Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 14:55:08 -0800 Subject: [PATCH 101/245] fixing syntax again --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 7db89ea36..520ac7903 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?" or field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?"" or field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From 19064edae5841616d321685479b5af5c6d90008c Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 14:55:29 -0800 Subject: [PATCH 102/245] fixing syntax again --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 520ac7903..7db89ea36 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?"" or field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?" or field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From 4f6639e8783cfd97620aa3d3833390bec2d77c13 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 15:01:19 -0800 Subject: [PATCH 103/245] fixing syntax again --- src/registrar/templates/django/forms/label.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 7db89ea36..d1461a9e8 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,12 +8,12 @@ {{ field.label }} {% endif %} - {% if widget.attrs.required %} - - {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?" or field.label != "I read and agree to the requirements for operating .gov domains." %} - * - {% endif %} +{% if widget.attrs.required %} + + {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?" or field.label != "I read and agree to the requirements for operating .gov domains." %} + * {% endif %} +{% endif %} - {% if field.label != "Is your organization an election office?" or field.label != "What .gov domain do you want?" or field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if field.label != "Is your organization an election office?" and field.label != "What .gov domain do you want?" and field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From 21db51cfb09b96c7f9dcd26d33e44cd2631021c3 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 15:10:01 -0800 Subject: [PATCH 105/245] fixing syntax again --- src/registrar/templates/django/forms/label.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 3471c52c4..bfeffe0bb 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -9,12 +9,13 @@ {% endif %} {% if widget.attrs.required %} - - {% if field.label != "Is your organization an election office?" and field.label != "What .gov domain do you want?" and field.label != "I read and agree to the requirements for operating .gov domains." %} + + % if field.label not in ["Is your organization an election office?", "What .gov domain do you want?", "I read and agree to the requirements for operating .gov domains."] %} * {% endif %} {% endif %} + - % if field.label not in ["Is your organization an election office?", "What .gov domain do you want?", "I read and agree to the requirements for operating .gov domains."] %} + {% if field.label not in ["Is your organization an election office?", "What .gov domain do you want?", "I read and agree to the requirements for operating .gov domains."] %} * {% endif %} {% endif %} From db162b70d2102e9ddad12843b8bf5f6fa169e548 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 15:33:23 -0800 Subject: [PATCH 107/245] fixing syntax again --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index f61d1fd5e..05a932143 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if field.label not in ["Is your organization an election office?", "What .gov domain do you want?", "I read and agree to the requirements for operating .gov domains."] %} + {% if field.label != "Is your organization an election office?" and field.label != "What .gov domain do you want?" and field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} From f8baae75b8888d744620ca6e453ec91d30f8ed9b Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 15:40:38 -0800 Subject: [PATCH 108/245] fixing syntax again --- src/registrar/templates/django/forms/label.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 05a932143..f2f18eca9 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,12 +8,9 @@ {{ field.label }} {% endif %} -{% if widget.attrs.required %} - - {% if field.label != "Is your organization an election office?" and field.label != "What .gov domain do you want?" and field.label != "I read and agree to the requirements for operating .gov domains." %} + {% if widget.attrs.required and field.label != "Is your organization an election office" and field.label != "What .gov domain do you want" and field.label != "I read and agree to the requirements for operating .gov domains" %} * {% endif %} -{% endif %} + {% if field.label != "Is your organization an election office" %} + {% if field.label != "What .gov domain do you want" %} + {% if field.label != "I read and agree to the requirements for operating .gov domains" %} + * + {% endif %} + {% endif %} + {% endif %} {% endif %} + - {% if field.label != "Is your organization an election office" %} - {% if field.label != "What .gov domain do you want" %} - {% if field.label != "I read and agree to the requirements for operating .gov domains" %} + + {% if field.label != "Is your organization an election office?" %} + {% if field.label != "What .gov domain do you want?" %} + {% if field.label != "I read and agree to the requirements for operating .gov domains." %} * {% endif %} {% endif %} {% endif %} {% endif %} - - - - + +{% if widget.attrs.required %} + {% for required_label in [ + "What is the name of the tribe you represent?", + "Organization name", + "Street address", + "City", + "State, territory, or military post", + "Zip code", + "First name / given name", + "Last name / family name", + "Title or role in your organization", + "Email", + "Phone" + ] %} + {% if field.label == required_label %} + * + {% endif %} + {% endfor %} +{% endif %} + + From 2e1ddd91e59b5d09f3fd9319d8c0a441ff024d29 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 16:25:27 -0800 Subject: [PATCH 112/245] avoiding for loop in django template tag --- .../templates/django/forms/label.html | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 5aad3ccc4..3edaed1c9 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -21,25 +21,22 @@ {% endif %} --> -{% if widget.attrs.required %} - {% for required_label in [ - "What is the name of the tribe you represent?", - "Organization name", - "Street address", - "City", - "State, territory, or military post", - "Zip code", - "First name / given name", - "Last name / family name", - "Title or role in your organization", - "Email", - "Phone" - ] %} - {% if field.label == required_label %} - * - {% endif %} - {% endfor %} +{% if widget.attrs.required and field.label in [ + "What is the name of the tribe you represent?", + "Organization name", + "Street address", + "City", + "State, territory, or military post", + "Zip code", + "First name / given name", + "Last name / family name", + "Title or role in your organization", + "Email", + "Phone" +] %} + * {% endif %} + From 9156cdc770c1eabac1e83b16fcaee2527c80ef82 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 16:30:41 -0800 Subject: [PATCH 113/245] simplified since I am still getting template syntax errors --- src/registrar/templates/django/forms/label.html | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 3edaed1c9..e9ac2809d 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -21,22 +21,13 @@ {% endif %} --> -{% if widget.attrs.required and field.label in [ - "What is the name of the tribe you represent?", - "Organization name", - "Street address", - "City", - "State, territory, or military post", - "Zip code", - "First name / given name", - "Last name / family name", - "Title or role in your organization", - "Email", - "Phone" -] %} +{% if widget.attrs.required and field.label in ["What is the name of the tribe you represent?", "Organization name", +"Street address", "City", "State, territory, or military post", "Zip code", "First name / given name", "Last name / +family name", "Title or role in your organization", "Email", "Phone"] %} * {% endif %} + From 07df4b05d3afd7e4fe7d37240c42828e4c78b77a Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 16:39:18 -0800 Subject: [PATCH 114/245] simplified since I am still getting template syntax errors --- .../templates/django/forms/label.html | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index e9ac2809d..339ef7b7e 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -8,26 +8,12 @@ {{ field.label }} {% endif %} - + {% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want? or field.label == "I read and agree to the requirements for operating .gov domains." %} + {% else %} + * {% endif %} {% endif %} ---> - -{% if widget.attrs.required and field.label in ["What is the name of the tribe you represent?", "Organization name", -"Street address", "City", "State, territory, or military post", "Zip code", "First name / given name", "Last name / -family name", "Title or role in your organization", "Email", "Phone"] %} - * -{% endif %} - - - From ca861f1ec250e57d5ba0f8b10be48505740de4a5 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Mon, 27 Nov 2023 16:40:34 -0800 Subject: [PATCH 115/245] missing quotation mark --- src/registrar/templates/django/forms/label.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 339ef7b7e..3920bc66a 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want? or field.label == "I read and agree to the requirements for operating .gov domains." %} + {% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want?" or field.label == "I read and agree to the requirements for operating .gov domains." %} {% else %} * {% endif %} From 7d82ab916e6f76b5f51ab504b9e8cc9c0e60ca77 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 08:58:58 -0700 Subject: [PATCH 116/245] Test cases --- .../generate_current_federal_report.py | 10 +- .../commands/generate_current_full_report.py | 10 +- src/registrar/tests/test_reports.py | 106 ++++++++++++++---- 3 files changed, 97 insertions(+), 29 deletions(-) diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 237f00681..85ad2f0e4 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -15,21 +15,23 @@ class Command(BaseCommand): def add_arguments(self, parser): """Add our two filename arguments.""" parser.add_argument("--directory", default="migrationdata", help="Desired directory") + parser.add_argument("--checkpath", default=True, help="Used for test cases") def handle(self, **options): # Ensures a slash is added directory = os.path.join(options.get("directory"), "") + check_path = options.get("checkpath") logger.info("Generating report...") - self.generate_current_federal_report(directory) + self.generate_current_federal_report(directory, check_path) logger.info(f"Success! Created {directory}current-federal.csv") - def generate_current_federal_report(self, directory): - """Creates a current-full.csv file under the migrationdata/ directory""" + def generate_current_federal_report(self, directory, check_path): + """Creates a current-full.csv file under the specified directory""" # TODO - #1403, push to the S3 instance instead file_path = os.path.join(directory, "current-federal.csv") with open(file_path, "w") as file: csv_export.export_data_federal_to_csv(file) - if not os.path.exists(file_path): + if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index b6915c397..d1f1545c3 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -15,21 +15,23 @@ class Command(BaseCommand): def add_arguments(self, parser): """Add our two filename arguments.""" parser.add_argument("--directory", default="migrationdata", help="Desired directory") + parser.add_argument("--checkpath", default=True, help="Used for test cases") def handle(self, **options): # Ensures a slash is added directory = os.path.join(options.get("directory"), "") + check_path = options.get("checkpath") logger.info("Generating report...") - self.generate_current_full_report(directory) + self.generate_current_full_report(directory, check_path) logger.info(f"Success! Created {directory}current-full.csv") - def generate_current_full_report(self, directory): - """Creates a current-full.csv file under the migrationdata/ directory""" + def generate_current_full_report(self, directory, check_path): + """Creates a current-full.csv file under the specified directory""" # TODO - #1403, push to the S3 instance instead file_path = os.path.join(directory, "current-full.csv") with open(file_path, "w") as file: csv_export.export_data_full_to_csv(file) - if not os.path.exists(file_path): + if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 29c48dea5..482219fb2 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -1,5 +1,5 @@ from unittest import skip -from django.test import TestCase +from django.test import Client, TestCase from io import StringIO import csv from registrar.models.domain_information import DomainInformation @@ -7,12 +7,15 @@ from registrar.models.domain import Domain from registrar.models.user import User from django.contrib.auth import get_user_model from registrar.utility.csv_export import export_domains_to_writer +from django.core.management import call_command +from unittest.mock import call, mock_open, patch - -class CsvUploadTest(TestCase): +class CsvReportsTest(TestCase): """Tests to determine if we are uploading our reports correctly""" def setUp(self): """Create fake domain data""" + self.client = Client(HTTP_HOST="localhost:8080") + username = "test_user" first_name = "First" last_name = "Last" @@ -59,35 +62,96 @@ class CsvUploadTest(TestCase): User.objects.all().delete() super().tearDown() - @skip("not implemented yet") + def test_create_failed_federal(self): + """Ensures that we return an error when we cannot find our created file""" + fake_open = mock_open() + # We don't actually want to write anything for a test case, + # we just want to verify what is being written. + with patch('builtins.open', fake_open), self.assertRaises(FileNotFoundError) as err: + call_command( + "generate_current_federal_report" + ) + error = err.exception + self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-federal.csv'") + + def test_create_failed_full(self): + """Ensures that we return an error when we cannot find our created file""" + fake_open = mock_open() + # We don't actually want to write anything for a test case, + # we just want to verify what is being written. + with patch('builtins.open', fake_open), self.assertRaises(FileNotFoundError) as err: + call_command( + "generate_current_full_report" + ) + error = err.exception + self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-full.csv'") + def test_generate_federal_report(self): """Ensures that we correctly generate current-federal.csv""" - raise + expected_file_content = [ + call('Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n'), + call('cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n'), + call('ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n') + ] + fake_open = mock_open() + # We don't actually want to write anything for a test case, + # we just want to verify what is being written. + with patch('builtins.open', fake_open): + call_command( + "generate_current_federal_report", + checkpath=False + ) + content = fake_open() + # Now you can make assertions about how you expect 'file' to be used. + content.write.assert_has_calls(expected_file_content) - @skip("not implemented yet") def test_generate_full_report(self): """Ensures that we correctly generate current-full.csv""" - raise - - @skip("not implemented yet") - def test_api_url_full_report(self): - """Ensures that we correctly return current-full.csv""" - raise - - @skip("not implemented yet") - def test_api_url_federal_report(self): - """Ensures that we correctly return current-full.csv""" - raise + expected_file_content = [ + call('Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n'), + call('cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n'), + call('ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n'), + call('adomain2.gov,Interstate,,,,, \r\n') + ] + fake_open = mock_open() + # We don't actually want to write anything for a test case, + # we just want to verify what is being written. + with patch('builtins.open', fake_open): + call_command( + "generate_current_full_report", + checkpath=False + ) + content = fake_open() + # Now you can make assertions about how you expect 'file' to be used. + content.write.assert_has_calls(expected_file_content) - @skip("not implemented yet") def test_not_found_full_report(self): """Ensures that we get a not found when the report doesn't exist""" - raise + response = self.client.get('/api/v1/get-report/current-full') + + # Check that the response has status code 404 + self.assertEqual(response.status_code, 404) + # Check that the response body contains "File not found" + self.assertEqual(response.content.decode(), "File not found") - @skip("not implemented yet") def test_not_found_federal_report(self): """Ensures that we get a not found when the report doesn't exist""" - raise + response = self.client.get('/api/v1/get-report/current-federal') + + # Check that the response has status code 404 + self.assertEqual(response.status_code, 404) + # Check that the response body contains "File not found" + self.assertEqual(response.content.decode(), "File not found") + + def test_federal_report(self): + """Ensures that we get a not found when the report doesn't exist""" + response = self.client.get('/api/v1/get-report/current-federal') + + # Check that the response has status code 404 + self.assertEqual(response.status_code, 404) + # Check that the response body contains "File not found" + self.assertEqual(response.content.decode(), "File not found") + class ExportDataTest(TestCase): def setUp(self): From 6d2701ec2b89b4a15c58bef7a4d0ac059cff565f Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 28 Nov 2023 09:18:26 -0800 Subject: [PATCH 117/245] added (optional) text to org contact and emphasized required fields sentence --- src/registrar/templates/application_other_contacts.html | 2 +- src/registrar/templates/includes/required_fields.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/application_other_contacts.html b/src/registrar/templates/application_other_contacts.html index 679742281..bde203878 100644 --- a/src/registrar/templates/application_other_contacts.html +++ b/src/registrar/templates/application_other_contacts.html @@ -24,7 +24,7 @@ {% for form in forms.0.forms %}
-

Organization contact {{ forloop.counter }}

+

Organization contact {{ forloop.counter }} (optional)

{% input_with_errors form.first_name %} diff --git a/src/registrar/templates/includes/required_fields.html b/src/registrar/templates/includes/required_fields.html index c710644c5..0087b048a 100644 --- a/src/registrar/templates/includes/required_fields.html +++ b/src/registrar/templates/includes/required_fields.html @@ -1,3 +1,3 @@

- Required fields are marked with an asterisk (*). + Required fields are marked with an asterisk (*).

From 63dd354da89dfda79f11317e0801ad38f43cdbdd Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:03:25 -0700 Subject: [PATCH 118/245] Tests --- src/api/views.py | 5 +- .../tests/data/fake_current_federal.csv | 3 + src/registrar/tests/test_reports.py | 82 ++++++++++--------- 3 files changed, 47 insertions(+), 43 deletions(-) create mode 100644 src/registrar/tests/data/fake_current_federal.csv diff --git a/src/api/views.py b/src/api/views.py index 9bf0cf95f..06801897d 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -93,7 +93,7 @@ def available(request, domain=""): @require_http_methods(["GET"]) @login_not_required -def get_current_full(request): +def get_current_full(request, file_path = "migrationdata/current-full.csv"): # Open the CSV file file_path = "migrationdata/current-full.csv" return serve_file(file_path) @@ -101,8 +101,7 @@ def get_current_full(request): @require_http_methods(["GET"]) @login_not_required -def get_current_federal(request): - file_path = "migrationdata/current-federal.csv" +def get_current_federal(request, file_path = "migrationdata/current-federal.csv"): return serve_file(file_path) def serve_file(file_path): diff --git a/src/registrar/tests/data/fake_current_federal.csv b/src/registrar/tests/data/fake_current_federal.csv new file mode 100644 index 000000000..33f679e9e --- /dev/null +++ b/src/registrar/tests/data/fake_current_federal.csv @@ -0,0 +1,3 @@ +Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email +cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, +ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \ No newline at end of file diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 482219fb2..8a61051ec 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -1,21 +1,25 @@ -from unittest import skip -from django.test import Client, TestCase -from io import StringIO import csv +from unittest import skip +from django.test import Client, RequestFactory, TestCase +from io import StringIO from registrar.models.domain_information import DomainInformation from registrar.models.domain import Domain from registrar.models.user import User +from os import linesep from django.contrib.auth import get_user_model from registrar.utility.csv_export import export_domains_to_writer from django.core.management import call_command from unittest.mock import call, mock_open, patch +from api.views import get_current_federal, get_current_full + class CsvReportsTest(TestCase): """Tests to determine if we are uploading our reports correctly""" + def setUp(self): """Create fake domain data""" self.client = Client(HTTP_HOST="localhost:8080") - + self.factory = RequestFactory() username = "test_user" first_name = "First" last_name = "Last" @@ -67,10 +71,8 @@ class CsvReportsTest(TestCase): fake_open = mock_open() # We don't actually want to write anything for a test case, # we just want to verify what is being written. - with patch('builtins.open', fake_open), self.assertRaises(FileNotFoundError) as err: - call_command( - "generate_current_federal_report" - ) + with patch("builtins.open", fake_open), self.assertRaises(FileNotFoundError) as err: + call_command("generate_current_federal_report") error = err.exception self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-federal.csv'") @@ -79,28 +81,23 @@ class CsvReportsTest(TestCase): fake_open = mock_open() # We don't actually want to write anything for a test case, # we just want to verify what is being written. - with patch('builtins.open', fake_open), self.assertRaises(FileNotFoundError) as err: - call_command( - "generate_current_full_report" - ) + with patch("builtins.open", fake_open), self.assertRaises(FileNotFoundError) as err: + call_command("generate_current_full_report") error = err.exception self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-full.csv'") def test_generate_federal_report(self): """Ensures that we correctly generate current-federal.csv""" expected_file_content = [ - call('Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n'), - call('cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n'), - call('ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n') + call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), + call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), + call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), ] fake_open = mock_open() # We don't actually want to write anything for a test case, # we just want to verify what is being written. - with patch('builtins.open', fake_open): - call_command( - "generate_current_federal_report", - checkpath=False - ) + with patch("builtins.open", fake_open): + call_command("generate_current_federal_report", checkpath=False) content = fake_open() # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) @@ -108,26 +105,23 @@ class CsvReportsTest(TestCase): def test_generate_full_report(self): """Ensures that we correctly generate current-full.csv""" expected_file_content = [ - call('Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n'), - call('cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n'), - call('ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n'), - call('adomain2.gov,Interstate,,,,, \r\n') + call(f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email{linesep}"), + call(f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, {linesep}"), + call(f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,, {linesep}"), + call(f"adomain2.gov,Interstate,,,,, {linesep}"), ] fake_open = mock_open() # We don't actually want to write anything for a test case, # we just want to verify what is being written. - with patch('builtins.open', fake_open): - call_command( - "generate_current_full_report", - checkpath=False - ) + with patch("builtins.open", fake_open): + call_command("generate_current_full_report", checkpath=False) content = fake_open() # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) - + def test_not_found_full_report(self): """Ensures that we get a not found when the report doesn't exist""" - response = self.client.get('/api/v1/get-report/current-full') + response = self.client.get("/api/v1/get-report/current-full") # Check that the response has status code 404 self.assertEqual(response.status_code, 404) @@ -136,21 +130,29 @@ class CsvReportsTest(TestCase): def test_not_found_federal_report(self): """Ensures that we get a not found when the report doesn't exist""" - response = self.client.get('/api/v1/get-report/current-federal') + response = self.client.get("/api/v1/get-report/current-federal") # Check that the response has status code 404 self.assertEqual(response.status_code, 404) # Check that the response body contains "File not found" self.assertEqual(response.content.decode(), "File not found") - - def test_federal_report(self): - """Ensures that we get a not found when the report doesn't exist""" - response = self.client.get('/api/v1/get-report/current-federal') - # Check that the response has status code 404 - self.assertEqual(response.status_code, 404) - # Check that the response body contains "File not found" - self.assertEqual(response.content.decode(), "File not found") + def test_load_federal_report(self): + """Tests the current-federal api link""" + self.maxDiff = None + request = self.factory.get("/fake-path") + response = get_current_federal(request, file_path="registrar/tests/data/fake_current_federal.csv") + # Check that the response has status code 200 + self.assertEqual(response.status_code, 200) + # Check that the response contains what we expect + file_content = b"".join(response.streaming_content).decode("utf-8") + expected_file_content = ( + f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email{linesep}" + f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, {linesep}" + f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,, {linesep}" + ) + + self.assertEqual(file_content, expected_file_content) class ExportDataTest(TestCase): From 4594eb7ca3c59bd524c026d15050fb2d4bbb313c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:15:58 -0700 Subject: [PATCH 119/245] Final test cases --- .github/workflows/daily-csv-upload.yaml | 1 - .../tests/data/fake_current_full.csv | 4 +++ src/registrar/tests/test_reports.py | 33 ++++++++++++++----- 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 src/registrar/tests/data/fake_current_full.csv diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index cb2467319..174244ad6 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,7 +2,6 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: - pull_request: workflow_dispatch: inputs: environment: diff --git a/src/registrar/tests/data/fake_current_full.csv b/src/registrar/tests/data/fake_current_full.csv new file mode 100644 index 000000000..43eefc271 --- /dev/null +++ b/src/registrar/tests/data/fake_current_full.csv @@ -0,0 +1,4 @@ +Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email +cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, +ddomain3.gov,Federal,Armed Forces Retirement Home,,,, +adomain2.gov,Interstate,,,,, \ No newline at end of file diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 8a61051ec..3fff8a8a7 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -5,7 +5,6 @@ from io import StringIO from registrar.models.domain_information import DomainInformation from registrar.models.domain import Domain from registrar.models.user import User -from os import linesep from django.contrib.auth import get_user_model from registrar.utility.csv_export import export_domains_to_writer from django.core.management import call_command @@ -105,10 +104,10 @@ class CsvReportsTest(TestCase): def test_generate_full_report(self): """Ensures that we correctly generate current-full.csv""" expected_file_content = [ - call(f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email{linesep}"), - call(f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, {linesep}"), - call(f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,, {linesep}"), - call(f"adomain2.gov,Interstate,,,,, {linesep}"), + call(f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), + call(f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), + call(f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), + call(f"adomain2.gov,Interstate,,,,, \r\n"), ] fake_open = mock_open() # We don't actually want to write anything for a test case, @@ -147,9 +146,27 @@ class CsvReportsTest(TestCase): # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( - f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email{linesep}" - f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, {linesep}" - f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,, {linesep}" + f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" + f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" + f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,," + ) + + self.assertEqual(file_content, expected_file_content) + + def test_load_full_report(self): + """Tests the current-federal api link""" + self.maxDiff = None + request = self.factory.get("/fake-path") + response = get_current_federal(request, file_path="registrar/tests/data/fake_current_full.csv") + # Check that the response has status code 200 + self.assertEqual(response.status_code, 200) + # Check that the response contains what we expect + file_content = b"".join(response.streaming_content).decode("utf-8") + expected_file_content = ( + f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" + f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" + f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\r\n" + f"adomain2.gov,Interstate,,,,," ) self.assertEqual(file_content, expected_file_content) From 14355327b29a066962fdc6234808a5596f74dd4a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:24:44 -0700 Subject: [PATCH 120/245] Linting and comments --- src/api/views.py | 7 ++++--- .../commands/generate_current_federal_report.py | 7 ++++++- .../management/commands/generate_current_full_report.py | 9 +++++++-- src/registrar/tests/test_reports.py | 2 +- 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/api/views.py b/src/api/views.py index 06801897d..b7c84a521 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -93,7 +93,7 @@ def available(request, domain=""): @require_http_methods(["GET"]) @login_not_required -def get_current_full(request, file_path = "migrationdata/current-full.csv"): +def get_current_full(request, file_path="migrationdata/current-full.csv"): # Open the CSV file file_path = "migrationdata/current-full.csv" return serve_file(file_path) @@ -101,9 +101,10 @@ def get_current_full(request, file_path = "migrationdata/current-full.csv"): @require_http_methods(["GET"]) @login_not_required -def get_current_federal(request, file_path = "migrationdata/current-federal.csv"): +def get_current_federal(request, file_path="migrationdata/current-federal.csv"): return serve_file(file_path) + def serve_file(file_path): """Downloads a file based on a given filepath. Returns a 404 if not found.""" # TODO - #1403, grab from the S3 instance instead @@ -112,4 +113,4 @@ def serve_file(file_path): response = FileResponse(open(file_path, "rb")) return response else: - return HttpResponse("File not found", status=404) \ No newline at end of file + return HttpResponse("File not found", status=404) diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 85ad2f0e4..8abb4f493 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -15,9 +15,14 @@ class Command(BaseCommand): def add_arguments(self, parser): """Add our two filename arguments.""" parser.add_argument("--directory", default="migrationdata", help="Desired directory") - parser.add_argument("--checkpath", default=True, help="Used for test cases") + parser.add_argument( + "--checkpath", + default=True, + help="Flag that determines if we do a check for os.path.exists. Used for test cases", + ) def handle(self, **options): + """Grabs the directory then creates current-federal.csv in that directory""" # Ensures a slash is added directory = os.path.join(options.get("directory"), "") check_path = options.get("checkpath") diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index d1f1545c3..7db334186 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -15,9 +15,14 @@ class Command(BaseCommand): def add_arguments(self, parser): """Add our two filename arguments.""" parser.add_argument("--directory", default="migrationdata", help="Desired directory") - parser.add_argument("--checkpath", default=True, help="Used for test cases") + parser.add_argument( + "--checkpath", + default=True, + help="Flag that determines if we do a check for os.path.exists. Used for test cases", + ) def handle(self, **options): + """Grabs the directory then creates current-full.csv in that directory""" # Ensures a slash is added directory = os.path.join(options.get("directory"), "") check_path = options.get("checkpath") @@ -32,6 +37,6 @@ class Command(BaseCommand): file_path = os.path.join(directory, "current-full.csv") with open(file_path, "w") as file: csv_export.export_data_full_to_csv(file) - + if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 3fff8a8a7..898437d06 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -152,7 +152,7 @@ class CsvReportsTest(TestCase): ) self.assertEqual(file_content, expected_file_content) - + def test_load_full_report(self): """Tests the current-federal api link""" self.maxDiff = None From 2faad04e9e14a2b7f9b274a01cc645c8a3428108 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:43:06 -0700 Subject: [PATCH 121/245] Linting changes --- src/api/views.py | 2 -- src/registrar/tests/test_reports.py | 31 ++++++++++++++--------------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/api/views.py b/src/api/views.py index b7c84a521..15515dd3a 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -94,8 +94,6 @@ def available(request, domain=""): @require_http_methods(["GET"]) @login_not_required def get_current_full(request, file_path="migrationdata/current-full.csv"): - # Open the CSV file - file_path = "migrationdata/current-full.csv" return serve_file(file_path) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 898437d06..2674823ee 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -1,5 +1,4 @@ import csv -from unittest import skip from django.test import Client, RequestFactory, TestCase from io import StringIO from registrar.models.domain_information import DomainInformation @@ -88,9 +87,9 @@ class CsvReportsTest(TestCase): def test_generate_federal_report(self): """Ensures that we correctly generate current-federal.csv""" expected_file_content = [ - call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), - call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), - call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), + call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n"), + call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \n"), + call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \n"), ] fake_open = mock_open() # We don't actually want to write anything for a test case, @@ -104,10 +103,10 @@ class CsvReportsTest(TestCase): def test_generate_full_report(self): """Ensures that we correctly generate current-full.csv""" expected_file_content = [ - call(f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), - call(f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), - call(f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), - call(f"adomain2.gov,Interstate,,,,, \r\n"), + call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n"), + call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \n"), + call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \n"), + call("adomain2.gov,Interstate,,,,, \n"), ] fake_open = mock_open() # We don't actually want to write anything for a test case, @@ -146,9 +145,9 @@ class CsvReportsTest(TestCase): # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( - f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" - f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" - f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,," + "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" + "ddomain3.gov,Federal,Armed Forces Retirement Home,,,," ) self.assertEqual(file_content, expected_file_content) @@ -157,16 +156,16 @@ class CsvReportsTest(TestCase): """Tests the current-federal api link""" self.maxDiff = None request = self.factory.get("/fake-path") - response = get_current_federal(request, file_path="registrar/tests/data/fake_current_full.csv") + response = get_current_full(request, file_path="registrar/tests/data/fake_current_full.csv") # Check that the response has status code 200 self.assertEqual(response.status_code, 200) # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( - f"Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" - f"cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" - f"ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\r\n" - f"adomain2.gov,Interstate,,,,," + "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" + "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n" + "adomain2.gov,Interstate,,,,," ) self.assertEqual(file_content, expected_file_content) From 3357696661dd00bfceba59c15ab74ad4d3de7374 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 28 Nov 2023 10:44:45 -0800 Subject: [PATCH 122/245] include required fields sentence in Other Contacts page --- src/registrar/templates/application_other_contacts.html | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/registrar/templates/application_other_contacts.html b/src/registrar/templates/application_other_contacts.html index bde203878..a3f0971dc 100644 --- a/src/registrar/templates/application_other_contacts.html +++ b/src/registrar/templates/application_other_contacts.html @@ -13,11 +13,9 @@ {% endblock %} {% block form_required_fields_help_text %} -{# there are no required fields on this page so don't show this #} +{% include "includes/required_fields.html" %} {% endblock %} - - {% block form_fields %} {{ forms.0.management_form }} {# forms.0 is a formset and this iterates over its forms #} From cf68aaea5b5f021799f8d69c3368fc6266f46073 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:52:34 -0700 Subject: [PATCH 123/245] Update test_reports.py --- src/registrar/tests/test_reports.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 2674823ee..160f80ef9 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -87,9 +87,9 @@ class CsvReportsTest(TestCase): def test_generate_federal_report(self): """Ensures that we correctly generate current-federal.csv""" expected_file_content = [ - call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n"), - call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \n"), - call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \n"), + call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), + call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), + call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), ] fake_open = mock_open() # We don't actually want to write anything for a test case, @@ -103,10 +103,10 @@ class CsvReportsTest(TestCase): def test_generate_full_report(self): """Ensures that we correctly generate current-full.csv""" expected_file_content = [ - call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n"), - call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \n"), - call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \n"), - call("adomain2.gov,Interstate,,,,, \n"), + call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), + call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), + call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), + call("adomain2.gov,Interstate,,,,, \r\n"), ] fake_open = mock_open() # We don't actually want to write anything for a test case, @@ -145,8 +145,8 @@ class CsvReportsTest(TestCase): # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( - "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" - "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" + "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" "ddomain3.gov,Federal,Armed Forces Retirement Home,,,," ) @@ -162,9 +162,9 @@ class CsvReportsTest(TestCase): # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( - "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" - "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" - "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n" + "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" + "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\r\n" "adomain2.gov,Interstate,,,,," ) From 328c0c0816866f418835c93c9f5ed94c986e471c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:08:57 -0700 Subject: [PATCH 124/245] Update test_reports.py --- src/registrar/tests/test_reports.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 160f80ef9..9f118a021 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -145,8 +145,8 @@ class CsvReportsTest(TestCase): # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( - "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" - "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" + "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email \r\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" "ddomain3.gov,Federal,Armed Forces Retirement Home,,,," ) @@ -163,8 +163,8 @@ class CsvReportsTest(TestCase): file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" - "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\r\n" - "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\r\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" + "ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n" "adomain2.gov,Interstate,,,,," ) From 00976b3b9b9022a46cce8e0a23d61aa350e42257 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:24:45 -0700 Subject: [PATCH 125/245] Add temp logging to find error --- src/registrar/tests/test_reports.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 9f118a021..f79f4be56 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -144,6 +144,8 @@ class CsvReportsTest(TestCase): self.assertEqual(response.status_code, 200) # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") + print("data to expect fed") + print(file_content) expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email \r\n" "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" @@ -161,6 +163,8 @@ class CsvReportsTest(TestCase): self.assertEqual(response.status_code, 200) # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") + print("data to expect") + print(file_content) expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" From 37456d57cc39cca5ea12dca5b3e264dadb861985 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:30:08 -0700 Subject: [PATCH 126/245] Update test_reports.py --- src/registrar/tests/test_reports.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index f79f4be56..b631f6040 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -9,7 +9,9 @@ from registrar.utility.csv_export import export_domains_to_writer from django.core.management import call_command from unittest.mock import call, mock_open, patch from api.views import get_current_federal, get_current_full +import logging +logger = logging.getLogger(__name__) class CsvReportsTest(TestCase): """Tests to determine if we are uploading our reports correctly""" @@ -144,8 +146,7 @@ class CsvReportsTest(TestCase): self.assertEqual(response.status_code, 200) # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") - print("data to expect fed") - print(file_content) + logger.info(f"data to expect fed: {file_content}") expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email \r\n" "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" @@ -163,8 +164,7 @@ class CsvReportsTest(TestCase): self.assertEqual(response.status_code, 200) # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") - print("data to expect") - print(file_content) + logger.info(f"data to expect full: {file_content}") expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" From e23ef4f5eb2c5504bca14a21c06a44e28fda8e41 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:35:25 -0700 Subject: [PATCH 127/245] Update test_reports.py --- src/registrar/tests/test_reports.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index b631f6040..ff734193d 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -9,9 +9,7 @@ from registrar.utility.csv_export import export_domains_to_writer from django.core.management import call_command from unittest.mock import call, mock_open, patch from api.views import get_current_federal, get_current_full -import logging -logger = logging.getLogger(__name__) class CsvReportsTest(TestCase): """Tests to determine if we are uploading our reports correctly""" @@ -146,10 +144,10 @@ class CsvReportsTest(TestCase): self.assertEqual(response.status_code, 200) # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") - logger.info(f"data to expect fed: {file_content}") + expected_file_content = ( - "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email \r\n" - "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" + "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \n" "ddomain3.gov,Federal,Armed Forces Retirement Home,,,," ) @@ -164,11 +162,10 @@ class CsvReportsTest(TestCase): self.assertEqual(response.status_code, 200) # Check that the response contains what we expect file_content = b"".join(response.streaming_content).decode("utf-8") - logger.info(f"data to expect full: {file_content}") expected_file_content = ( - "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n" - "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n" - "ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n" + "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" + "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n" "adomain2.gov,Interstate,,,,," ) From 3f1a8b4ef597cb3006ec6e09ec8573694ba075b6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:38:58 -0700 Subject: [PATCH 128/245] Fix test cases --- src/registrar/tests/test_reports.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index ff734193d..cb1d6a0b9 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -137,7 +137,6 @@ class CsvReportsTest(TestCase): def test_load_federal_report(self): """Tests the current-federal api link""" - self.maxDiff = None request = self.factory.get("/fake-path") response = get_current_federal(request, file_path="registrar/tests/data/fake_current_federal.csv") # Check that the response has status code 200 @@ -147,7 +146,7 @@ class CsvReportsTest(TestCase): expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" - "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \n" + "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" "ddomain3.gov,Federal,Armed Forces Retirement Home,,,," ) @@ -155,7 +154,6 @@ class CsvReportsTest(TestCase): def test_load_full_report(self): """Tests the current-federal api link""" - self.maxDiff = None request = self.factory.get("/fake-path") response = get_current_full(request, file_path="registrar/tests/data/fake_current_full.csv") # Check that the response has status code 200 From f5974e00dcb103afb20fea7160bd8d5954454332 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 28 Nov 2023 15:55:45 -0700 Subject: [PATCH 129/245] Create s3_bucket.py --- src/registrar/utility/s3_bucket.py | 62 ++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/registrar/utility/s3_bucket.py diff --git a/src/registrar/utility/s3_bucket.py b/src/registrar/utility/s3_bucket.py new file mode 100644 index 000000000..af59fdb67 --- /dev/null +++ b/src/registrar/utility/s3_bucket.py @@ -0,0 +1,62 @@ +"""Utilities for accessing an AWS S3 bucket""" + +import boto3 + +from django.conf import settings +from django.template.loader import get_template + + +class S3ClientError(RuntimeError): + """Local error for handling all failures with boto3.client""" + pass + + +class S3ClientHelper: + """Helper class that simplifies S3 intialization""" + def __init__(self): + try: + self.boto_client = boto3.client( + "s3", + region_name=settings.AWS_S3_REGION, + aws_access_key_id=settings.AWS_S3_ACCESS_KEY_ID, + aws_secret_access_key=settings.AWS_S3_SECRET_ACCESS_KEY + #config=settings.BOTO_CONFIG, + ) + except Exception as exc: + raise S3ClientError("Could not access the S3 client.") from exc + + #self.bucket_name = + print("here:") + bucket = self.list_objects() + print(bucket) + + def get_bucket_name(self): + """Gets the name of our S3 Bucket""" + return settings.AWS_S3_BUCKET_NAME + + def list_objects(self): + """Returns a list of the top 1000 objects within our S3 instance""" + try: + response = self.boto_client.list_objects_v2(Bucket=self.get_bucket_name()) + except Exception as exc: + raise S3ClientError("Couldn't list objects") from exc + return response + + def upload_file(self, file_path, file_name): + """Uploads a file to our S3 instance""" + try: + response = self.boto_client.upload_file(file_path, self.get_bucket_name(), file_name) + except Exception as exc: + raise S3ClientError("Couldn't upload file") from exc + return response + + def get_file(self, file_name, decode_to_utf=False): + """Gets a file to our S3 instance and returns the file content""" + try: + response = self.boto_client.get_object(Bucket=self.get_bucket_name(), Key=file_name) + except Exception as exc: + raise S3ClientError("Couldn't get file") from exc + file_content = response["Body"].read() + if decode_to_utf: + return file_content.decode("utf-8") + return file_content From 1134b781004780f0e672808694f4a430bc0dac63 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 28 Nov 2023 18:30:53 -0800 Subject: [PATCH 130/245] adding (optional) text to anything else app page --- src/registrar/forms/application_wizard.py | 2 +- src/registrar/models/domain_application.py | 2 +- src/registrar/models/domain_information.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index c974fe18d..98997aae8 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -620,7 +620,7 @@ class NoOtherContactsForm(RegistrarForm): class AnythingElseForm(RegistrarForm): anything_else = forms.CharField( required=False, - label="Anything else we should know?", + label="Anything else we should know? (optional)", widget=forms.Textarea(), validators=[ MaxLengthValidator( diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 6418ff308..0ca768288 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -543,7 +543,7 @@ class DomainApplication(TimeStampedModel): anything_else = models.TextField( null=True, blank=True, - help_text="Anything else we should know?", + help_text="Anything else we should know? (optional)", ) is_policy_acknowledged = models.BooleanField( diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 6e20f4c5e..83a818aa2 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -190,7 +190,7 @@ class DomainInformation(TimeStampedModel): anything_else = models.TextField( null=True, blank=True, - help_text="Anything else we should know?", + help_text="Anything else we should know? (optional)", ) is_policy_acknowledged = models.BooleanField( From deab78ccbe9f6e4d026b2ffd14f0b86a6ca66265 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 28 Nov 2023 18:48:20 -0800 Subject: [PATCH 131/245] migrations --- ...omainapplication_anything_else_and_more.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py diff --git a/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py b/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py new file mode 100644 index 000000000..6cc14a219 --- /dev/null +++ b/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.7 on 2023-11-29 02:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0049_alter_domainapplication_urbanization_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="anything_else", + field=models.TextField(blank=True, help_text="Anything else we should know? (optional)", null=True), + ), + migrations.AlterField( + model_name="domaininformation", + name="anything_else", + field=models.TextField(blank=True, help_text="Anything else we should know? (optional)", null=True), + ), + ] From 25a0ceb330cd974bd397e9e64e1797c6a2c2f935 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 28 Nov 2023 19:02:13 -0800 Subject: [PATCH 132/245] adding (optional) text to anything else app page --- src/registrar/admin.py | 2 +- src/registrar/views/application.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 6585d602a..74b83e2a0 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -434,7 +434,7 @@ class DomainInformationAdmin(ListHeaderAdmin): "No other employees from your organization?", {"fields": ["no_other_contacts_rationale"]}, ), - ("Anything else we should know?", {"fields": ["anything_else"]}), + ("Anything else we should know? (optional)", {"fields": ["anything_else"]}), ( "Requirements for operating .gov domains", {"fields": ["is_policy_acknowledged"]}, diff --git a/src/registrar/views/application.py b/src/registrar/views/application.py index e907be8e5..e21f1a3ea 100644 --- a/src/registrar/views/application.py +++ b/src/registrar/views/application.py @@ -85,7 +85,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): Step.YOUR_CONTACT: _("Your contact information"), Step.OTHER_CONTACTS: _("Other employees from your organization"), Step.NO_OTHER_CONTACTS: _("No other employees from your organization?"), - Step.ANYTHING_ELSE: _("Anything else we should know?"), + Step.ANYTHING_ELSE: _("Anything else we should know? (optional)"), Step.REQUIREMENTS: _("Requirements for operating .gov domains"), Step.REVIEW: _("Review and submit your domain request"), } From cff5e39a173e0a3c46c45788b448f56d96c0487f Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 28 Nov 2023 19:20:32 -0800 Subject: [PATCH 133/245] add optional to title of security email page --- src/registrar/forms/domain.py | 2 +- src/registrar/templates/domain_security_email.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py index 6ba48a0eb..0305dadd5 100644 --- a/src/registrar/forms/domain.py +++ b/src/registrar/forms/domain.py @@ -223,7 +223,7 @@ class DomainSecurityEmailForm(forms.Form): """Form for adding or editing a security email to a domain.""" security_email = forms.EmailField( - label="Security email (optional)", + label="Security email", required=False, error_messages={ "invalid": str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)), diff --git a/src/registrar/templates/domain_security_email.html b/src/registrar/templates/domain_security_email.html index 4054186da..f52ef4549 100644 --- a/src/registrar/templates/domain_security_email.html +++ b/src/registrar/templates/domain_security_email.html @@ -6,7 +6,7 @@ {% block domain_content %} {% include "includes/form_errors.html" with form=form %} -

Security email

+

Security email (optional)

We strongly recommend that you provide a security email. This email will allow the public to report observed or suspected security issues on your domain. Security emails are made public and included in the .gov domain data we provide.

From e78a506d2b2cde785b357c65888bf91595236f4c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 08:36:12 -0700 Subject: [PATCH 134/245] Link bucket to generator --- src/api/views.py | 13 +++++++++---- .../commands/generate_current_full_report.py | 16 ++++++++++++---- src/registrar/utility/s3_bucket.py | 13 +++++-------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/api/views.py b/src/api/views.py index 15515dd3a..ddd96f744 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -9,6 +9,8 @@ from login_required import login_not_required from cachetools.func import ttl_cache +from registrar.utility.s3_bucket import S3ClientHelper + DOMAIN_FILE_URL = "https://raw.githubusercontent.com/cisagov/dotgov-data/main/current-full.csv" @@ -94,21 +96,24 @@ def available(request, domain=""): @require_http_methods(["GET"]) @login_not_required def get_current_full(request, file_path="migrationdata/current-full.csv"): - return serve_file(file_path) + return serve_file(file_path, "current-full.csv") @require_http_methods(["GET"]) @login_not_required def get_current_federal(request, file_path="migrationdata/current-federal.csv"): - return serve_file(file_path) + return serve_file(file_path, "current-federal.csv") -def serve_file(file_path): +def serve_file(file_path, file_name): """Downloads a file based on a given filepath. Returns a 404 if not found.""" + s3_client = S3ClientHelper() # TODO - #1403, grab from the S3 instance instead + # TODO - check if file exists in s3, not here if os.path.exists(file_path): # Serve the CSV file - response = FileResponse(open(file_path, "rb")) + file = s3_client.get_file(file_name) + response = FileResponse(file) return response else: return HttpResponse("File not found", status=404) diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 7db334186..f9ed12ba5 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -4,6 +4,7 @@ import os from django.core.management import BaseCommand from registrar.utility import csv_export +from registrar.utility.s3_bucket import S3ClientHelper logger = logging.getLogger(__name__) @@ -23,20 +24,27 @@ class Command(BaseCommand): def handle(self, **options): """Grabs the directory then creates current-full.csv in that directory""" + file_name = "current-full.csv" # Ensures a slash is added directory = os.path.join(options.get("directory"), "") check_path = options.get("checkpath") logger.info("Generating report...") - self.generate_current_full_report(directory, check_path) - logger.info(f"Success! Created {directory}current-full.csv") + self.generate_current_full_report(directory, file_name, check_path) - def generate_current_full_report(self, directory, check_path): + file_path = os.path.join(directory, file_name) + logger.info(f"Success! Created {file_path}") + + def generate_current_full_report(self, directory, file_name, check_path): """Creates a current-full.csv file under the specified directory""" + s3_client = S3ClientHelper() # TODO - #1403, push to the S3 instance instead - file_path = os.path.join(directory, "current-full.csv") + file_path = os.path.join(directory, file_name) + # TODO - Don't genererate a useless file with open(file_path, "w") as file: csv_export.export_data_full_to_csv(file) if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") + + s3_client.upload_file(file_path, file_name) diff --git a/src/registrar/utility/s3_bucket.py b/src/registrar/utility/s3_bucket.py index af59fdb67..959c6b23a 100644 --- a/src/registrar/utility/s3_bucket.py +++ b/src/registrar/utility/s3_bucket.py @@ -25,15 +25,10 @@ class S3ClientHelper: except Exception as exc: raise S3ClientError("Could not access the S3 client.") from exc - #self.bucket_name = - print("here:") - bucket = self.list_objects() - print(bucket) - def get_bucket_name(self): """Gets the name of our S3 Bucket""" return settings.AWS_S3_BUCKET_NAME - + def list_objects(self): """Returns a list of the top 1000 objects within our S3 instance""" try: @@ -49,14 +44,16 @@ class S3ClientHelper: except Exception as exc: raise S3ClientError("Couldn't upload file") from exc return response - + def get_file(self, file_name, decode_to_utf=False): """Gets a file to our S3 instance and returns the file content""" try: response = self.boto_client.get_object(Bucket=self.get_bucket_name(), Key=file_name) except Exception as exc: raise S3ClientError("Couldn't get file") from exc + file_content = response["Body"].read() if decode_to_utf: return file_content.decode("utf-8") - return file_content + else: + return file_content From 5530db82fdcaca3ec42aca92fb7a23ebbbe77725 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 08:42:09 -0700 Subject: [PATCH 135/245] Add comments --- src/api/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api/views.py b/src/api/views.py index 782a770ef..7dc336460 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -102,12 +102,18 @@ def available(request, domain=""): @require_http_methods(["GET"]) @login_not_required def get_current_full(request, file_path="migrationdata/current-full.csv"): + """This will return the file content of current-full.csv which is the command + output of generate_current_full_report.py. This command iterates through each Domain + and returns a CSV representation.""" return serve_file(file_path) @require_http_methods(["GET"]) @login_not_required def get_current_federal(request, file_path="migrationdata/current-federal.csv"): + """This will return the file content of current-federal.csv which is the command + output of generate_current_federal_report.py. This command iterates through each Domain + and returns a CSV representation.""" return serve_file(file_path) From c328e053982da9dacbf55f6d7fb02235661b19b4 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 08:44:13 -0800 Subject: [PATCH 136/245] making anything else page format more consistent --- src/registrar/forms/application_wizard.py | 2 +- src/registrar/models/domain_application.py | 2 +- src/registrar/models/domain_information.py | 2 +- src/registrar/templates/application_anything_else.html | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index 98997aae8..c974fe18d 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -620,7 +620,7 @@ class NoOtherContactsForm(RegistrarForm): class AnythingElseForm(RegistrarForm): anything_else = forms.CharField( required=False, - label="Anything else we should know? (optional)", + label="Anything else we should know?", widget=forms.Textarea(), validators=[ MaxLengthValidator( diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 0ca768288..6418ff308 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -543,7 +543,7 @@ class DomainApplication(TimeStampedModel): anything_else = models.TextField( null=True, blank=True, - help_text="Anything else we should know? (optional)", + help_text="Anything else we should know?", ) is_policy_acknowledged = models.BooleanField( diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 83a818aa2..6e20f4c5e 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -190,7 +190,7 @@ class DomainInformation(TimeStampedModel): anything_else = models.TextField( null=True, blank=True, - help_text="Anything else we should know? (optional)", + help_text="Anything else we should know?", ) is_policy_acknowledged = models.BooleanField( diff --git a/src/registrar/templates/application_anything_else.html b/src/registrar/templates/application_anything_else.html index 1c598db9a..ac9c9787c 100644 --- a/src/registrar/templates/application_anything_else.html +++ b/src/registrar/templates/application_anything_else.html @@ -2,7 +2,7 @@ {% load field_helpers %} {% block form_instructions %} -

Is there anything else we should know about your domain request?

+

Is there anything else we should know about your domain request? (optional)

{% endblock %} {% block form_required_fields_help_text %} From d7984c69d6fb9ae6ada416634eddce9c60959c0f Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 08:52:37 -0800 Subject: [PATCH 137/245] migrations --- ...omainapplication_anything_else_and_more.py | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py diff --git a/src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py b/src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py new file mode 100644 index 000000000..7c8f9c3f6 --- /dev/null +++ b/src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.7 on 2023-11-29 16:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0050_alter_domainapplication_anything_else_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="anything_else", + field=models.TextField(blank=True, help_text="Anything else we should know?", null=True), + ), + migrations.AlterField( + model_name="domaininformation", + name="anything_else", + field=models.TextField(blank=True, help_text="Anything else we should know?", null=True), + ), + ] From 7cd037999ee6df6563c20126dfb4fc495f46eeee Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 09:21:34 -0800 Subject: [PATCH 138/245] removing optional from title on anything else page --- src/registrar/views/application.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/views/application.py b/src/registrar/views/application.py index e21f1a3ea..e907be8e5 100644 --- a/src/registrar/views/application.py +++ b/src/registrar/views/application.py @@ -85,7 +85,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): Step.YOUR_CONTACT: _("Your contact information"), Step.OTHER_CONTACTS: _("Other employees from your organization"), Step.NO_OTHER_CONTACTS: _("No other employees from your organization?"), - Step.ANYTHING_ELSE: _("Anything else we should know? (optional)"), + Step.ANYTHING_ELSE: _("Anything else we should know?"), Step.REQUIREMENTS: _("Requirements for operating .gov domains"), Step.REVIEW: _("Review and submit your domain request"), } From 59950a1fde709293f32c05d6b07818426822615e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 11:57:17 -0700 Subject: [PATCH 139/245] Change logging and add secrets --- .github/workflows/daily-csv-upload.yaml | 18 +++++++++- src/api/views.py | 33 ++++++++++--------- src/registrar/config/settings.py | 12 +++++++ .../generate_current_federal_report.py | 27 +++++++++++---- .../commands/generate_current_full_report.py | 24 +++++++++----- src/registrar/utility/s3_bucket.py | 9 ++--- 6 files changed, 86 insertions(+), 37 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 174244ad6..5925cffcb 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,6 +2,7 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: + pull_request: workflow_dispatch: inputs: environment: @@ -42,9 +43,24 @@ jobs: const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; core.setOutput('environment', environment); + wait-for-deploy: + runs-on: ubuntu-latest + steps: + - name: Wait for deploy to complete + uses: fountainhead/action-wait-for-check@v1.0.0 + id: wait-for-deploy + with: + token: ${{ secrets.GITHUB_TOKEN }} + checkName: "deploy" + ref: ${{ github.event.pull_request.head.sha }} + # the maximum time to wait for the check to complete, in seconds + timeoutSeconds: 600 + # the time to wait between checks, in seconds + intervalSeconds: 10 + upload-reports: runs-on: ubuntu-latest - needs: [variables] + needs: [variables, wait-for-deploy] env: CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD diff --git a/src/api/views.py b/src/api/views.py index 9f077fea6..60f11023e 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -12,7 +12,7 @@ from login_required import login_not_required from cachetools.func import ttl_cache -from registrar.utility.s3_bucket import S3ClientHelper +from registrar.utility.s3_bucket import S3ClientError, S3ClientHelper DOMAIN_FILE_URL = "https://raw.githubusercontent.com/cisagov/dotgov-data/main/current-full.csv" @@ -103,31 +103,32 @@ def available(request, domain=""): @require_http_methods(["GET"]) @login_not_required -def get_current_full(request, file_path="migrationdata/current-full.csv"): +def get_current_full(request, file_name="current-full.csv"): """This will return the file content of current-full.csv which is the command output of generate_current_full_report.py. This command iterates through each Domain and returns a CSV representation.""" - return serve_file(file_path, "current-full.csv") + return serve_file(file_name) @require_http_methods(["GET"]) @login_not_required -def get_current_federal(request, file_path="migrationdata/current-federal.csv"): +def get_current_federal(request, file_name="current-federal.csv"): """This will return the file content of current-federal.csv which is the command output of generate_current_federal_report.py. This command iterates through each Domain and returns a CSV representation.""" - return serve_file(file_path, "current-federal.csv") + return serve_file(file_name) -def serve_file(file_path, file_name): - """Downloads a file based on a given filepath. Returns a 404 if not found.""" +def serve_file(file_name): + """Downloads a file based on a given filepath. Returns a 500 if not found.""" s3_client = S3ClientHelper() - # TODO - #1403, grab from the S3 instance instead - # TODO - check if file exists in s3, not here - if os.path.exists(file_path): - # Serve the CSV file - file = s3_client.get_file(file_name) - response = FileResponse(file) - return response - else: - return HttpResponse("File not found", status=404) + # Serve the CSV file. If not found, an exception will be thrown. + # This will then be caught by flat, causing it to not read it - which is what we want. + try: + file = s3_client.get_file(file_name, decode_to_utf=True) + except S3ClientError as err: + # TODO - #1317: Notify operations when auto report generation fails + raise err + + response = HttpResponse(file) + return response diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 3487b1b66..5de143cb1 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -58,6 +58,11 @@ secret_key = secret("DJANGO_SECRET_KEY") secret_aws_ses_key_id = secret("AWS_ACCESS_KEY_ID", None) secret_aws_ses_key = secret("AWS_SECRET_ACCESS_KEY", None) +aws_s3_region_name = secret("AWS_S3_ACCESS_KEY_ID", None) +secret_aws_s3_key_id = secret("AWS_S3_SECRET_ACCESS_KEY", None) +secret_aws_s3_key = secret("AWS_S3_REGION", None) +secret_aws_s3_bucket_name = secret("AWS_S3_BUCKET_NAME", None) + secret_registry_cl_id = secret("REGISTRY_CL_ID") secret_registry_password = secret("REGISTRY_PASSWORD") secret_registry_cert = b64decode(secret("REGISTRY_CERT", "")) @@ -257,6 +262,13 @@ AUTH_USER_MODEL = "registrar.User" AWS_ACCESS_KEY_ID = secret_aws_ses_key_id AWS_SECRET_ACCESS_KEY = secret_aws_ses_key AWS_REGION = "us-gov-west-1" + +# Configuration for accessing AWS S3 +AWS_S3_ACCESS_KEY_ID = secret_aws_s3_key_id +AWS_S3_SECRET_ACCESS_KEY = secret_aws_s3_key +AWS_S3_REGION = aws_s3_region_name +AWS_S3_BUCKET_NAME = secret_aws_s3_bucket_name + # https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html#standard-retry-mode AWS_RETRY_MODE: Final = "standard" # base 2 exponential backoff with max of 20 seconds: diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 8abb4f493..6075d8ebb 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -4,6 +4,7 @@ import os from django.core.management import BaseCommand from registrar.utility import csv_export +from registrar.utility.s3_bucket import S3ClientHelper logger = logging.getLogger(__name__) @@ -23,20 +24,32 @@ class Command(BaseCommand): def handle(self, **options): """Grabs the directory then creates current-federal.csv in that directory""" + file_name = "current-federal.csv" # Ensures a slash is added directory = os.path.join(options.get("directory"), "") check_path = options.get("checkpath") + logger.info("Generating report...") + try: + self.generate_current_federal_report(directory, file_name, check_path) + except Exception as err: + # TODO - #1317: Notify operations when auto report generation fails + raise err + else: + logger.info(f"Success! Created {file_name}") - self.generate_current_federal_report(directory, check_path) - logger.info(f"Success! Created {directory}current-federal.csv") - - def generate_current_federal_report(self, directory, check_path): - """Creates a current-full.csv file under the specified directory""" - # TODO - #1403, push to the S3 instance instead - file_path = os.path.join(directory, "current-federal.csv") + def generate_current_federal_report(self, directory, file_name, check_path): + """Creates a current-full.csv file under the specified directory, + then uploads it to a AWS S3 bucket""" + s3_client = S3ClientHelper() + file_path = os.path.join(directory, file_name) + + # Generate a file locally for upload with open(file_path, "w") as file: csv_export.export_data_federal_to_csv(file) if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") + + # Upload this generated file for our S3 instance + s3_client.upload_file(file_path, file_name) diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index f9ed12ba5..83be4f9b5 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -28,23 +28,29 @@ class Command(BaseCommand): # Ensures a slash is added directory = os.path.join(options.get("directory"), "") check_path = options.get("checkpath") + logger.info("Generating report...") - - self.generate_current_full_report(directory, file_name, check_path) - - file_path = os.path.join(directory, file_name) - logger.info(f"Success! Created {file_path}") + try: + self.generate_current_full_report(directory, file_name, check_path) + except Exception as err: + # TODO - #1317: Notify operations when auto report generation fails + raise err + else: + logger.info(f"Success! Created {file_name}") def generate_current_full_report(self, directory, file_name, check_path): - """Creates a current-full.csv file under the specified directory""" + """Creates a current-full.csv file under the specified directory, + then uploads it to a AWS S3 bucket""" s3_client = S3ClientHelper() - # TODO - #1403, push to the S3 instance instead file_path = os.path.join(directory, file_name) - # TODO - Don't genererate a useless file + + # Generate a file locally for upload with open(file_path, "w") as file: csv_export.export_data_full_to_csv(file) if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") - + + # Upload this generated file for our S3 instance s3_client.upload_file(file_path, file_name) + diff --git a/src/registrar/utility/s3_bucket.py b/src/registrar/utility/s3_bucket.py index 959c6b23a..9e7f0da31 100644 --- a/src/registrar/utility/s3_bucket.py +++ b/src/registrar/utility/s3_bucket.py @@ -19,8 +19,8 @@ class S3ClientHelper: "s3", region_name=settings.AWS_S3_REGION, aws_access_key_id=settings.AWS_S3_ACCESS_KEY_ID, - aws_secret_access_key=settings.AWS_S3_SECRET_ACCESS_KEY - #config=settings.BOTO_CONFIG, + aws_secret_access_key=settings.AWS_S3_SECRET_ACCESS_KEY, + config=settings.BOTO_CONFIG, ) except Exception as exc: raise S3ClientError("Could not access the S3 client.") from exc @@ -49,9 +49,10 @@ class S3ClientHelper: """Gets a file to our S3 instance and returns the file content""" try: response = self.boto_client.get_object(Bucket=self.get_bucket_name(), Key=file_name) + except self.boto_client.exceptions.NoSuchKey as exc: + raise S3ClientError("File was not found") from exc except Exception as exc: - raise S3ClientError("Couldn't get file") from exc - + raise S3ClientError("Couldn't get file, an unspecified error occured") from exc file_content = response["Body"].read() if decode_to_utf: return file_content.decode("utf-8") From fa72f413abcfc1a4f20b8fdb69e674dfc0ecd4c2 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 11:10:18 -0800 Subject: [PATCH 140/245] changing anything else page --- src/registrar/admin.py | 4 ++-- src/registrar/forms/application_wizard.py | 2 +- ...omainapplication_anything_else_and_more.py | 6 ++--- ...omainapplication_anything_else_and_more.py | 22 ------------------- src/registrar/models/domain_application.py | 2 +- src/registrar/models/domain_information.py | 2 +- .../templates/application_anything_else.html | 2 +- .../templates/application_status.html | 2 +- .../emails/includes/application_summary.txt | 2 +- src/registrar/views/application.py | 2 +- 10 files changed, 12 insertions(+), 34 deletions(-) delete mode 100644 src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 74b83e2a0..82dba6e02 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -434,7 +434,7 @@ class DomainInformationAdmin(ListHeaderAdmin): "No other employees from your organization?", {"fields": ["no_other_contacts_rationale"]}, ), - ("Anything else we should know? (optional)", {"fields": ["anything_else"]}), + ("Anything else?", {"fields": ["anything_else"]}), ( "Requirements for operating .gov domains", {"fields": ["is_policy_acknowledged"]}, @@ -569,7 +569,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): "No other employees from your organization?", {"fields": ["no_other_contacts_rationale"]}, ), - ("Anything else we should know?", {"fields": ["anything_else"]}), + ("Anything else?", {"fields": ["anything_else"]}), ( "Requirements for operating .gov domains", {"fields": ["is_policy_acknowledged"]}, diff --git a/src/registrar/forms/application_wizard.py b/src/registrar/forms/application_wizard.py index c974fe18d..ad11ebfd3 100644 --- a/src/registrar/forms/application_wizard.py +++ b/src/registrar/forms/application_wizard.py @@ -620,7 +620,7 @@ class NoOtherContactsForm(RegistrarForm): class AnythingElseForm(RegistrarForm): anything_else = forms.CharField( required=False, - label="Anything else we should know?", + label="Anything else?", widget=forms.Textarea(), validators=[ MaxLengthValidator( diff --git a/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py b/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py index 6cc14a219..a84e7e1c4 100644 --- a/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py +++ b/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.7 on 2023-11-29 02:47 +# Generated by Django 4.2.7 on 2023-11-29 19:05 from django.db import migrations, models @@ -12,11 +12,11 @@ class Migration(migrations.Migration): migrations.AlterField( model_name="domainapplication", name="anything_else", - field=models.TextField(blank=True, help_text="Anything else we should know? (optional)", null=True), + field=models.TextField(blank=True, help_text="Anything else?", null=True), ), migrations.AlterField( model_name="domaininformation", name="anything_else", - field=models.TextField(blank=True, help_text="Anything else we should know? (optional)", null=True), + field=models.TextField(blank=True, help_text="Anything else?", null=True), ), ] diff --git a/src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py b/src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py deleted file mode 100644 index 7c8f9c3f6..000000000 --- a/src/registrar/migrations/0051_alter_domainapplication_anything_else_and_more.py +++ /dev/null @@ -1,22 +0,0 @@ -# Generated by Django 4.2.7 on 2023-11-29 16:51 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("registrar", "0050_alter_domainapplication_anything_else_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="domainapplication", - name="anything_else", - field=models.TextField(blank=True, help_text="Anything else we should know?", null=True), - ), - migrations.AlterField( - model_name="domaininformation", - name="anything_else", - field=models.TextField(blank=True, help_text="Anything else we should know?", null=True), - ), - ] diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 6418ff308..d10539145 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -543,7 +543,7 @@ class DomainApplication(TimeStampedModel): anything_else = models.TextField( null=True, blank=True, - help_text="Anything else we should know?", + help_text="Anything else?", ) is_policy_acknowledged = models.BooleanField( diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index 6e20f4c5e..62b0362ec 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -190,7 +190,7 @@ class DomainInformation(TimeStampedModel): anything_else = models.TextField( null=True, blank=True, - help_text="Anything else we should know?", + help_text="Anything else?", ) is_policy_acknowledged = models.BooleanField( diff --git a/src/registrar/templates/application_anything_else.html b/src/registrar/templates/application_anything_else.html index ac9c9787c..f69b7e70e 100644 --- a/src/registrar/templates/application_anything_else.html +++ b/src/registrar/templates/application_anything_else.html @@ -2,7 +2,7 @@ {% load field_helpers %} {% block form_instructions %} -

Is there anything else we should know about your domain request? (optional)

+

Is there anything else you'd like us to know about your domain request? This question is optional.

{% endblock %} {% block form_required_fields_help_text %} diff --git a/src/registrar/templates/application_status.html b/src/registrar/templates/application_status.html index 79d0f7ff9..3bf02f0e0 100644 --- a/src/registrar/templates/application_status.html +++ b/src/registrar/templates/application_status.html @@ -111,7 +111,7 @@ {% include "includes/summary_item.html" with title='Other employees from your organization' value=domainapplication.other_contacts.all contact='true' list='true' heading_level=heading_level %} - {% include "includes/summary_item.html" with title='Anything else we should know' value=domainapplication.anything_else|default:"No" heading_level=heading_level %} + {% include "includes/summary_item.html" with title='Anything else?' value=domainapplication.anything_else|default:"No" heading_level=heading_level %} {% endwith %} diff --git a/src/registrar/templates/emails/includes/application_summary.txt b/src/registrar/templates/emails/includes/application_summary.txt index 293dad2e4..c628e1074 100644 --- a/src/registrar/templates/emails/includes/application_summary.txt +++ b/src/registrar/templates/emails/includes/application_summary.txt @@ -34,6 +34,6 @@ Other employees from your organization: {% for other in application.other_contacts.all %} {% spaceless %}{% include "emails/includes/contact.txt" with contact=other %}{% endspaceless %} {% endfor %}{% endif %}{% if application.anything_else %} -Anything else we should know? +Anything else? {{ application.anything_else }} {% endif %} \ No newline at end of file diff --git a/src/registrar/views/application.py b/src/registrar/views/application.py index e907be8e5..dd185198f 100644 --- a/src/registrar/views/application.py +++ b/src/registrar/views/application.py @@ -85,7 +85,7 @@ class ApplicationWizard(ApplicationWizardPermissionView, TemplateView): Step.YOUR_CONTACT: _("Your contact information"), Step.OTHER_CONTACTS: _("Other employees from your organization"), Step.NO_OTHER_CONTACTS: _("No other employees from your organization?"), - Step.ANYTHING_ELSE: _("Anything else we should know?"), + Step.ANYTHING_ELSE: _("Anything else?"), Step.REQUIREMENTS: _("Requirements for operating .gov domains"), Step.REVIEW: _("Review and submit your domain request"), } From 462ebe4454017881ace448e6fb6cd0212e22d4c1 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 11:15:24 -0800 Subject: [PATCH 141/245] updating test_emails.py to reflect new anything else title --- src/registrar/tests/test_emails.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py index 7bce52668..eb6da072d 100644 --- a/src/registrar/tests/test_emails.py +++ b/src/registrar/tests/test_emails.py @@ -158,7 +158,7 @@ class TestEmails(TestCase): _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] # spacing should be right between adjacent elements - self.assertRegex(body, r"5557\n\nAnything else we should know?") + self.assertRegex(body, r"5557\n\nAnything else?") @boto3_mocking.patching def test_submission_confirmation_no_anything_else_spacing(self): @@ -168,6 +168,6 @@ class TestEmails(TestCase): application.submit() _, kwargs = self.mock_client.send_email.call_args body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"] - self.assertNotIn("Anything else we should know", body) + self.assertNotIn("Anything else", body) # spacing should be right between adjacent elements self.assertRegex(body, r"5557\n\n----") From e90d254339131ebd115370b4992798e1768e0da2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 12:50:59 -0700 Subject: [PATCH 142/245] Test s3 config settings --- src/registrar/config/settings.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 5de143cb1..a76f87847 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -38,6 +38,13 @@ if key_service and key_service.credentials: else: secret = env +# Get secrets from Cloud.gov user provided s3 service, if exists +# If not, get secrets from environment variables. +s3_key_service = AppEnv().get_service(name="getgov-s3") +if s3_key_service and s3_key_service.credentials: + secret_s3 = s3_key_service.credentials.get +else: + secret_s3 = None # # # ### # Values obtained externally # # # # ### @@ -58,10 +65,10 @@ secret_key = secret("DJANGO_SECRET_KEY") secret_aws_ses_key_id = secret("AWS_ACCESS_KEY_ID", None) secret_aws_ses_key = secret("AWS_SECRET_ACCESS_KEY", None) -aws_s3_region_name = secret("AWS_S3_ACCESS_KEY_ID", None) -secret_aws_s3_key_id = secret("AWS_S3_SECRET_ACCESS_KEY", None) -secret_aws_s3_key = secret("AWS_S3_REGION", None) -secret_aws_s3_bucket_name = secret("AWS_S3_BUCKET_NAME", None) +aws_s3_region_name = secret_s3("region", None) +secret_aws_s3_key_id = secret_s3("access_key_id", None) +secret_aws_s3_key = secret_s3("secret_access_key", None) +secret_aws_s3_bucket_name = secret_s3("bucket", None) secret_registry_cl_id = secret("REGISTRY_CL_ID") secret_registry_password = secret("REGISTRY_PASSWORD") @@ -269,7 +276,7 @@ AWS_S3_SECRET_ACCESS_KEY = secret_aws_s3_key AWS_S3_REGION = aws_s3_region_name AWS_S3_BUCKET_NAME = secret_aws_s3_bucket_name -# https://boto3.amazonaws.com/v1/documentation/api/latest/guide/retries.html#standard-retry-mode +# https://boto3.amazonaws.com/v1/documentation/latest/guide/retries.html#standard-retry-mode AWS_RETRY_MODE: Final = "standard" # base 2 exponential backoff with max of 20 seconds: AWS_MAX_ATTEMPTS = 3 From 98aa1c11c800c18e71befb27e541646971f0d530 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 12:57:44 -0700 Subject: [PATCH 143/245] Update settings.py --- src/registrar/config/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index a76f87847..530de3af3 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -44,7 +44,7 @@ s3_key_service = AppEnv().get_service(name="getgov-s3") if s3_key_service and s3_key_service.credentials: secret_s3 = s3_key_service.credentials.get else: - secret_s3 = None + secret_s3 = env # # # ### # Values obtained externally # # # # ### From 5b4960268417b9df879b1eeb9e578001d3b14824 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:15:11 -0700 Subject: [PATCH 144/245] Update workflow --- .github/workflows/daily-csv-upload.yaml | 8 ++++---- src/registrar/tests/test_reports.py | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 5925cffcb..bcec795d2 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -66,20 +66,20 @@ jobs: CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD steps: - name: Generate current-federal.csv - uses: 18f/cg-deploy-action@main + uses: cloud-gov/cg-cli-tools@main with: cf_username: ${{ secrets[env.CF_USERNAME] }} cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} - full_command: "cf run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" + cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" - name: Generate current-full.csv - uses: 18f/cg-deploy-action@main + uses: cloud-gov/cg-cli-tools@main with: cf_username: ${{ secrets[env.CF_USERNAME] }} cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} - full_command: "cf run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_full_report' --name full" + cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_full_report' --name full" diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 5fe12fa37..c0c520955 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -9,7 +9,7 @@ from registrar.utility.csv_export import export_domains_to_writer from django.core.management import call_command from unittest.mock import call, mock_open, patch from api.views import get_current_federal, get_current_full - +import boto3_mocking # type: ignore class CsvReportsTest(TestCase): """Tests to determine if we are uploading our reports correctly""" @@ -84,6 +84,7 @@ class CsvReportsTest(TestCase): error = err.exception self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-full.csv'") + @boto3_mocking.patching def test_generate_federal_report(self): """Ensures that we correctly generate current-federal.csv""" expected_file_content = [ @@ -100,6 +101,7 @@ class CsvReportsTest(TestCase): # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) + @boto3_mocking.patching def test_generate_full_report(self): """Ensures that we correctly generate current-full.csv""" expected_file_content = [ @@ -116,7 +118,7 @@ class CsvReportsTest(TestCase): content = fake_open() # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) - + def test_not_found_full_report(self): """Ensures that we get a not found when the report doesn't exist""" response = self.client.get("/api/v1/get-report/current-full") @@ -134,7 +136,8 @@ class CsvReportsTest(TestCase): self.assertEqual(response.status_code, 404) # Check that the response body contains "File not found" self.assertEqual(response.content.decode(), "File not found") - + + @boto3_mocking.patching def test_load_federal_report(self): """Tests the current-federal api link""" request = self.factory.get("/fake-path") @@ -152,6 +155,7 @@ class CsvReportsTest(TestCase): self.assertEqual(file_content, expected_file_content) + @boto3_mocking.patching def test_load_full_report(self): """Tests the current-federal api link""" request = self.factory.get("/fake-path") From d159ac09bf8f2ba2a10fafb3e08f69f8d94ce654 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:17:30 -0700 Subject: [PATCH 145/245] Fix typo --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index bcec795d2..558b9e0b5 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -72,7 +72,7 @@ jobs: cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} - cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" + cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" - name: Generate current-full.csv uses: cloud-gov/cg-cli-tools@main From e21b8b6e7149ae95cc719ced073866e8e0bca2d2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 13:28:29 -0700 Subject: [PATCH 146/245] Change environment default --- .github/workflows/daily-csv-upload.yaml | 2 +- src/registrar/config/settings.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 558b9e0b5..27680f561 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -40,7 +40,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'ZA'; core.setOutput('environment', environment); wait-for-deploy: diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 530de3af3..d23326553 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -38,7 +38,7 @@ if key_service and key_service.credentials: else: secret = env -# Get secrets from Cloud.gov user provided s3 service, if exists +# Get secrets from Cloud.gov user provided s3 service, if it exists # If not, get secrets from environment variables. s3_key_service = AppEnv().get_service(name="getgov-s3") if s3_key_service and s3_key_service.credentials: From 159118d005a8d321b270f96616103b16d3ebda82 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Wed, 29 Nov 2023 14:21:33 -0700 Subject: [PATCH 147/245] Change how creds are handled --- .github/workflows/daily-csv-upload.yaml | 2 +- src/registrar/config/settings.py | 25 ++++++++++++++----------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 27680f561..558b9e0b5 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -40,7 +40,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'ZA'; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; core.setOutput('environment', environment); wait-for-deploy: diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index d23326553..9c4762e80 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -33,18 +33,20 @@ env = environs.Env() # Get secrets from Cloud.gov user provided service, if exists # If not, get secrets from environment variables key_service = AppEnv().get_service(name="getgov-credentials") + + +# Get secrets from Cloud.gov user provided s3 service, if it exists +s3_key_service = AppEnv().get_service(name="getgov-s3") + if key_service and key_service.credentials: + if s3_key_service and s3_key_service.credentials: + # Concatenate the credentials from our S3 service into our secret service + key_service.credentials.update(s3_key_service.credentials) secret = key_service.credentials.get else: secret = env -# Get secrets from Cloud.gov user provided s3 service, if it exists -# If not, get secrets from environment variables. -s3_key_service = AppEnv().get_service(name="getgov-s3") -if s3_key_service and s3_key_service.credentials: - secret_s3 = s3_key_service.credentials.get -else: - secret_s3 = env + # # # ### # Values obtained externally # # # # ### @@ -65,10 +67,11 @@ secret_key = secret("DJANGO_SECRET_KEY") secret_aws_ses_key_id = secret("AWS_ACCESS_KEY_ID", None) secret_aws_ses_key = secret("AWS_SECRET_ACCESS_KEY", None) -aws_s3_region_name = secret_s3("region", None) -secret_aws_s3_key_id = secret_s3("access_key_id", None) -secret_aws_s3_key = secret_s3("secret_access_key", None) -secret_aws_s3_bucket_name = secret_s3("bucket", None) +# TODO - allow for local env variable +aws_s3_region_name = secret("region", None) +secret_aws_s3_key_id = secret("access_key_id", None) +secret_aws_s3_key = secret("secret_access_key", None) +secret_aws_s3_bucket_name = secret("bucket", None) secret_registry_cl_id = secret("REGISTRY_CL_ID") secret_registry_password = secret("REGISTRY_PASSWORD") From dd673a2f58a9ec820963cde82003c82e73edc8ce Mon Sep 17 00:00:00 2001 From: CocoByte Date: Wed, 29 Nov 2023 16:01:58 -0700 Subject: [PATCH 148/245] Fed agency and state are now dropdowns --- ...mainapplication_federal_agency_and_more.py | 771 ++++++++++++++++++ src/registrar/models/domain_application.py | 2 + src/registrar/models/domain_information.py | 2 + 3 files changed, 775 insertions(+) create mode 100644 src/registrar/migrations/0048_alter_domainapplication_federal_agency_and_more.py diff --git a/src/registrar/migrations/0048_alter_domainapplication_federal_agency_and_more.py b/src/registrar/migrations/0048_alter_domainapplication_federal_agency_and_more.py new file mode 100644 index 000000000..e00d67cb5 --- /dev/null +++ b/src/registrar/migrations/0048_alter_domainapplication_federal_agency_and_more.py @@ -0,0 +1,771 @@ +# Generated by Django 4.2.7 on 2023-11-29 22:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0047_transitiondomain_address_line_transitiondomain_city_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="federal_agency", + field=models.TextField( + blank=True, + choices=[ + ( + "Administrative Conference of the United States", + "Administrative Conference of the United States", + ), + ("Advisory Council on Historic Preservation", "Advisory Council on Historic Preservation"), + ("American Battle Monuments Commission", "American Battle Monuments Commission"), + ("AMTRAK", "AMTRAK"), + ("Appalachian Regional Commission", "Appalachian Regional Commission"), + ( + "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", + "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", + ), + ("Appraisal Subcommittee", "Appraisal Subcommittee"), + ("Architect of the Capitol", "Architect of the Capitol"), + ("Armed Forces Retirement Home", "Armed Forces Retirement Home"), + ( + "Barry Goldwater Scholarship and Excellence in Education Foundation", + "Barry Goldwater Scholarship and Excellence in Education Foundation", + ), + ( + "Barry Goldwater Scholarship and Excellence in Education Program", + "Barry Goldwater Scholarship and Excellence in Education Program", + ), + ("Central Intelligence Agency", "Central Intelligence Agency"), + ("Chemical Safety Board", "Chemical Safety Board"), + ("Christopher Columbus Fellowship Foundation", "Christopher Columbus Fellowship Foundation"), + ("Civil Rights Cold Case Records Review Board", "Civil Rights Cold Case Records Review Board"), + ( + "Commission for the Preservation of America's Heritage Abroad", + "Commission for the Preservation of America's Heritage Abroad", + ), + ("Commission of Fine Arts", "Commission of Fine Arts"), + ( + "Committee for Purchase From People Who Are Blind or Severely Disabled", + "Committee for Purchase From People Who Are Blind or Severely Disabled", + ), + ("Commodity Futures Trading Commission", "Commodity Futures Trading Commission"), + ("Congressional Budget Office", "Congressional Budget Office"), + ("Consumer Financial Protection Bureau", "Consumer Financial Protection Bureau"), + ("Consumer Product Safety Commission", "Consumer Product Safety Commission"), + ("Corporation for National & Community Service", "Corporation for National & Community Service"), + ( + "Corporation for National and Community Service", + "Corporation for National and Community Service", + ), + ( + "Council of Inspectors General on Integrity and Efficiency", + "Council of Inspectors General on Integrity and Efficiency", + ), + ("Court Services and Offender Supervision", "Court Services and Offender Supervision"), + ("Cyberspace Solarium Commission", "Cyberspace Solarium Commission"), + ( + "DC Court Services and Offender Supervision Agency", + "DC Court Services and Offender Supervision Agency", + ), + ("DC Pre-trial Services", "DC Pre-trial Services"), + ("Defense Nuclear Facilities Safety Board", "Defense Nuclear Facilities Safety Board"), + ("Delta Regional Authority", "Delta Regional Authority"), + ("Denali Commission", "Denali Commission"), + ("Department of Agriculture", "Department of Agriculture"), + ("Department of Commerce", "Department of Commerce"), + ("Department of Defense", "Department of Defense"), + ("Department of Education", "Department of Education"), + ("Department of Energy", "Department of Energy"), + ("Department of Health and Human Services", "Department of Health and Human Services"), + ("Department of Homeland Security", "Department of Homeland Security"), + ("Department of Housing and Urban Development", "Department of Housing and Urban Development"), + ("Department of Justice", "Department of Justice"), + ("Department of Labor", "Department of Labor"), + ("Department of State", "Department of State"), + ("Department of the Interior", "Department of the Interior"), + ("Department of the Treasury", "Department of the Treasury"), + ("Department of Transportation", "Department of Transportation"), + ("Department of Veterans Affairs", "Department of Veterans Affairs"), + ("Director of National Intelligence", "Director of National Intelligence"), + ("Dwight D. Eisenhower Memorial Commission", "Dwight D. Eisenhower Memorial Commission"), + ("Election Assistance Commission", "Election Assistance Commission"), + ("Environmental Protection Agency", "Environmental Protection Agency"), + ("Equal Employment Opportunity Commission", "Equal Employment Opportunity Commission"), + ("Executive Office of the President", "Executive Office of the President"), + ("Export-Import Bank of the United States", "Export-Import Bank of the United States"), + ("Export/Import Bank of the U.S.", "Export/Import Bank of the U.S."), + ("Farm Credit Administration", "Farm Credit Administration"), + ("Farm Credit System Insurance Corporation", "Farm Credit System Insurance Corporation"), + ("Federal Communications Commission", "Federal Communications Commission"), + ("Federal Deposit Insurance Corporation", "Federal Deposit Insurance Corporation"), + ("Federal Election Commission", "Federal Election Commission"), + ("Federal Energy Regulatory Commission", "Federal Energy Regulatory Commission"), + ( + "Federal Financial Institutions Examination Council", + "Federal Financial Institutions Examination Council", + ), + ("Federal Housing Finance Agency", "Federal Housing Finance Agency"), + ("Federal Judiciary", "Federal Judiciary"), + ("Federal Labor Relations Authority", "Federal Labor Relations Authority"), + ("Federal Maritime Commission", "Federal Maritime Commission"), + ("Federal Mediation and Conciliation Service", "Federal Mediation and Conciliation Service"), + ( + "Federal Mine Safety and Health Review Commission", + "Federal Mine Safety and Health Review Commission", + ), + ( + "Federal Permitting Improvement Steering Council", + "Federal Permitting Improvement Steering Council", + ), + ("Federal Reserve Board of Governors", "Federal Reserve Board of Governors"), + ("Federal Reserve System", "Federal Reserve System"), + ("Federal Trade Commission", "Federal Trade Commission"), + ("General Services Administration", "General Services Administration"), + ("gov Administration", "gov Administration"), + ("Government Accountability Office", "Government Accountability Office"), + ("Government Publishing Office", "Government Publishing Office"), + ("Gulf Coast Ecosystem Restoration Council", "Gulf Coast Ecosystem Restoration Council"), + ("Harry S Truman Scholarship Foundation", "Harry S Truman Scholarship Foundation"), + ("Harry S. Truman Scholarship Foundation", "Harry S. Truman Scholarship Foundation"), + ("Institute of Museum and Library Services", "Institute of Museum and Library Services"), + ("Institute of Peace", "Institute of Peace"), + ("Inter-American Foundation", "Inter-American Foundation"), + ( + "International Boundary and Water Commission: United States and Mexico", + "International Boundary and Water Commission: United States and Mexico", + ), + ( + "International Boundary Commission: United States and Canada", + "International Boundary Commission: United States and Canada", + ), + ( + "International Joint Commission: United States and Canada", + "International Joint Commission: United States and Canada", + ), + ("James Madison Memorial Fellowship Foundation", "James Madison Memorial Fellowship Foundation"), + ("Japan-United States Friendship Commission", "Japan-United States Friendship Commission"), + ("Japan-US Friendship Commission", "Japan-US Friendship Commission"), + ("John F. Kennedy Center for Performing Arts", "John F. Kennedy Center for Performing Arts"), + ( + "John F. Kennedy Center for the Performing Arts", + "John F. Kennedy Center for the Performing Arts", + ), + ("Legal Services Corporation", "Legal Services Corporation"), + ("Legislative Branch", "Legislative Branch"), + ("Library of Congress", "Library of Congress"), + ("Marine Mammal Commission", "Marine Mammal Commission"), + ( + "Medicaid and CHIP Payment and Access Commission", + "Medicaid and CHIP Payment and Access Commission", + ), + ("Medical Payment Advisory Commission", "Medical Payment Advisory Commission"), + ("Medicare Payment Advisory Commission", "Medicare Payment Advisory Commission"), + ("Merit Systems Protection Board", "Merit Systems Protection Board"), + ("Millennium Challenge Corporation", "Millennium Challenge Corporation"), + ( + "Morris K. Udall and Stewart L. Udall Foundation", + "Morris K. Udall and Stewart L. Udall Foundation", + ), + ("National Aeronautics and Space Administration", "National Aeronautics and Space Administration"), + ("National Archives and Records Administration", "National Archives and Records Administration"), + ("National Capital Planning Commission", "National Capital Planning Commission"), + ("National Council on Disability", "National Council on Disability"), + ("National Credit Union Administration", "National Credit Union Administration"), + ("National Endowment for the Arts", "National Endowment for the Arts"), + ("National Endowment for the Humanities", "National Endowment for the Humanities"), + ( + "National Foundation on the Arts and the Humanities", + "National Foundation on the Arts and the Humanities", + ), + ("National Gallery of Art", "National Gallery of Art"), + ("National Indian Gaming Commission", "National Indian Gaming Commission"), + ("National Labor Relations Board", "National Labor Relations Board"), + ("National Mediation Board", "National Mediation Board"), + ("National Science Foundation", "National Science Foundation"), + ( + "National Security Commission on Artificial Intelligence", + "National Security Commission on Artificial Intelligence", + ), + ("National Transportation Safety Board", "National Transportation Safety Board"), + ( + "Networking Information Technology Research and Development", + "Networking Information Technology Research and Development", + ), + ("Non-Federal Agency", "Non-Federal Agency"), + ("Northern Border Regional Commission", "Northern Border Regional Commission"), + ("Nuclear Regulatory Commission", "Nuclear Regulatory Commission"), + ("Nuclear Safety Oversight Committee", "Nuclear Safety Oversight Committee"), + ("Nuclear Waste Technical Review Board", "Nuclear Waste Technical Review Board"), + ( + "Occupational Safety & Health Review Commission", + "Occupational Safety & Health Review Commission", + ), + ( + "Occupational Safety and Health Review Commission", + "Occupational Safety and Health Review Commission", + ), + ("Office of Compliance", "Office of Compliance"), + ("Office of Congressional Workplace Rights", "Office of Congressional Workplace Rights"), + ("Office of Government Ethics", "Office of Government Ethics"), + ("Office of Navajo and Hopi Indian Relocation", "Office of Navajo and Hopi Indian Relocation"), + ("Office of Personnel Management", "Office of Personnel Management"), + ("Open World Leadership Center", "Open World Leadership Center"), + ("Overseas Private Investment Corporation", "Overseas Private Investment Corporation"), + ("Peace Corps", "Peace Corps"), + ("Pension Benefit Guaranty Corporation", "Pension Benefit Guaranty Corporation"), + ("Postal Regulatory Commission", "Postal Regulatory Commission"), + ("Presidio Trust", "Presidio Trust"), + ("Privacy and Civil Liberties Oversight Board", "Privacy and Civil Liberties Oversight Board"), + ("Public Buildings Reform Board", "Public Buildings Reform Board"), + ( + "Public Defender Service for the District of Columbia", + "Public Defender Service for the District of Columbia", + ), + ("Railroad Retirement Board", "Railroad Retirement Board"), + ("Securities and Exchange Commission", "Securities and Exchange Commission"), + ("Selective Service System", "Selective Service System"), + ("Small Business Administration", "Small Business Administration"), + ("Smithsonian Institution", "Smithsonian Institution"), + ("Social Security Administration", "Social Security Administration"), + ("Social Security Advisory Board", "Social Security Advisory Board"), + ("Southeast Crescent Regional Commission", "Southeast Crescent Regional Commission"), + ("Southwest Border Regional Commission", "Southwest Border Regional Commission"), + ("State Justice Institute", "State Justice Institute"), + ("State, Local, and Tribal Government", "State, Local, and Tribal Government"), + ("Stennis Center for Public Service", "Stennis Center for Public Service"), + ("Surface Transportation Board", "Surface Transportation Board"), + ("Tennessee Valley Authority", "Tennessee Valley Authority"), + ("The Executive Office of the President", "The Executive Office of the President"), + ("The Intelligence Community", "The Intelligence Community"), + ("The Legislative Branch", "The Legislative Branch"), + ("The Supreme Court", "The Supreme Court"), + ( + "The United States World War One Centennial Commission", + "The United States World War One Centennial Commission", + ), + ("U.S. Access Board", "U.S. Access Board"), + ("U.S. Agency for Global Media", "U.S. Agency for Global Media"), + ("U.S. Agency for International Development", "U.S. Agency for International Development"), + ("U.S. Capitol Police", "U.S. Capitol Police"), + ("U.S. Chemical Safety Board", "U.S. Chemical Safety Board"), + ( + "U.S. China Economic and Security Review Commission", + "U.S. China Economic and Security Review Commission", + ), + ( + "U.S. Commission for the Preservation of Americas Heritage Abroad", + "U.S. Commission for the Preservation of Americas Heritage Abroad", + ), + ("U.S. Commission of Fine Arts", "U.S. Commission of Fine Arts"), + ("U.S. Commission on Civil Rights", "U.S. Commission on Civil Rights"), + ( + "U.S. Commission on International Religious Freedom", + "U.S. Commission on International Religious Freedom", + ), + ("U.S. Courts", "U.S. Courts"), + ("U.S. Department of Agriculture", "U.S. Department of Agriculture"), + ("U.S. Interagency Council on Homelessness", "U.S. Interagency Council on Homelessness"), + ("U.S. International Trade Commission", "U.S. International Trade Commission"), + ("U.S. Nuclear Waste Technical Review Board", "U.S. Nuclear Waste Technical Review Board"), + ("U.S. Office of Special Counsel", "U.S. Office of Special Counsel"), + ("U.S. Peace Corps", "U.S. Peace Corps"), + ("U.S. Postal Service", "U.S. Postal Service"), + ("U.S. Semiquincentennial Commission", "U.S. Semiquincentennial Commission"), + ("U.S. Trade and Development Agency", "U.S. Trade and Development Agency"), + ( + "U.S.-China Economic and Security Review Commission", + "U.S.-China Economic and Security Review Commission", + ), + ("Udall Foundation", "Udall Foundation"), + ("United States AbilityOne", "United States AbilityOne"), + ("United States Access Board", "United States Access Board"), + ("United States African Development Foundation", "United States African Development Foundation"), + ("United States Agency for Global Media", "United States Agency for Global Media"), + ("United States Arctic Research Commission", "United States Arctic Research Commission"), + ("United States Global Change Research Program", "United States Global Change Research Program"), + ("United States Holocaust Memorial Museum", "United States Holocaust Memorial Museum"), + ("United States Institute of Peace", "United States Institute of Peace"), + ( + "United States Interagency Council on Homelessness", + "United States Interagency Council on Homelessness", + ), + ( + "United States International Development Finance Corporation", + "United States International Development Finance Corporation", + ), + ("United States International Trade Commission", "United States International Trade Commission"), + ("United States Postal Service", "United States Postal Service"), + ("United States Senate", "United States Senate"), + ("United States Trade and Development Agency", "United States Trade and Development Agency"), + ( + "Utah Reclamation Mitigation and Conservation Commission", + "Utah Reclamation Mitigation and Conservation Commission", + ), + ("Vietnam Education Foundation", "Vietnam Education Foundation"), + ("Western Hemisphere Drug Policy Commission", "Western Hemisphere Drug Policy Commission"), + ( + "Woodrow Wilson International Center for Scholars", + "Woodrow Wilson International Center for Scholars", + ), + ("World War I Centennial Commission", "World War I Centennial Commission"), + ], + help_text="Federal agency", + null=True, + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="state_territory", + field=models.CharField( + blank=True, + choices=[ + ("AL", "Alabama (AL)"), + ("AK", "Alaska (AK)"), + ("AS", "American Samoa (AS)"), + ("AZ", "Arizona (AZ)"), + ("AR", "Arkansas (AR)"), + ("CA", "California (CA)"), + ("CO", "Colorado (CO)"), + ("CT", "Connecticut (CT)"), + ("DE", "Delaware (DE)"), + ("DC", "District of Columbia (DC)"), + ("FL", "Florida (FL)"), + ("GA", "Georgia (GA)"), + ("GU", "Guam (GU)"), + ("HI", "Hawaii (HI)"), + ("ID", "Idaho (ID)"), + ("IL", "Illinois (IL)"), + ("IN", "Indiana (IN)"), + ("IA", "Iowa (IA)"), + ("KS", "Kansas (KS)"), + ("KY", "Kentucky (KY)"), + ("LA", "Louisiana (LA)"), + ("ME", "Maine (ME)"), + ("MD", "Maryland (MD)"), + ("MA", "Massachusetts (MA)"), + ("MI", "Michigan (MI)"), + ("MN", "Minnesota (MN)"), + ("MS", "Mississippi (MS)"), + ("MO", "Missouri (MO)"), + ("MT", "Montana (MT)"), + ("NE", "Nebraska (NE)"), + ("NV", "Nevada (NV)"), + ("NH", "New Hampshire (NH)"), + ("NJ", "New Jersey (NJ)"), + ("NM", "New Mexico (NM)"), + ("NY", "New York (NY)"), + ("NC", "North Carolina (NC)"), + ("ND", "North Dakota (ND)"), + ("MP", "Northern Mariana Islands (MP)"), + ("OH", "Ohio (OH)"), + ("OK", "Oklahoma (OK)"), + ("OR", "Oregon (OR)"), + ("PA", "Pennsylvania (PA)"), + ("PR", "Puerto Rico (PR)"), + ("RI", "Rhode Island (RI)"), + ("SC", "South Carolina (SC)"), + ("SD", "South Dakota (SD)"), + ("TN", "Tennessee (TN)"), + ("TX", "Texas (TX)"), + ("UM", "United States Minor Outlying Islands (UM)"), + ("UT", "Utah (UT)"), + ("VT", "Vermont (VT)"), + ("VI", "Virgin Islands (VI)"), + ("VA", "Virginia (VA)"), + ("WA", "Washington (WA)"), + ("WV", "West Virginia (WV)"), + ("WI", "Wisconsin (WI)"), + ("WY", "Wyoming (WY)"), + ("AA", "Armed Forces Americas (AA)"), + ("AE", "Armed Forces Africa, Canada, Europe, Middle East (AE)"), + ("AP", "Armed Forces Pacific (AP)"), + ], + help_text="State, territory, or military post", + max_length=2, + null=True, + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="federal_agency", + field=models.TextField( + blank=True, + choices=[ + ( + "Administrative Conference of the United States", + "Administrative Conference of the United States", + ), + ("Advisory Council on Historic Preservation", "Advisory Council on Historic Preservation"), + ("American Battle Monuments Commission", "American Battle Monuments Commission"), + ("AMTRAK", "AMTRAK"), + ("Appalachian Regional Commission", "Appalachian Regional Commission"), + ( + "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", + "Appraisal Subcommittee of the Federal Financial Institutions Examination Council", + ), + ("Appraisal Subcommittee", "Appraisal Subcommittee"), + ("Architect of the Capitol", "Architect of the Capitol"), + ("Armed Forces Retirement Home", "Armed Forces Retirement Home"), + ( + "Barry Goldwater Scholarship and Excellence in Education Foundation", + "Barry Goldwater Scholarship and Excellence in Education Foundation", + ), + ( + "Barry Goldwater Scholarship and Excellence in Education Program", + "Barry Goldwater Scholarship and Excellence in Education Program", + ), + ("Central Intelligence Agency", "Central Intelligence Agency"), + ("Chemical Safety Board", "Chemical Safety Board"), + ("Christopher Columbus Fellowship Foundation", "Christopher Columbus Fellowship Foundation"), + ("Civil Rights Cold Case Records Review Board", "Civil Rights Cold Case Records Review Board"), + ( + "Commission for the Preservation of America's Heritage Abroad", + "Commission for the Preservation of America's Heritage Abroad", + ), + ("Commission of Fine Arts", "Commission of Fine Arts"), + ( + "Committee for Purchase From People Who Are Blind or Severely Disabled", + "Committee for Purchase From People Who Are Blind or Severely Disabled", + ), + ("Commodity Futures Trading Commission", "Commodity Futures Trading Commission"), + ("Congressional Budget Office", "Congressional Budget Office"), + ("Consumer Financial Protection Bureau", "Consumer Financial Protection Bureau"), + ("Consumer Product Safety Commission", "Consumer Product Safety Commission"), + ("Corporation for National & Community Service", "Corporation for National & Community Service"), + ( + "Corporation for National and Community Service", + "Corporation for National and Community Service", + ), + ( + "Council of Inspectors General on Integrity and Efficiency", + "Council of Inspectors General on Integrity and Efficiency", + ), + ("Court Services and Offender Supervision", "Court Services and Offender Supervision"), + ("Cyberspace Solarium Commission", "Cyberspace Solarium Commission"), + ( + "DC Court Services and Offender Supervision Agency", + "DC Court Services and Offender Supervision Agency", + ), + ("DC Pre-trial Services", "DC Pre-trial Services"), + ("Defense Nuclear Facilities Safety Board", "Defense Nuclear Facilities Safety Board"), + ("Delta Regional Authority", "Delta Regional Authority"), + ("Denali Commission", "Denali Commission"), + ("Department of Agriculture", "Department of Agriculture"), + ("Department of Commerce", "Department of Commerce"), + ("Department of Defense", "Department of Defense"), + ("Department of Education", "Department of Education"), + ("Department of Energy", "Department of Energy"), + ("Department of Health and Human Services", "Department of Health and Human Services"), + ("Department of Homeland Security", "Department of Homeland Security"), + ("Department of Housing and Urban Development", "Department of Housing and Urban Development"), + ("Department of Justice", "Department of Justice"), + ("Department of Labor", "Department of Labor"), + ("Department of State", "Department of State"), + ("Department of the Interior", "Department of the Interior"), + ("Department of the Treasury", "Department of the Treasury"), + ("Department of Transportation", "Department of Transportation"), + ("Department of Veterans Affairs", "Department of Veterans Affairs"), + ("Director of National Intelligence", "Director of National Intelligence"), + ("Dwight D. Eisenhower Memorial Commission", "Dwight D. Eisenhower Memorial Commission"), + ("Election Assistance Commission", "Election Assistance Commission"), + ("Environmental Protection Agency", "Environmental Protection Agency"), + ("Equal Employment Opportunity Commission", "Equal Employment Opportunity Commission"), + ("Executive Office of the President", "Executive Office of the President"), + ("Export-Import Bank of the United States", "Export-Import Bank of the United States"), + ("Export/Import Bank of the U.S.", "Export/Import Bank of the U.S."), + ("Farm Credit Administration", "Farm Credit Administration"), + ("Farm Credit System Insurance Corporation", "Farm Credit System Insurance Corporation"), + ("Federal Communications Commission", "Federal Communications Commission"), + ("Federal Deposit Insurance Corporation", "Federal Deposit Insurance Corporation"), + ("Federal Election Commission", "Federal Election Commission"), + ("Federal Energy Regulatory Commission", "Federal Energy Regulatory Commission"), + ( + "Federal Financial Institutions Examination Council", + "Federal Financial Institutions Examination Council", + ), + ("Federal Housing Finance Agency", "Federal Housing Finance Agency"), + ("Federal Judiciary", "Federal Judiciary"), + ("Federal Labor Relations Authority", "Federal Labor Relations Authority"), + ("Federal Maritime Commission", "Federal Maritime Commission"), + ("Federal Mediation and Conciliation Service", "Federal Mediation and Conciliation Service"), + ( + "Federal Mine Safety and Health Review Commission", + "Federal Mine Safety and Health Review Commission", + ), + ( + "Federal Permitting Improvement Steering Council", + "Federal Permitting Improvement Steering Council", + ), + ("Federal Reserve Board of Governors", "Federal Reserve Board of Governors"), + ("Federal Reserve System", "Federal Reserve System"), + ("Federal Trade Commission", "Federal Trade Commission"), + ("General Services Administration", "General Services Administration"), + ("gov Administration", "gov Administration"), + ("Government Accountability Office", "Government Accountability Office"), + ("Government Publishing Office", "Government Publishing Office"), + ("Gulf Coast Ecosystem Restoration Council", "Gulf Coast Ecosystem Restoration Council"), + ("Harry S Truman Scholarship Foundation", "Harry S Truman Scholarship Foundation"), + ("Harry S. Truman Scholarship Foundation", "Harry S. Truman Scholarship Foundation"), + ("Institute of Museum and Library Services", "Institute of Museum and Library Services"), + ("Institute of Peace", "Institute of Peace"), + ("Inter-American Foundation", "Inter-American Foundation"), + ( + "International Boundary and Water Commission: United States and Mexico", + "International Boundary and Water Commission: United States and Mexico", + ), + ( + "International Boundary Commission: United States and Canada", + "International Boundary Commission: United States and Canada", + ), + ( + "International Joint Commission: United States and Canada", + "International Joint Commission: United States and Canada", + ), + ("James Madison Memorial Fellowship Foundation", "James Madison Memorial Fellowship Foundation"), + ("Japan-United States Friendship Commission", "Japan-United States Friendship Commission"), + ("Japan-US Friendship Commission", "Japan-US Friendship Commission"), + ("John F. Kennedy Center for Performing Arts", "John F. Kennedy Center for Performing Arts"), + ( + "John F. Kennedy Center for the Performing Arts", + "John F. Kennedy Center for the Performing Arts", + ), + ("Legal Services Corporation", "Legal Services Corporation"), + ("Legislative Branch", "Legislative Branch"), + ("Library of Congress", "Library of Congress"), + ("Marine Mammal Commission", "Marine Mammal Commission"), + ( + "Medicaid and CHIP Payment and Access Commission", + "Medicaid and CHIP Payment and Access Commission", + ), + ("Medical Payment Advisory Commission", "Medical Payment Advisory Commission"), + ("Medicare Payment Advisory Commission", "Medicare Payment Advisory Commission"), + ("Merit Systems Protection Board", "Merit Systems Protection Board"), + ("Millennium Challenge Corporation", "Millennium Challenge Corporation"), + ( + "Morris K. Udall and Stewart L. Udall Foundation", + "Morris K. Udall and Stewart L. Udall Foundation", + ), + ("National Aeronautics and Space Administration", "National Aeronautics and Space Administration"), + ("National Archives and Records Administration", "National Archives and Records Administration"), + ("National Capital Planning Commission", "National Capital Planning Commission"), + ("National Council on Disability", "National Council on Disability"), + ("National Credit Union Administration", "National Credit Union Administration"), + ("National Endowment for the Arts", "National Endowment for the Arts"), + ("National Endowment for the Humanities", "National Endowment for the Humanities"), + ( + "National Foundation on the Arts and the Humanities", + "National Foundation on the Arts and the Humanities", + ), + ("National Gallery of Art", "National Gallery of Art"), + ("National Indian Gaming Commission", "National Indian Gaming Commission"), + ("National Labor Relations Board", "National Labor Relations Board"), + ("National Mediation Board", "National Mediation Board"), + ("National Science Foundation", "National Science Foundation"), + ( + "National Security Commission on Artificial Intelligence", + "National Security Commission on Artificial Intelligence", + ), + ("National Transportation Safety Board", "National Transportation Safety Board"), + ( + "Networking Information Technology Research and Development", + "Networking Information Technology Research and Development", + ), + ("Non-Federal Agency", "Non-Federal Agency"), + ("Northern Border Regional Commission", "Northern Border Regional Commission"), + ("Nuclear Regulatory Commission", "Nuclear Regulatory Commission"), + ("Nuclear Safety Oversight Committee", "Nuclear Safety Oversight Committee"), + ("Nuclear Waste Technical Review Board", "Nuclear Waste Technical Review Board"), + ( + "Occupational Safety & Health Review Commission", + "Occupational Safety & Health Review Commission", + ), + ( + "Occupational Safety and Health Review Commission", + "Occupational Safety and Health Review Commission", + ), + ("Office of Compliance", "Office of Compliance"), + ("Office of Congressional Workplace Rights", "Office of Congressional Workplace Rights"), + ("Office of Government Ethics", "Office of Government Ethics"), + ("Office of Navajo and Hopi Indian Relocation", "Office of Navajo and Hopi Indian Relocation"), + ("Office of Personnel Management", "Office of Personnel Management"), + ("Open World Leadership Center", "Open World Leadership Center"), + ("Overseas Private Investment Corporation", "Overseas Private Investment Corporation"), + ("Peace Corps", "Peace Corps"), + ("Pension Benefit Guaranty Corporation", "Pension Benefit Guaranty Corporation"), + ("Postal Regulatory Commission", "Postal Regulatory Commission"), + ("Presidio Trust", "Presidio Trust"), + ("Privacy and Civil Liberties Oversight Board", "Privacy and Civil Liberties Oversight Board"), + ("Public Buildings Reform Board", "Public Buildings Reform Board"), + ( + "Public Defender Service for the District of Columbia", + "Public Defender Service for the District of Columbia", + ), + ("Railroad Retirement Board", "Railroad Retirement Board"), + ("Securities and Exchange Commission", "Securities and Exchange Commission"), + ("Selective Service System", "Selective Service System"), + ("Small Business Administration", "Small Business Administration"), + ("Smithsonian Institution", "Smithsonian Institution"), + ("Social Security Administration", "Social Security Administration"), + ("Social Security Advisory Board", "Social Security Advisory Board"), + ("Southeast Crescent Regional Commission", "Southeast Crescent Regional Commission"), + ("Southwest Border Regional Commission", "Southwest Border Regional Commission"), + ("State Justice Institute", "State Justice Institute"), + ("State, Local, and Tribal Government", "State, Local, and Tribal Government"), + ("Stennis Center for Public Service", "Stennis Center for Public Service"), + ("Surface Transportation Board", "Surface Transportation Board"), + ("Tennessee Valley Authority", "Tennessee Valley Authority"), + ("The Executive Office of the President", "The Executive Office of the President"), + ("The Intelligence Community", "The Intelligence Community"), + ("The Legislative Branch", "The Legislative Branch"), + ("The Supreme Court", "The Supreme Court"), + ( + "The United States World War One Centennial Commission", + "The United States World War One Centennial Commission", + ), + ("U.S. Access Board", "U.S. Access Board"), + ("U.S. Agency for Global Media", "U.S. Agency for Global Media"), + ("U.S. Agency for International Development", "U.S. Agency for International Development"), + ("U.S. Capitol Police", "U.S. Capitol Police"), + ("U.S. Chemical Safety Board", "U.S. Chemical Safety Board"), + ( + "U.S. China Economic and Security Review Commission", + "U.S. China Economic and Security Review Commission", + ), + ( + "U.S. Commission for the Preservation of Americas Heritage Abroad", + "U.S. Commission for the Preservation of Americas Heritage Abroad", + ), + ("U.S. Commission of Fine Arts", "U.S. Commission of Fine Arts"), + ("U.S. Commission on Civil Rights", "U.S. Commission on Civil Rights"), + ( + "U.S. Commission on International Religious Freedom", + "U.S. Commission on International Religious Freedom", + ), + ("U.S. Courts", "U.S. Courts"), + ("U.S. Department of Agriculture", "U.S. Department of Agriculture"), + ("U.S. Interagency Council on Homelessness", "U.S. Interagency Council on Homelessness"), + ("U.S. International Trade Commission", "U.S. International Trade Commission"), + ("U.S. Nuclear Waste Technical Review Board", "U.S. Nuclear Waste Technical Review Board"), + ("U.S. Office of Special Counsel", "U.S. Office of Special Counsel"), + ("U.S. Peace Corps", "U.S. Peace Corps"), + ("U.S. Postal Service", "U.S. Postal Service"), + ("U.S. Semiquincentennial Commission", "U.S. Semiquincentennial Commission"), + ("U.S. Trade and Development Agency", "U.S. Trade and Development Agency"), + ( + "U.S.-China Economic and Security Review Commission", + "U.S.-China Economic and Security Review Commission", + ), + ("Udall Foundation", "Udall Foundation"), + ("United States AbilityOne", "United States AbilityOne"), + ("United States Access Board", "United States Access Board"), + ("United States African Development Foundation", "United States African Development Foundation"), + ("United States Agency for Global Media", "United States Agency for Global Media"), + ("United States Arctic Research Commission", "United States Arctic Research Commission"), + ("United States Global Change Research Program", "United States Global Change Research Program"), + ("United States Holocaust Memorial Museum", "United States Holocaust Memorial Museum"), + ("United States Institute of Peace", "United States Institute of Peace"), + ( + "United States Interagency Council on Homelessness", + "United States Interagency Council on Homelessness", + ), + ( + "United States International Development Finance Corporation", + "United States International Development Finance Corporation", + ), + ("United States International Trade Commission", "United States International Trade Commission"), + ("United States Postal Service", "United States Postal Service"), + ("United States Senate", "United States Senate"), + ("United States Trade and Development Agency", "United States Trade and Development Agency"), + ( + "Utah Reclamation Mitigation and Conservation Commission", + "Utah Reclamation Mitigation and Conservation Commission", + ), + ("Vietnam Education Foundation", "Vietnam Education Foundation"), + ("Western Hemisphere Drug Policy Commission", "Western Hemisphere Drug Policy Commission"), + ( + "Woodrow Wilson International Center for Scholars", + "Woodrow Wilson International Center for Scholars", + ), + ("World War I Centennial Commission", "World War I Centennial Commission"), + ], + help_text="Federal agency", + null=True, + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="state_territory", + field=models.CharField( + blank=True, + choices=[ + ("AL", "Alabama (AL)"), + ("AK", "Alaska (AK)"), + ("AS", "American Samoa (AS)"), + ("AZ", "Arizona (AZ)"), + ("AR", "Arkansas (AR)"), + ("CA", "California (CA)"), + ("CO", "Colorado (CO)"), + ("CT", "Connecticut (CT)"), + ("DE", "Delaware (DE)"), + ("DC", "District of Columbia (DC)"), + ("FL", "Florida (FL)"), + ("GA", "Georgia (GA)"), + ("GU", "Guam (GU)"), + ("HI", "Hawaii (HI)"), + ("ID", "Idaho (ID)"), + ("IL", "Illinois (IL)"), + ("IN", "Indiana (IN)"), + ("IA", "Iowa (IA)"), + ("KS", "Kansas (KS)"), + ("KY", "Kentucky (KY)"), + ("LA", "Louisiana (LA)"), + ("ME", "Maine (ME)"), + ("MD", "Maryland (MD)"), + ("MA", "Massachusetts (MA)"), + ("MI", "Michigan (MI)"), + ("MN", "Minnesota (MN)"), + ("MS", "Mississippi (MS)"), + ("MO", "Missouri (MO)"), + ("MT", "Montana (MT)"), + ("NE", "Nebraska (NE)"), + ("NV", "Nevada (NV)"), + ("NH", "New Hampshire (NH)"), + ("NJ", "New Jersey (NJ)"), + ("NM", "New Mexico (NM)"), + ("NY", "New York (NY)"), + ("NC", "North Carolina (NC)"), + ("ND", "North Dakota (ND)"), + ("MP", "Northern Mariana Islands (MP)"), + ("OH", "Ohio (OH)"), + ("OK", "Oklahoma (OK)"), + ("OR", "Oregon (OR)"), + ("PA", "Pennsylvania (PA)"), + ("PR", "Puerto Rico (PR)"), + ("RI", "Rhode Island (RI)"), + ("SC", "South Carolina (SC)"), + ("SD", "South Dakota (SD)"), + ("TN", "Tennessee (TN)"), + ("TX", "Texas (TX)"), + ("UM", "United States Minor Outlying Islands (UM)"), + ("UT", "Utah (UT)"), + ("VT", "Vermont (VT)"), + ("VI", "Virgin Islands (VI)"), + ("VA", "Virginia (VA)"), + ("WA", "Washington (WA)"), + ("WV", "West Virginia (WV)"), + ("WI", "Wisconsin (WI)"), + ("WY", "Wyoming (WY)"), + ("AA", "Armed Forces Americas (AA)"), + ("AE", "Armed Forces Africa, Canada, Europe, Middle East (AE)"), + ("AP", "Armed Forces Pacific (AP)"), + ], + help_text="State, territory, or military post", + max_length=2, + null=True, + verbose_name="State, territory, or military post", + ), + ), + ] diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 86b8a0f7a..4a1945678 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -409,6 +409,7 @@ class DomainApplication(TimeStampedModel): ) federal_agency = models.TextField( + choices=AGENCY_CHOICES, null=True, blank=True, help_text="Federal agency", @@ -451,6 +452,7 @@ class DomainApplication(TimeStampedModel): ) state_territory = models.CharField( max_length=2, + choices=StateTerritoryChoices.choices, null=True, blank=True, help_text="State, territory, or military post", diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index d2bc5c53d..6eef94cf8 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -72,6 +72,7 @@ class DomainInformation(TimeStampedModel): ) federal_agency = models.TextField( + choices=AGENCY_CHOICES, null=True, blank=True, help_text="Federal agency", @@ -116,6 +117,7 @@ class DomainInformation(TimeStampedModel): ) state_territory = models.CharField( max_length=2, + choices=StateTerritoryChoices.choices, null=True, blank=True, help_text="State, territory, or military post", From f465e2e06b8403a42b297d9b407951b92956c247 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 17:53:11 -0800 Subject: [PATCH 149/245] remove (optional) from security email title and put it in label instead --- src/registrar/forms/domain.py | 2 +- src/registrar/templates/domain_security_email.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py index 0305dadd5..6ba48a0eb 100644 --- a/src/registrar/forms/domain.py +++ b/src/registrar/forms/domain.py @@ -223,7 +223,7 @@ class DomainSecurityEmailForm(forms.Form): """Form for adding or editing a security email to a domain.""" security_email = forms.EmailField( - label="Security email", + label="Security email (optional)", required=False, error_messages={ "invalid": str(SecurityEmailError(code=SecurityEmailErrorCodes.BAD_DATA)), diff --git a/src/registrar/templates/domain_security_email.html b/src/registrar/templates/domain_security_email.html index f52ef4549..4054186da 100644 --- a/src/registrar/templates/domain_security_email.html +++ b/src/registrar/templates/domain_security_email.html @@ -6,7 +6,7 @@ {% block domain_content %} {% include "includes/form_errors.html" with form=form %} -

Security email (optional)

+

Security email

We strongly recommend that you provide a security email. This email will allow the public to report observed or suspected security issues on your domain. Security emails are made public and included in the .gov domain data we provide.

From 63cbd1908d84fbb1b71e35fa56639f290c20a17f Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 18:42:04 -0800 Subject: [PATCH 150/245] Add Optionally to Current Sites page and remove asterisk from No Other Conacts page --- src/registrar/templates/application_current_sites.html | 2 +- src/registrar/templates/django/forms/label.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/application_current_sites.html b/src/registrar/templates/application_current_sites.html index 627727ae3..3cada9e0e 100644 --- a/src/registrar/templates/application_current_sites.html +++ b/src/registrar/templates/application_current_sites.html @@ -2,7 +2,7 @@ {% load static field_helpers %} {% block form_instructions %} -

Enter your organization’s current public website, if you have one. For example, +

Optionally, enter your organization’s current public website, if you have one. For example, www.city.com. We can better evaluate your domain request if we know about domains you’re already using. If you already have any .gov domains please include them.

{% endblock %} diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 3920bc66a..033296ab1 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want?" or field.label == "I read and agree to the requirements for operating .gov domains." %} + {% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want?" or field.label == "I read and agree to the requirements for operating .gov domains." or field.label == "Please explain why there are no other employees from your organization" %} {% else %} * {% endif %} From 44f8b0189d9a2e6b4aa249e6823ee13381278db1 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 20:06:02 -0800 Subject: [PATCH 151/245] add 'this question is optional' to current sites page and removing required fields sentence for no other contacts page --- src/registrar/templates/application_current_sites.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/application_current_sites.html b/src/registrar/templates/application_current_sites.html index 3cada9e0e..67343aee9 100644 --- a/src/registrar/templates/application_current_sites.html +++ b/src/registrar/templates/application_current_sites.html @@ -2,9 +2,9 @@ {% load static field_helpers %} {% block form_instructions %} -

Optionally, enter your organization’s current public website, if you have one. For example, +

Enter your organization’s current public website, if you have one. For example, www.city.com. We can better evaluate your domain request if we know about domains -you’re already using. If you already have any .gov domains please include them.

+you’re already using. If you already have any .gov domains please include them. This question is optional.

{% endblock %} {% block form_required_fields_help_text %} From f21ca59e0466ce6dbb750fa9a272374c379f6422 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 20:14:52 -0800 Subject: [PATCH 152/245] trying another way --- src/registrar/templates/application_form.html | 5 ++++- src/registrar/templates/django/forms/label.html | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/registrar/templates/application_form.html b/src/registrar/templates/application_form.html index 6830033b5..53f8d7a52 100644 --- a/src/registrar/templates/application_form.html +++ b/src/registrar/templates/application_form.html @@ -49,7 +49,10 @@ {% endblock %} {% block form_required_fields_help_text %} - {% include "includes/required_fields.html" %} + + {% if field.label != "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." %} + {% include "includes/required_fields.html" %} + {% endif %} {% endblock %}
diff --git a/src/registrar/templates/django/forms/label.html b/src/registrar/templates/django/forms/label.html index 033296ab1..18d24a7bd 100644 --- a/src/registrar/templates/django/forms/label.html +++ b/src/registrar/templates/django/forms/label.html @@ -10,7 +10,7 @@ {% if widget.attrs.required %} - {% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want?" or field.label == "I read and agree to the requirements for operating .gov domains." or field.label == "Please explain why there are no other employees from your organization" %} + {% if field.label == "Is your organization an election office?" or field.label == "What .gov domain do you want?" or field.label == "I read and agree to the requirements for operating .gov domains." or field.label == "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." %} {% else %} * {% endif %} From 6b4c6e9f376522ad1b06ce52550a8b55d69b225f Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Wed, 29 Nov 2023 20:30:15 -0800 Subject: [PATCH 153/245] trying another way of getting rid of required sentence for no other contacts page --- src/registrar/templates/application_form.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/templates/application_form.html b/src/registrar/templates/application_form.html index 53f8d7a52..744f4e5f2 100644 --- a/src/registrar/templates/application_form.html +++ b/src/registrar/templates/application_form.html @@ -48,12 +48,12 @@ {% block form_instructions %} {% endblock %} -{% block form_required_fields_help_text %} - {% if field.label != "Please explain why there are no other employees from your organization we can contact to help us assess your eligibility for a .gov domain." %} +{% if steps.current != "no_other_contacts" %} + {% block form_required_fields_help_text %} {% include "includes/required_fields.html" %} - {% endif %} -{% endblock %} + {% endblock %} +{% endif %} {% csrf_token %} From bb175bd3d460ed507f414c0c9a8be1e633e3c324 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 30 Nov 2023 09:27:27 -0700 Subject: [PATCH 154/245] Fix credentials not loading correctly --- src/docker-compose.yml | 5 +++++ src/registrar/config/settings.py | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/docker-compose.yml b/src/docker-compose.yml index 90ce1acb0..c9b78fd8e 100644 --- a/src/docker-compose.yml +++ b/src/docker-compose.yml @@ -51,6 +51,11 @@ services: # AWS credentials - AWS_ACCESS_KEY_ID - AWS_SECRET_ACCESS_KEY + # AWS S3 bucket credentials + - AWS_S3_ACCESS_KEY_ID + - AWS_S3_SECRET_ACCESS_KEY + - AWS_S3_REGION + - AWS_S3_BUCKET_NAME stdin_open: true tty: true ports: diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 9c4762e80..b31590c4b 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -67,11 +67,11 @@ secret_key = secret("DJANGO_SECRET_KEY") secret_aws_ses_key_id = secret("AWS_ACCESS_KEY_ID", None) secret_aws_ses_key = secret("AWS_SECRET_ACCESS_KEY", None) -# TODO - allow for local env variable -aws_s3_region_name = secret("region", None) -secret_aws_s3_key_id = secret("access_key_id", None) -secret_aws_s3_key = secret("secret_access_key", None) -secret_aws_s3_bucket_name = secret("bucket", None) +# These keys are present in a getgov-s3 instance, or they can be defined locally +aws_s3_region_name = secret("region", None) or secret("AWS_S3_REGION", None) +secret_aws_s3_key_id = secret("access_key_id", None) or secret("AWS_S3_ACCESS_KEY_ID", None) +secret_aws_s3_key = secret("secret_access_key", None) or secret("AWS_S3_SECRET_ACCESS_KEY", None) +secret_aws_s3_bucket_name = secret("bucket", None) or secret("AWS_S3_BUCKET_NAME", None) secret_registry_cl_id = secret("REGISTRY_CL_ID") secret_registry_password = secret("REGISTRY_PASSWORD") From 72ef5bb0b1783e80a909082c468def469930e308 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:13:06 -0700 Subject: [PATCH 155/245] Test --- .github/workflows/daily-csv-upload.yaml | 2 +- src/registrar/tests/test_reports.py | 15 ++++++++++++--- src/registrar/utility/s3_bucket.py | 11 ++--------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 558b9e0b5..245f19fcc 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -32,7 +32,7 @@ on: jobs: variables: outputs: - environment: ${{ steps.var.outputs.environment }} + environment: 'za' runs-on: "ubuntu-latest" steps: - name: Setting global variables diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index c0c520955..b3cbb72fd 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -7,7 +7,7 @@ from registrar.models.user import User from django.contrib.auth import get_user_model from registrar.utility.csv_export import export_domains_to_writer from django.core.management import call_command -from unittest.mock import call, mock_open, patch +from unittest.mock import MagicMock, call, mock_open, patch from api.views import get_current_federal, get_current_full import boto3_mocking # type: ignore @@ -73,7 +73,7 @@ class CsvReportsTest(TestCase): call_command("generate_current_federal_report") error = err.exception self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-federal.csv'") - + def test_create_failed_full(self): """Ensures that we return an error when we cannot find our created file""" fake_open = mock_open() @@ -119,15 +119,22 @@ class CsvReportsTest(TestCase): # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) + @boto3_mocking.patching def test_not_found_full_report(self): """Ensures that we get a not found when the report doesn't exist""" - response = self.client.get("/api/v1/get-report/current-full") + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + with boto3_mocking.clients.handler_for("s3", mock_client): + response = self.client.get("/api/v1/get-report/current-full") + call_args = mock_client_instance + args, kwargs = call_args # Check that the response has status code 404 self.assertEqual(response.status_code, 404) # Check that the response body contains "File not found" self.assertEqual(response.content.decode(), "File not found") + @boto3_mocking.patching def test_not_found_federal_report(self): """Ensures that we get a not found when the report doesn't exist""" response = self.client.get("/api/v1/get-report/current-federal") @@ -140,6 +147,8 @@ class CsvReportsTest(TestCase): @boto3_mocking.patching def test_load_federal_report(self): """Tests the current-federal api link""" + if not boto3_mocking.patching_engaged(): + raise Exception("test123") request = self.factory.get("/fake-path") response = get_current_federal(request, file_path="registrar/tests/data/fake_current_federal.csv") # Check that the response has status code 200 diff --git a/src/registrar/utility/s3_bucket.py b/src/registrar/utility/s3_bucket.py index 9e7f0da31..329a68c40 100644 --- a/src/registrar/utility/s3_bucket.py +++ b/src/registrar/utility/s3_bucket.py @@ -23,20 +23,12 @@ class S3ClientHelper: config=settings.BOTO_CONFIG, ) except Exception as exc: - raise S3ClientError("Could not access the S3 client.") from exc + raise S3ClientError("Could not access the S3 client") from exc def get_bucket_name(self): """Gets the name of our S3 Bucket""" return settings.AWS_S3_BUCKET_NAME - def list_objects(self): - """Returns a list of the top 1000 objects within our S3 instance""" - try: - response = self.boto_client.list_objects_v2(Bucket=self.get_bucket_name()) - except Exception as exc: - raise S3ClientError("Couldn't list objects") from exc - return response - def upload_file(self, file_path, file_name): """Uploads a file to our S3 instance""" try: @@ -53,6 +45,7 @@ class S3ClientHelper: raise S3ClientError("File was not found") from exc except Exception as exc: raise S3ClientError("Couldn't get file, an unspecified error occured") from exc + file_content = response["Body"].read() if decode_to_utf: return file_content.decode("utf-8") From d9d86c2eb8c8e2c572ab830846ac810b52ce8c06 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 30 Nov 2023 11:33:15 -0700 Subject: [PATCH 156/245] Update test_reports.py --- src/registrar/tests/test_reports.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index b3cbb72fd..e8796e1fa 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -9,6 +9,8 @@ from registrar.utility.csv_export import export_domains_to_writer 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 +from django.conf import settings +from botocore.exceptions import ClientError import boto3_mocking # type: ignore class CsvReportsTest(TestCase): @@ -122,13 +124,23 @@ class CsvReportsTest(TestCase): @boto3_mocking.patching def test_not_found_full_report(self): """Ensures that we get a not found when the report doesn't exist""" + def side_effect(fake): + raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object") mock_client = MagicMock() mock_client_instance = mock_client.return_value - with boto3_mocking.clients.handler_for("s3", mock_client): - response = self.client.get("/api/v1/get-report/current-full") + mock_client.get_object.side_effect = side_effect + with patch('boto3.client', return_value=mock_client): + with self.assertRaises(ClientError) as context: + with boto3_mocking.clients.handler_for("s3", mock_client): + response = self.client.get("/api/v1/get-report/current-full") - call_args = mock_client_instance - args, kwargs = call_args + expected_call = [ + call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key='current-full.csv') + ] + mock_client_instance.assert_has_calls(expected_call) + mock_client_instance.get_object.side_effect = Exception("An error occurred") + print("look") + print(response.content.decode()) # Check that the response has status code 404 self.assertEqual(response.status_code, 404) # Check that the response body contains "File not found" From 55126689331a4d2e090b6ab3e8e7495a90ffa17a Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:48:41 -0700 Subject: [PATCH 157/245] Test cases - WIP --- src/registrar/tests/test_reports.py | 115 +++++++++++++++++++--------- src/registrar/utility/s3_bucket.py | 48 ++++++++++-- 2 files changed, 119 insertions(+), 44 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index e8796e1fa..23ac04139 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -1,4 +1,5 @@ import csv +import io from django.test import Client, RequestFactory, TestCase from io import StringIO from registrar.models.domain_information import DomainInformation @@ -11,7 +12,8 @@ from unittest.mock import MagicMock, call, mock_open, patch from api.views import get_current_federal, get_current_full from django.conf import settings from botocore.exceptions import ClientError -import boto3_mocking # type: ignore +import boto3_mocking +from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore class CsvReportsTest(TestCase): """Tests to determine if we are uploading our reports correctly""" @@ -124,75 +126,114 @@ class CsvReportsTest(TestCase): @boto3_mocking.patching def test_not_found_full_report(self): """Ensures that we get a not found when the report doesn't exist""" - def side_effect(fake): + def side_effect(Bucket, Key): raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object") mock_client = MagicMock() - mock_client_instance = mock_client.return_value mock_client.get_object.side_effect = side_effect - with patch('boto3.client', return_value=mock_client): - with self.assertRaises(ClientError) as context: - with boto3_mocking.clients.handler_for("s3", mock_client): - response = self.client.get("/api/v1/get-report/current-full") - expected_call = [ - call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key='current-full.csv') - ] - mock_client_instance.assert_has_calls(expected_call) - mock_client_instance.get_object.side_effect = Exception("An error occurred") - print("look") - print(response.content.decode()) - # Check that the response has status code 404 - self.assertEqual(response.status_code, 404) - # Check that the response body contains "File not found" - self.assertEqual(response.content.decode(), "File not found") + response = None + with boto3_mocking.clients.handler_for("s3", mock_client): + with patch('boto3.client', return_value=mock_client): + with self.assertRaises(S3ClientError) as context: + response = self.client.get("/api/v1/get-report/current-full") + # Check that the response has status code 500 + self.assertEqual(response.status_code, 500) + + # Check that we get the right error back from the page + self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR) + @boto3_mocking.patching def test_not_found_federal_report(self): """Ensures that we get a not found when the report doesn't exist""" - response = self.client.get("/api/v1/get-report/current-federal") + def side_effect(Bucket, Key): + raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object") + mock_client = MagicMock() + mock_client.get_object.side_effect = side_effect + + with boto3_mocking.clients.handler_for("s3", mock_client): + with patch('boto3.client', return_value=mock_client): + with self.assertRaises(S3ClientError) as context: + response = self.client.get("/api/v1/get-report/current-federal") + # Check that the response has status code 500 + self.assertEqual(response.status_code, 500) - # Check that the response has status code 404 - self.assertEqual(response.status_code, 404) - # Check that the response body contains "File not found" - self.assertEqual(response.content.decode(), "File not found") + # Check that we get the right error back from the page + self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR) @boto3_mocking.patching def test_load_federal_report(self): - """Tests the current-federal api link""" - if not boto3_mocking.patching_engaged(): - raise Exception("test123") - request = self.factory.get("/fake-path") - response = get_current_federal(request, file_path="registrar/tests/data/fake_current_federal.csv") + """Tests the get_current_federal api endpoint""" + self.maxDiff = None + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + + with open("registrar/tests/data/fake_current_federal.csv", "r") as file: + file_content = file.read() + + # Mock a recieved file + mock_client_instance.get_object.return_value = { + 'Body': io.BytesIO(file_content.encode()) + } + with boto3_mocking.clients.handler_for("s3", mock_client): + request = self.factory.get("/fake-path") + response = get_current_federal(request) + + # Check that we are sending the correct calls. + # Ensures that we are decoding the file content recieved from AWS. + expected_call = [ + call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key='current-federal.csv') + ] + mock_client_instance.assert_has_calls(expected_call) + # Check that the response has status code 200 self.assertEqual(response.status_code, 200) - # Check that the response contains what we expect - file_content = b"".join(response.streaming_content).decode("utf-8") + # Check that the response contains what we expect expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" "ddomain3.gov,Federal,Armed Forces Retirement Home,,,," - ) + ).encode() - self.assertEqual(file_content, expected_file_content) + self.assertEqual(expected_file_content, response.content) @boto3_mocking.patching def test_load_full_report(self): """Tests the current-federal api link""" - request = self.factory.get("/fake-path") - response = get_current_full(request, file_path="registrar/tests/data/fake_current_full.csv") + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + + with open("registrar/tests/data/fake_current_full.csv", "r") as file: + file_content = file.read() + + # Mock a recieved file + mock_client_instance.get_object.return_value = { + 'Body': io.BytesIO(file_content.encode()) + } + with boto3_mocking.clients.handler_for("s3", mock_client): + request = self.factory.get("/fake-path") + response = get_current_federal(request) + + # Check that we are sending the correct calls. + # Ensures that we are decoding the file content recieved from AWS. + expected_call = [ + call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key='current-federal.csv') + ] + mock_client_instance.assert_has_calls(expected_call) + # Check that the response has status code 200 self.assertEqual(response.status_code, 200) + # Check that the response contains what we expect - file_content = b"".join(response.streaming_content).decode("utf-8") expected_file_content = ( "Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\n" "cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,,\n" "ddomain3.gov,Federal,Armed Forces Retirement Home,,,,\n" "adomain2.gov,Interstate,,,,," - ) + ).encode() - self.assertEqual(file_content, expected_file_content) + self.assertEqual(expected_file_content, response.content) class ExportDataTest(TestCase): diff --git a/src/registrar/utility/s3_bucket.py b/src/registrar/utility/s3_bucket.py index 329a68c40..6370b0736 100644 --- a/src/registrar/utility/s3_bucket.py +++ b/src/registrar/utility/s3_bucket.py @@ -1,14 +1,45 @@ """Utilities for accessing an AWS S3 bucket""" +from enum import IntEnum import boto3 - +from botocore.exceptions import ClientError from django.conf import settings from django.template.loader import get_template +class S3ClientErrorCodes(IntEnum): + """Used for S3ClientError + Error code overview: + - 1 ACCESS_S3_CLIENT_ERROR + - 2 UPLOAD_FILE_ERROR + - 3 FILE_NOT_FOUND_ERROR + - 4 GET_FILE_ERROR + """ + + ACCESS_S3_CLIENT_ERROR = 1 + UPLOAD_FILE_ERROR = 2 + FILE_NOT_FOUND_ERROR = 3 + GET_FILE_ERROR = 4 class S3ClientError(RuntimeError): """Local error for handling all failures with boto3.client""" - pass + _error_mapping = { + S3ClientErrorCodes.ACCESS_S3_CLIENT_ERROR: "Failed to establish a connection with the storage service.", + S3ClientErrorCodes.UPLOAD_FILE_ERROR: "File upload to the storage service failed.", + S3ClientErrorCodes.FILE_NOT_FOUND_ERROR: "Requested file not found in the storage service.", + S3ClientErrorCodes.GET_FILE_ERROR: ( + "Retrieval of the requested file from " + "the storage service failed due to an unspecified error." + ), + } + + def __init__(self, *args, code=None, **kwargs): + super().__init__(*args, **kwargs) + self.code = code + if self.code in self._error_mapping: + self.message = self._error_mapping.get(self.code) + + def __str__(self): + return f"{self.message}" class S3ClientHelper: @@ -23,7 +54,7 @@ class S3ClientHelper: config=settings.BOTO_CONFIG, ) except Exception as exc: - raise S3ClientError("Could not access the S3 client") from exc + raise S3ClientError(code=S3ClientErrorCodes.ACCESS_S3_CLIENT_ERROR) from exc def get_bucket_name(self): """Gets the name of our S3 Bucket""" @@ -34,17 +65,20 @@ class S3ClientHelper: try: response = self.boto_client.upload_file(file_path, self.get_bucket_name(), file_name) except Exception as exc: - raise S3ClientError("Couldn't upload file") from exc + raise S3ClientError(code=S3ClientErrorCodes.UPLOAD_FILE_ERROR) from exc return response def get_file(self, file_name, decode_to_utf=False): """Gets a file to our S3 instance and returns the file content""" try: response = self.boto_client.get_object(Bucket=self.get_bucket_name(), Key=file_name) - except self.boto_client.exceptions.NoSuchKey as exc: - raise S3ClientError("File was not found") from exc + except ClientError as exc: + if exc.response['Error']['Code'] == 'NoSuchKey': + raise S3ClientError(code=S3ClientErrorCodes.FILE_NOT_FOUND_ERROR) from exc + else: + raise S3ClientError(code=S3ClientErrorCodes.GET_FILE_ERROR) from exc except Exception as exc: - raise S3ClientError("Couldn't get file, an unspecified error occured") from exc + raise S3ClientError(code=S3ClientErrorCodes.GET_FILE_ERROR) from exc file_content = response["Body"].read() if decode_to_utf: From 682ad5640b50e45ca745c64f71f89afb4e2f0cae Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 30 Nov 2023 15:15:02 -0500 Subject: [PATCH 158/245] wip --- src/registrar/admin.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 2f9bc97c5..b25014fcf 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -455,6 +455,8 @@ class DomainInformationAdmin(ListHeaderAdmin): "is_policy_acknowledged", ] + filter_horizontal = ('other_contacts',) + def get_readonly_fields(self, request, obj=None): """Set the read-only state on form elements. We have 1 conditions that determine which fields are read-only: @@ -591,6 +593,15 @@ class DomainApplicationAdmin(ListHeaderAdmin): "is_policy_acknowledged", ] + filter_horizontal = ('current_websites', 'alternative_domains') + + # lists in filter_horizontal are not sorted properly, sort them + # by website + def formfield_for_manytomany(self, db_field, request, **kwargs): + if db_field.name in ("current_websites", "alternative_domains"): + kwargs["queryset"] = models.Website.objects.all().order_by('website') # Sort websites + return super().formfield_for_manytomany(db_field, request, **kwargs) + # Trigger action when a fieldset is changed def save_model(self, request, obj, form, change): if obj and obj.creator.status != models.User.RESTRICTED: @@ -749,7 +760,7 @@ class DomainAdmin(ListHeaderAdmin): change_form_template = "django/admin/domain_change_form.html" change_list_template = "django/admin/domain_change_list.html" readonly_fields = ["state", "expiration_date"] - + def export_data_type(self, request): # match the CSV example with all the fields response = HttpResponse(content_type="text/csv") From 7904ca0cc4e15b070a2b62ee569693756e74fcce Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Thu, 30 Nov 2023 15:43:54 -0500 Subject: [PATCH 159/245] implement filter_horizontal on other contacts on inline DomainInfo --- src/registrar/admin.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index b25014fcf..e8eb206c2 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -455,7 +455,7 @@ class DomainInformationAdmin(ListHeaderAdmin): "is_policy_acknowledged", ] - filter_horizontal = ('other_contacts',) + filter_horizontal = ("other_contacts",) def get_readonly_fields(self, request, obj=None): """Set the read-only state on form elements. @@ -593,13 +593,13 @@ class DomainApplicationAdmin(ListHeaderAdmin): "is_policy_acknowledged", ] - filter_horizontal = ('current_websites', 'alternative_domains') + filter_horizontal = ("current_websites", "alternative_domains") # lists in filter_horizontal are not sorted properly, sort them # by website def formfield_for_manytomany(self, db_field, request, **kwargs): if db_field.name in ("current_websites", "alternative_domains"): - kwargs["queryset"] = models.Website.objects.all().order_by('website') # Sort websites + kwargs["queryset"] = models.Website.objects.all().order_by("website") # Sort websites return super().formfield_for_manytomany(db_field, request, **kwargs) # Trigger action when a fieldset is changed @@ -730,6 +730,7 @@ class DomainInformationInline(admin.StackedInline): fieldsets = DomainInformationAdmin.fieldsets analyst_readonly_fields = DomainInformationAdmin.analyst_readonly_fields + filter_horizontal = ("other_contacts",) def get_readonly_fields(self, request, obj=None): return DomainInformationAdmin.get_readonly_fields(self, request, obj=None) @@ -760,7 +761,7 @@ class DomainAdmin(ListHeaderAdmin): change_form_template = "django/admin/domain_change_form.html" change_list_template = "django/admin/domain_change_list.html" readonly_fields = ["state", "expiration_date"] - + def export_data_type(self, request): # match the CSV example with all the fields response = HttpResponse(content_type="text/csv") From 856a32210d4f053c141e384f4af2eea33619e692 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Thu, 30 Nov 2023 16:27:24 -0500 Subject: [PATCH 160/245] other contacts updated in domain applications --- src/registrar/admin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index e8eb206c2..93511929f 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -593,7 +593,7 @@ class DomainApplicationAdmin(ListHeaderAdmin): "is_policy_acknowledged", ] - filter_horizontal = ("current_websites", "alternative_domains") + filter_horizontal = ("current_websites", "alternative_domains", "other_contacts") # lists in filter_horizontal are not sorted properly, sort them # by website From 73a82a0b1bf55667635a6995c51d1d340c98fed2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:12:54 -0700 Subject: [PATCH 161/245] Create migration-troubleshooting.md --- docs/developer/migration-troubleshooting.md | 112 ++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 docs/developer/migration-troubleshooting.md diff --git a/docs/developer/migration-troubleshooting.md b/docs/developer/migration-troubleshooting.md new file mode 100644 index 000000000..6b757fdb7 --- /dev/null +++ b/docs/developer/migration-troubleshooting.md @@ -0,0 +1,112 @@ +## Troubleshooting + +### Your toolkit +For a general overview, read [this documentation](https://www.algotech.solutions/blog/python/django-migrations-and-how-to-manage-conflicts/) + + +Some common commands: +- docker-compose exec app bash -- gets you into bash +- ./manage.py showmigrations -- shows the current migrations that are finished, all should have [x] +- ./manage.py makemigrations -- makes the migration +- ./manage.py showmigrations -- now you should see the new/updated migration with a [ ] +- ./manage.py migrate [folder name here, ie registrar] +- ./manage.py showmigrations -- the migration changes should now have a [x] by it + + +On occasion, you will need to run this set of commands to refresh your environment: +docker-compose down +docker-compose build +docker-compose up + + +## Scenarios + +### Scenario 1: Conflicting migrations on local + +If you get conflicting migrations on local, you probably have a new migration on your branch and you merged main which had new migrations as well. Do NOT merge migrations together. Assume your local migration is 40_local_migration and the migration from main is 40_some_migration_from_main: +Delete 40_local_migration +Run `docker-compose exec app ./manage.py makemigrations` +Compose down then up or run `docker-compose exec app ./manage.py migrate` +You should end up with 40_some_migration_from_main, 41_local_migration +Alternatively, assuming that the conflicting migrations are not dependent on each other, you can manually edit the migration file such that your new migration is incremented by one (file name, and definition inside the file) but this approach is not recommended. + +### Scenario 2: Conflicting migrations on sandbox + +You will diagnose when the migrations job on your PR fails and the logs show “conflicting migrations, multiple leaves found” (something like that). This happens when you swap branches on your sandbox that contain diverging leaves (eg: 40_migration_1 and 40_migration_2). The fix is to go into the sandbox, delete one of these leaves, fake run the preceding migration, hand run the remaining previously conflicting leaf, fake run the last migration: +`cf login -a api.fr.cloud.gov --sso` +`cf ssh getgov-` +`/tmp/lifecycle/shell` +Navigate to and delete the offending migration +`cf run-task getgov- --wait --command 'python manage.py migrate registrar 39_previous_miration --fake' --name migrate +`cf run-task getgov- --wait --command 'python manage.py migrate registrar 40_migration_2' --name migrate` +`cf run-task getgov- --wait --command 'python manage.py migrate registrar 45_last_migration --fake' --name migrate` + + +### Scenario 3: Migrations ran incorrectly, and migrate no longer works (sandbox) + +This has happened when updating user perms (so running a new data migration). Something is off with the update on the sandbox and you need to run that last data migration again: +`cf login -a api.fr.cloud.gov --sso` +`cf run-task getgov- --wait --command 'python manage.py migrate registrar 39_penultimate_miration --fake' --name migrate` +`cf run-task getgov- --wait --command 'python manage.py migrate' --name migrate` + + +### Scenario 4: All migrations refuse to load due to existing duplicates on sandboxes + +This typically happens with a DB conflict that prevents 001_initial from loading. For instance, let's say all migrations have ran successfully before, and a zero command is ran to reset everything. This can lead to a catastrophic issue with your postgres database. + +To diagnose this issue, you will have to manually delete tables using the psql shell environment. If you are in a production environment and cannot lose that data, then you will need some method of backing that up and reattaching it to the table. +`cf login -a api.fr.cloud.gov --sso` +Run `cf connect-to-service -no-client getgov-{environment_name} getgov-{environment_name}-database` to open a SSH tunnel +Run `psql -h localhost -p {port} -U {username} -d {broker_name}` +Open a new terminal window and run `cf ssh getgov{environment_name}` +Run `tmp/lifecycle/shell` +Run `./manage.py migrate` and observe which tables are duplicates +In the psql instance, run `DROP TABLE {table_name} CASCADE` **WARNING:** this will permanently erase data! Be careful when doing this and exercise common sense. +Run `./manage.py migrate` again and repeat step 7 for each table which returns this error. +After these errors are resolved, follow instructions in the other scenarios if applicable. + + +### Scenario 5: Permissions group exist, but my users cannot log onto the sandbox + +This is most likely due to fixtures not running or fixtures running before the data creating migration. Simple run fixtures again (WARNING: This applies to dev sandboxes only. We never want to rerun fixtures on a stable environment) +`cf login -a api.fr.cloud.gov --sso` +`cf run-task getgov- --command "./manage.py load" --name fixtures` + +### Scenario 6: The data is corrupted on the sandbox + +Example: there are extra columns created on a table by an old migration long since gone from the code. In that case, you may have to tunnel into your DB on the sandbox and hand-delete these columns. See scenario #4 if you are running into duplicate table definitions. Also see [this documentation](docs/developer/database-access.md) for a good reference here: +`cf login -a api.fr.cloud.gov --sso` +Open a new terminal window and run `cf ssh getgov{environment_name}` +Run `tmp/lifecycle/shell` +Run `./manage.py migrate` and observe which tables have invalid column definitions +Run the `\l` command to see all of the databases that are present +`\c cgawsbrokerprodlgi635s6c0afp8w` (assume cgawsbrokerprodlgi635s6c0afp8w is your DB) +‘\dt’ to see the tables +`SELECT * FROM {bad_table};` +`alter table registrar_domain drop {bad_column};` + + +### Scenario 7: Continual 500 error for the registrar + your requests (login, clicking around, etc) are not showing up in the logstream + +Example: You are able to log in and access the /admin page, but when you arrive at the registrar you keep getting 500 errors and your log-ins any API calls you make via the UI does not show up in the log stream. And you feel like you’re starting to lose your marbles. + +In the CLI, run the command `cf routes` +If you notice that your route of `getgov-.app.cloud.gov` is pointing two apps, then that is probably the major issue of the 500 error. (ie mine was pointing at `getgov-.app.cloud.gov` AND `cisa-dotgov` +In the CLI, run the command `cf apps` to check that it has an app running called `cisa-dotgov`. If so, there’s the error! +Essentially this shows that your requests were being handled by two completely separate applications and that’s why some requests aren’t being located. +To resolve this issue, remove the app named `cisa-dotgov` from this space. +Test out the sandbox from there and it should be working! + +Debug connectivity: + +dig getgov-rh.app.cloud.gov (domain information groper, gets DNS nameserver information) +curl -v https://getgov-.app.cloud.gov/ --resolve 'getgov-.app.cloud.gov:' (this gets you access to ping to it) +You should be able to play around with your sandbox and see from the curl command above that it’s being pinged. This command is basically log stream, but gives you full access to make sure you can ping the sandbox manually +https://cisa-corp.slack.com/archives/C05BGB4L5NF/p1697810600723069 + +### Scenario 8: Can’t log into sandbox, permissions do not exist + +Fake migrate the migration that’s before the last data creation migration +Run the last data creation migration (AND ONLY THAT ONE) +Fake migrate the last migration in the migration list +Rerun fixtures From e100a0edbd0e1617b0f0d9fd0c84ce218f690e75 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:30:19 -0700 Subject: [PATCH 162/245] Some formatting --- docs/developer/migration-troubleshooting.md | 106 ++++++++++++-------- 1 file changed, 63 insertions(+), 43 deletions(-) diff --git a/docs/developer/migration-troubleshooting.md b/docs/developer/migration-troubleshooting.md index 6b757fdb7..ff451bfdd 100644 --- a/docs/developer/migration-troubleshooting.md +++ b/docs/developer/migration-troubleshooting.md @@ -14,40 +14,51 @@ Some common commands: On occasion, you will need to run this set of commands to refresh your environment: -docker-compose down -docker-compose build -docker-compose up +- docker-compose down +- docker-compose build +- docker-compose up ## Scenarios ### Scenario 1: Conflicting migrations on local -If you get conflicting migrations on local, you probably have a new migration on your branch and you merged main which had new migrations as well. Do NOT merge migrations together. Assume your local migration is 40_local_migration and the migration from main is 40_some_migration_from_main: -Delete 40_local_migration -Run `docker-compose exec app ./manage.py makemigrations` -Compose down then up or run `docker-compose exec app ./manage.py migrate` -You should end up with 40_some_migration_from_main, 41_local_migration +If you get conflicting migrations on local, you probably have a new migration on your branch and you merged main which had new migrations as well. Do NOT merge migrations together. + +Assuming your local migration is `40_local_migration` and the migration from main is `40_some_migration_from_main`: +- Delete `40_local_migration` +- Run `docker-compose exec app ./manage.py makemigrations` +- Run `docker-compose down` +- Run `docker-compose up` +- Run `docker-compose exec app ./manage.py migrate` + +You should end up with `40_some_migration_from_main`, `41_local_migration` + Alternatively, assuming that the conflicting migrations are not dependent on each other, you can manually edit the migration file such that your new migration is incremented by one (file name, and definition inside the file) but this approach is not recommended. ### Scenario 2: Conflicting migrations on sandbox -You will diagnose when the migrations job on your PR fails and the logs show “conflicting migrations, multiple leaves found” (something like that). This happens when you swap branches on your sandbox that contain diverging leaves (eg: 40_migration_1 and 40_migration_2). The fix is to go into the sandbox, delete one of these leaves, fake run the preceding migration, hand run the remaining previously conflicting leaf, fake run the last migration: -`cf login -a api.fr.cloud.gov --sso` -`cf ssh getgov-` -`/tmp/lifecycle/shell` -Navigate to and delete the offending migration -`cf run-task getgov- --wait --command 'python manage.py migrate registrar 39_previous_miration --fake' --name migrate -`cf run-task getgov- --wait --command 'python manage.py migrate registrar 40_migration_2' --name migrate` -`cf run-task getgov- --wait --command 'python manage.py migrate registrar 45_last_migration --fake' --name migrate` +This occurs when the logs return the following: +>Conflicting migrations detected; multiple leaf nodes in the migration graph: (0040_example, 0041_example in base). +To fix them run 'python manage.py makemigrations --merge' +This happens when you swap branches on your sandbox that contain diverging leaves (eg: 0040_example, 0041_example). The fix is to go into the sandbox, delete one of these leaves, fake run the preceding migration, hand run the remaining previously conflicting leaf, fake run the last migration: + +- `cf login -a api.fr.cloud.gov --sso` +- `cf ssh getgov-` +- `/tmp/lifecycle/shell` +- `cf run-task getgov- --wait --command 'python manage.py migrate registrar 39_previous_miration --fake' --name migrate` +- `cf run-task getgov- --wait --command 'python manage.py migrate registrar 41_example_migration' --name migrate` +- `cf run-task getgov- --wait --command 'python manage.py migrate registrar 45_last_migration --fake' --name migrate` + +Then, navigate to and delete the offending migration. In this case, it is 0041_example_migration. ### Scenario 3: Migrations ran incorrectly, and migrate no longer works (sandbox) This has happened when updating user perms (so running a new data migration). Something is off with the update on the sandbox and you need to run that last data migration again: -`cf login -a api.fr.cloud.gov --sso` -`cf run-task getgov- --wait --command 'python manage.py migrate registrar 39_penultimate_miration --fake' --name migrate` -`cf run-task getgov- --wait --command 'python manage.py migrate' --name migrate` +- `cf login -a api.fr.cloud.gov --sso` +- `cf run-task getgov- --wait --command 'python manage.py migrate registrar 39_penultimate_miration --fake' --name migrate` +- `cf run-task getgov- --wait --command 'python manage.py migrate' --name migrate` ### Scenario 4: All migrations refuse to load due to existing duplicates on sandboxes @@ -55,35 +66,44 @@ This has happened when updating user perms (so running a new data migration). So This typically happens with a DB conflict that prevents 001_initial from loading. For instance, let's say all migrations have ran successfully before, and a zero command is ran to reset everything. This can lead to a catastrophic issue with your postgres database. To diagnose this issue, you will have to manually delete tables using the psql shell environment. If you are in a production environment and cannot lose that data, then you will need some method of backing that up and reattaching it to the table. -`cf login -a api.fr.cloud.gov --sso` -Run `cf connect-to-service -no-client getgov-{environment_name} getgov-{environment_name}-database` to open a SSH tunnel -Run `psql -h localhost -p {port} -U {username} -d {broker_name}` -Open a new terminal window and run `cf ssh getgov{environment_name}` -Run `tmp/lifecycle/shell` -Run `./manage.py migrate` and observe which tables are duplicates -In the psql instance, run `DROP TABLE {table_name} CASCADE` **WARNING:** this will permanently erase data! Be careful when doing this and exercise common sense. -Run `./manage.py migrate` again and repeat step 7 for each table which returns this error. + +1. `cf login -a api.fr.cloud.gov --sso` +2. Run `cf connect-to-service -no-client getgov-{environment_name} getgov-{environment_name}-database` to open a SSH tunnel +3. Run `psql -h localhost -p {port} -U {username} -d {broker_name}` +4. Open a new terminal window and run `cf ssh getgov{environment_name}` +5. Within that window, run `tmp/lifecycle/shell` +6. Within that window, run `./manage.py migrate` and observe which tables are duplicates + +Afterwards, go back to your psql instance. Run the following for each problematic table: + +7. `DROP TABLE {table_name} CASCADE` + +**WARNING:** this will permanently erase data! Be careful when doing this and exercise common sense. + +Then, run `./manage.py migrate` again and repeat step 7 for each table which returns this error. After these errors are resolved, follow instructions in the other scenarios if applicable. ### Scenario 5: Permissions group exist, but my users cannot log onto the sandbox This is most likely due to fixtures not running or fixtures running before the data creating migration. Simple run fixtures again (WARNING: This applies to dev sandboxes only. We never want to rerun fixtures on a stable environment) -`cf login -a api.fr.cloud.gov --sso` -`cf run-task getgov- --command "./manage.py load" --name fixtures` -### Scenario 6: The data is corrupted on the sandbox +- `cf login -a api.fr.cloud.gov --sso` +- `cf run-task getgov- --command "./manage.py load" --name fixtures` + +### Scenario 6: Data is corrupted on the sandbox Example: there are extra columns created on a table by an old migration long since gone from the code. In that case, you may have to tunnel into your DB on the sandbox and hand-delete these columns. See scenario #4 if you are running into duplicate table definitions. Also see [this documentation](docs/developer/database-access.md) for a good reference here: -`cf login -a api.fr.cloud.gov --sso` -Open a new terminal window and run `cf ssh getgov{environment_name}` -Run `tmp/lifecycle/shell` -Run `./manage.py migrate` and observe which tables have invalid column definitions -Run the `\l` command to see all of the databases that are present -`\c cgawsbrokerprodlgi635s6c0afp8w` (assume cgawsbrokerprodlgi635s6c0afp8w is your DB) + +- `cf login -a api.fr.cloud.gov --sso` +- Open a new terminal window and run `cf ssh getgov{environment_name}` +- Run `tmp/lifecycle/shell` +- Run `./manage.py migrate` and observe which tables have invalid column definitions +- Run the `\l` command to see all of the databases that are present +- `\c cgawsbrokerprodlgi635s6c0afp8w` (assume cgawsbrokerprodlgi635s6c0afp8w is your DB) ‘\dt’ to see the tables -`SELECT * FROM {bad_table};` -`alter table registrar_domain drop {bad_column};` +- `SELECT * FROM {bad_table};` +- `alter table registrar_domain drop {bad_column};` ### Scenario 7: Continual 500 error for the registrar + your requests (login, clicking around, etc) are not showing up in the logstream @@ -97,7 +117,7 @@ Essentially this shows that your requests were being handled by two completely s To resolve this issue, remove the app named `cisa-dotgov` from this space. Test out the sandbox from there and it should be working! -Debug connectivity: +**Debug connectivity** dig getgov-rh.app.cloud.gov (domain information groper, gets DNS nameserver information) curl -v https://getgov-.app.cloud.gov/ --resolve 'getgov-.app.cloud.gov:' (this gets you access to ping to it) @@ -106,7 +126,7 @@ https://cisa-corp.slack.com/archives/C05BGB4L5NF/p1697810600723069 ### Scenario 8: Can’t log into sandbox, permissions do not exist -Fake migrate the migration that’s before the last data creation migration -Run the last data creation migration (AND ONLY THAT ONE) -Fake migrate the last migration in the migration list -Rerun fixtures +- Fake migrate the migration that’s before the last data creation migration +- Run the last data creation migration (AND ONLY THAT ONE) +- Fake migrate the last migration in the migration list +- Rerun fixtures From 7f71eb4b96712675fc88cd8cd99ea55ce835e461 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 08:52:50 -0700 Subject: [PATCH 163/245] Update test cases --- src/registrar/tests/test_reports.py | 36 ++++++++--------------------- 1 file changed, 10 insertions(+), 26 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 23ac04139..a06d6f1c2 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -68,39 +68,21 @@ class CsvReportsTest(TestCase): User.objects.all().delete() super().tearDown() - def test_create_failed_federal(self): - """Ensures that we return an error when we cannot find our created file""" - fake_open = mock_open() - # We don't actually want to write anything for a test case, - # we just want to verify what is being written. - with patch("builtins.open", fake_open), self.assertRaises(FileNotFoundError) as err: - call_command("generate_current_federal_report") - error = err.exception - self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-federal.csv'") - - def test_create_failed_full(self): - """Ensures that we return an error when we cannot find our created file""" - fake_open = mock_open() - # We don't actually want to write anything for a test case, - # we just want to verify what is being written. - with patch("builtins.open", fake_open), self.assertRaises(FileNotFoundError) as err: - call_command("generate_current_full_report") - error = err.exception - self.assertEqual(str(error), "Could not find newly created file at 'migrationdata/current-full.csv'") - @boto3_mocking.patching def test_generate_federal_report(self): """Ensures that we correctly generate current-federal.csv""" + mock_client = MagicMock() + fake_open = mock_open() expected_file_content = [ call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), ] - fake_open = mock_open() # We don't actually want to write anything for a test case, # we just want to verify what is being written. - with patch("builtins.open", fake_open): - call_command("generate_current_federal_report", checkpath=False) + with boto3_mocking.clients.handler_for("s3", mock_client): + with patch("builtins.open", fake_open): + call_command("generate_current_federal_report", checkpath=False) content = fake_open() # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) @@ -108,17 +90,19 @@ class CsvReportsTest(TestCase): @boto3_mocking.patching def test_generate_full_report(self): """Ensures that we correctly generate current-full.csv""" + mock_client = MagicMock() + fake_open = mock_open() expected_file_content = [ call("Domain name,Domain type,Agency,Organization name,City,State,Security Contact Email\r\n"), call("cdomain1.gov,Federal - Executive,World War I Centennial Commission,,,, \r\n"), call("ddomain3.gov,Federal,Armed Forces Retirement Home,,,, \r\n"), call("adomain2.gov,Interstate,,,,, \r\n"), ] - fake_open = mock_open() # We don't actually want to write anything for a test case, # we just want to verify what is being written. - with patch("builtins.open", fake_open): - call_command("generate_current_full_report", checkpath=False) + with boto3_mocking.clients.handler_for("s3", mock_client): + with patch("builtins.open", fake_open): + call_command("generate_current_full_report", checkpath=False) content = fake_open() # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) From ea289a6f592a8e6009b09fd8ca5083dc5442d3bb Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:06:27 -0700 Subject: [PATCH 164/245] Linting + test cases --- src/api/views.py | 3 +- .../generate_current_federal_report.py | 6 +-- .../commands/generate_current_full_report.py | 7 ++-- src/registrar/tests/test_reports.py | 42 +++++++++---------- src/registrar/utility/s3_bucket.py | 10 +++-- 5 files changed, 32 insertions(+), 36 deletions(-) diff --git a/src/api/views.py b/src/api/views.py index 60f11023e..f888ee6d4 100644 --- a/src/api/views.py +++ b/src/api/views.py @@ -1,8 +1,7 @@ """Internal API views""" -import os from django.apps import apps from django.views.decorators.http import require_http_methods -from django.http import FileResponse, HttpResponse, JsonResponse +from django.http import HttpResponse, JsonResponse from django.utils.safestring import mark_safe from registrar.templatetags.url_helpers import public_site_url diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 6075d8ebb..478265ca0 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -39,11 +39,11 @@ class Command(BaseCommand): logger.info(f"Success! Created {file_name}") def generate_current_federal_report(self, directory, file_name, check_path): - """Creates a current-full.csv file under the specified directory, + """Creates a current-full.csv file under the specified directory, then uploads it to a AWS S3 bucket""" s3_client = S3ClientHelper() file_path = os.path.join(directory, file_name) - + # Generate a file locally for upload with open(file_path, "w") as file: csv_export.export_data_federal_to_csv(file) @@ -51,5 +51,5 @@ class Command(BaseCommand): if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") - # Upload this generated file for our S3 instance + # Upload this generated file for our S3 instance s3_client.upload_file(file_path, file_name) diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 83be4f9b5..c41c697a1 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -39,11 +39,11 @@ class Command(BaseCommand): logger.info(f"Success! Created {file_name}") def generate_current_full_report(self, directory, file_name, check_path): - """Creates a current-full.csv file under the specified directory, + """Creates a current-full.csv file under the specified directory, then uploads it to a AWS S3 bucket""" s3_client = S3ClientHelper() file_path = os.path.join(directory, file_name) - + # Generate a file locally for upload with open(file_path, "w") as file: csv_export.export_data_full_to_csv(file) @@ -51,6 +51,5 @@ class Command(BaseCommand): if check_path and not os.path.exists(file_path): raise FileNotFoundError(f"Could not find newly created file at '{file_path}'") - # Upload this generated file for our S3 instance + # Upload this generated file for our S3 instance s3_client.upload_file(file_path, file_name) - diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index a06d6f1c2..266f7c799 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -15,6 +15,7 @@ from botocore.exceptions import ClientError import boto3_mocking from registrar.utility.s3_bucket import S3ClientError, S3ClientErrorCodes # type: ignore + class CsvReportsTest(TestCase): """Tests to determine if we are uploading our reports correctly""" @@ -106,18 +107,20 @@ class CsvReportsTest(TestCase): content = fake_open() # Now you can make assertions about how you expect 'file' to be used. content.write.assert_has_calls(expected_file_content) - + @boto3_mocking.patching def test_not_found_full_report(self): """Ensures that we get a not found when the report doesn't exist""" + def side_effect(Bucket, Key): raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object") + mock_client = MagicMock() mock_client.get_object.side_effect = side_effect response = None with boto3_mocking.clients.handler_for("s3", mock_client): - with patch('boto3.client', return_value=mock_client): + with patch("boto3.client", return_value=mock_client): with self.assertRaises(S3ClientError) as context: response = self.client.get("/api/v1/get-report/current-full") # Check that the response has status code 500 @@ -126,17 +129,18 @@ class CsvReportsTest(TestCase): # Check that we get the right error back from the page self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR) - @boto3_mocking.patching def test_not_found_federal_report(self): """Ensures that we get a not found when the report doesn't exist""" + def side_effect(Bucket, Key): raise ClientError({"Error": {"Code": "NoSuchKey", "Message": "No such key"}}, "get_object") + mock_client = MagicMock() mock_client.get_object.side_effect = side_effect - + with boto3_mocking.clients.handler_for("s3", mock_client): - with patch('boto3.client', return_value=mock_client): + with patch("boto3.client", return_value=mock_client): with self.assertRaises(S3ClientError) as context: response = self.client.get("/api/v1/get-report/current-federal") # Check that the response has status code 500 @@ -144,7 +148,7 @@ class CsvReportsTest(TestCase): # Check that we get the right error back from the page self.assertEqual(context.exception.code, S3ClientErrorCodes.FILE_NOT_FOUND_ERROR) - + @boto3_mocking.patching def test_load_federal_report(self): """Tests the get_current_federal api endpoint""" @@ -156,18 +160,14 @@ class CsvReportsTest(TestCase): file_content = file.read() # Mock a recieved file - mock_client_instance.get_object.return_value = { - 'Body': io.BytesIO(file_content.encode()) - } + mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())} with boto3_mocking.clients.handler_for("s3", mock_client): request = self.factory.get("/fake-path") response = get_current_federal(request) - - # Check that we are sending the correct calls. + + # Check that we are sending the correct calls. # Ensures that we are decoding the file content recieved from AWS. - expected_call = [ - call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key='current-federal.csv') - ] + expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-federal.csv")] mock_client_instance.assert_has_calls(expected_call) # Check that the response has status code 200 @@ -192,18 +192,14 @@ class CsvReportsTest(TestCase): file_content = file.read() # Mock a recieved file - mock_client_instance.get_object.return_value = { - 'Body': io.BytesIO(file_content.encode()) - } + mock_client_instance.get_object.return_value = {"Body": io.BytesIO(file_content.encode())} with boto3_mocking.clients.handler_for("s3", mock_client): request = self.factory.get("/fake-path") - response = get_current_federal(request) - - # Check that we are sending the correct calls. + response = get_current_full(request) + + # Check that we are sending the correct calls. # Ensures that we are decoding the file content recieved from AWS. - expected_call = [ - call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key='current-federal.csv') - ] + expected_call = [call.get_object(Bucket=settings.AWS_S3_BUCKET_NAME, Key="current-full.csv")] mock_client_instance.assert_has_calls(expected_call) # Check that the response has status code 200 diff --git a/src/registrar/utility/s3_bucket.py b/src/registrar/utility/s3_bucket.py index 6370b0736..162be37c9 100644 --- a/src/registrar/utility/s3_bucket.py +++ b/src/registrar/utility/s3_bucket.py @@ -4,7 +4,7 @@ from enum import IntEnum import boto3 from botocore.exceptions import ClientError from django.conf import settings -from django.template.loader import get_template + class S3ClientErrorCodes(IntEnum): """Used for S3ClientError @@ -20,15 +20,16 @@ class S3ClientErrorCodes(IntEnum): FILE_NOT_FOUND_ERROR = 3 GET_FILE_ERROR = 4 + class S3ClientError(RuntimeError): """Local error for handling all failures with boto3.client""" + _error_mapping = { S3ClientErrorCodes.ACCESS_S3_CLIENT_ERROR: "Failed to establish a connection with the storage service.", S3ClientErrorCodes.UPLOAD_FILE_ERROR: "File upload to the storage service failed.", S3ClientErrorCodes.FILE_NOT_FOUND_ERROR: "Requested file not found in the storage service.", S3ClientErrorCodes.GET_FILE_ERROR: ( - "Retrieval of the requested file from " - "the storage service failed due to an unspecified error." + "Retrieval of the requested file from " "the storage service failed due to an unspecified error." ), } @@ -44,6 +45,7 @@ class S3ClientError(RuntimeError): class S3ClientHelper: """Helper class that simplifies S3 intialization""" + def __init__(self): try: self.boto_client = boto3.client( @@ -73,7 +75,7 @@ class S3ClientHelper: try: response = self.boto_client.get_object(Bucket=self.get_bucket_name(), Key=file_name) except ClientError as exc: - if exc.response['Error']['Code'] == 'NoSuchKey': + if exc.response["Error"]["Code"] == "NoSuchKey": raise S3ClientError(code=S3ClientErrorCodes.FILE_NOT_FOUND_ERROR) from exc else: raise S3ClientError(code=S3ClientErrorCodes.GET_FILE_ERROR) from exc From 840cd4748aeaa161f7fd2996e32cb9b16653f43b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:31:02 -0700 Subject: [PATCH 165/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 245f19fcc..ebd7c0df5 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -24,15 +24,14 @@ on: - bl - rjm - dk - # TODO - uncomment after #1403 is finished - #schedule: + schedule: # Runs every day at 5 AM UTC. - # - cron: "0 5 * * *" + - cron: "0 5 * * *" jobs: variables: outputs: - environment: 'za' + environment: ${{ steps.var.outputs.environment}} runs-on: "ubuntu-latest" steps: - name: Setting global variables @@ -60,7 +59,7 @@ jobs: upload-reports: runs-on: ubuntu-latest - needs: [variables, wait-for-deploy] + needs: [variables] env: CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD From 18a10978e1c019e9bdacc999be557b9849b24345 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:33:56 -0700 Subject: [PATCH 166/245] Print all secrets --- .github/workflows/daily-csv-upload.yaml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index ebd7c0df5..72a2c3c93 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -56,14 +56,16 @@ jobs: timeoutSeconds: 600 # the time to wait between checks, in seconds intervalSeconds: 10 - + upload-reports: runs-on: ubuntu-latest - needs: [variables] + needs: [variables, wait-for-deploy] env: CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD steps: + - name: Print names of all secrets + run: echo ${{ toJson(secrets) }} - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: From 20122727f76639a95e34b327ff6161aa02d267e5 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:35:03 -0700 Subject: [PATCH 167/245] More prints --- .github/workflows/daily-csv-upload.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 72a2c3c93..21ef3676c 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -66,6 +66,10 @@ jobs: steps: - name: Print names of all secrets run: echo ${{ toJson(secrets) }} + - name: Print cf_username + run: echo ${{ env.CF_USERNAME }} + - name: Print cf_password + run: echo ${{ env.CF_PASSWORD }} - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: From 6a10b8096dca975130842dba38123d3dc6ec3eee Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:42:28 -0700 Subject: [PATCH 168/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 21ef3676c..0cbd44f0d 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -59,17 +59,21 @@ jobs: upload-reports: runs-on: ubuntu-latest - needs: [variables, wait-for-deploy] + needs: [variables] env: CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD steps: - - name: Print names of all secrets - run: echo ${{ toJson(secrets) }} - - name: Print cf_username - run: echo ${{ env.CF_USERNAME }} - - name: Print cf_password - run: echo ${{ env.CF_PASSWORD }} + - name: Check secrets + run: | + if [[ -z "${{ secrets.CF_ZA_USERNAME }}" ]]; then + echo "CF_ZA_USERNAME is not set" + exit 1 + fi + if [[ -z "${{ secrets.CF_ZA_PASSWORD }}" ]]; then + echo "CF_ZA_PASSWORD is not set" + exit 1 + fi - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: From 89f45ef2fb7fe69b287c4e869df8a7e3b9b31cec Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 09:59:06 -0700 Subject: [PATCH 169/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 0cbd44f0d..886808528 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -64,16 +64,16 @@ jobs: CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD steps: - - name: Check secrets - run: | - if [[ -z "${{ secrets.CF_ZA_USERNAME }}" ]]; then - echo "CF_ZA_USERNAME is not set" - exit 1 - fi - if [[ -z "${{ secrets.CF_ZA_PASSWORD }}" ]]; then - echo "CF_ZA_PASSWORD is not set" - exit 1 - fi + - name: Check secrets + run: | + if [[ -z "${{ secrets.CF_ZA_USERNAME }}" ]]; then + echo "CF_ZA_USERNAME is not set" + exit 1 + fi + if [[ -z "${{ secrets.CF_ZA_PASSWORD }}" ]]; then + echo "CF_ZA_PASSWORD is not set" + exit 1 + fi - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: From 5c3766cb0636a2dcf66bc59fd5d14cdcfb0a9510 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:21:02 -0700 Subject: [PATCH 170/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 886808528..7421a2ae7 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -39,7 +39,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'za'; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'ZA'; core.setOutput('environment', environment); wait-for-deploy: @@ -64,16 +64,6 @@ jobs: CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD steps: - - name: Check secrets - run: | - if [[ -z "${{ secrets.CF_ZA_USERNAME }}" ]]; then - echo "CF_ZA_USERNAME is not set" - exit 1 - fi - if [[ -z "${{ secrets.CF_ZA_PASSWORD }}" ]]; then - echo "CF_ZA_PASSWORD is not set" - exit 1 - fi - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: From 23b30808490141241642f489e262cf1b8db9a1e7 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:24:32 -0700 Subject: [PATCH 171/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 7421a2ae7..25ad0c074 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -67,8 +67,8 @@ jobs: - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: - cf_username: ${{ secrets[env.CF_USERNAME] }} - cf_password: ${{ secrets[env.CF_PASSWORD] }} + cf_username: ${{ secrets[CF_ZA_USERNAME] }} + cf_password: ${{ secrets[CF_ZA_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" From 873f2df7e0464b65afb4b27932e0b1e7eb15f970 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:38:19 -0700 Subject: [PATCH 172/245] Test string --- .github/workflows/daily-csv-upload.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 25ad0c074..ce60b75ac 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -67,8 +67,8 @@ jobs: - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: - cf_username: ${{ secrets[CF_ZA_USERNAME] }} - cf_password: ${{ secrets[CF_ZA_PASSWORD] }} + cf_username: ${{ secrets["CF_ZA_USERNAME"] }} + cf_password: ${{ secrets["CF_ZA_USERNAME"] }} cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" From bdbde4a56b152bfea1da405f563f1610f71992d6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:39:23 -0700 Subject: [PATCH 173/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index ce60b75ac..2b00215a4 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -68,7 +68,7 @@ jobs: uses: cloud-gov/cg-cli-tools@main with: cf_username: ${{ secrets["CF_ZA_USERNAME"] }} - cf_password: ${{ secrets["CF_ZA_USERNAME"] }} + cf_password: ${{ secrets["CF_ZA_PASSWORD"] }} cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" From 5ce598e848c81172b2480abb2e2a66f7f3278ebe Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:42:28 -0700 Subject: [PATCH 174/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 2b00215a4..7421a2ae7 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -67,8 +67,8 @@ jobs: - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main with: - cf_username: ${{ secrets["CF_ZA_USERNAME"] }} - cf_password: ${{ secrets["CF_ZA_PASSWORD"] }} + cf_username: ${{ secrets[env.CF_USERNAME] }} + cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov cf_space: ${{ needs.variables.outputs.environment }} cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" From d4224799d82f3d8482d629caf168228602c64404 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:44:15 -0700 Subject: [PATCH 175/245] Remove wait-for-deploy and added comment --- .github/workflows/daily-csv-upload.yaml | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 7421a2ae7..321fd92a7 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,6 +2,7 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: + # pull_request will be removed when merged pull_request: workflow_dispatch: inputs: @@ -42,21 +43,6 @@ jobs: const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'ZA'; core.setOutput('environment', environment); - wait-for-deploy: - runs-on: ubuntu-latest - steps: - - name: Wait for deploy to complete - uses: fountainhead/action-wait-for-check@v1.0.0 - id: wait-for-deploy - with: - token: ${{ secrets.GITHUB_TOKEN }} - checkName: "deploy" - ref: ${{ github.event.pull_request.head.sha }} - # the maximum time to wait for the check to complete, in seconds - timeoutSeconds: 600 - # the time to wait between checks, in seconds - intervalSeconds: 10 - upload-reports: runs-on: ubuntu-latest needs: [variables] From aad157c7e117132e4536df729db8eba9dc0d73c1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:49:23 -0700 Subject: [PATCH 176/245] Change to double quotes --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 321fd92a7..a9f82d096 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -40,7 +40,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : 'ZA'; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : "ZA"; core.setOutput('environment', environment); upload-reports: From b81a3f1708178f792e97bc70f43eb1fc4db0c3b5 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:51:52 -0700 Subject: [PATCH 177/245] Add missing dollar sign --- .github/workflows/daily-csv-upload.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index a9f82d096..3b9918713 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -47,8 +47,8 @@ jobs: runs-on: ubuntu-latest needs: [variables] env: - CF_USERNAME: CF_{{ needs.variables.outputs.environment }}_USERNAME - CF_PASSWORD: CF_{{ needs.variables.outputs.environment }}_PASSWORD + CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME + CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD steps: - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main From bd0f0bb2d6d61e1b968edec7f00b61d40c8e80cc Mon Sep 17 00:00:00 2001 From: CocoByte Date: Fri, 1 Dec 2023 12:24:18 -0700 Subject: [PATCH 178/245] Fix for phone number not raising invalid message in domain management --- src/registrar/forms/domain.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/forms/domain.py b/src/registrar/forms/domain.py index 71c86ef41..39bda2f20 100644 --- a/src/registrar/forms/domain.py +++ b/src/registrar/forms/domain.py @@ -190,7 +190,7 @@ class ContactForm(forms.ModelForm): self.fields["email"].error_messages = { "required": "Enter your email address in the required format, like name@example.com." } - self.fields["phone"].error_messages = {"required": "Enter your phone number."} + self.fields["phone"].error_messages["required"] = "Enter your phone number." class AuthorizingOfficialContactForm(ContactForm): @@ -213,7 +213,7 @@ class AuthorizingOfficialContactForm(ContactForm): self.fields["email"].error_messages = { "required": "Enter an email address in the required format, like name@example.com." } - self.fields["phone"].error_messages = {"required": "Enter a phone number for your authorizing official."} + self.fields["phone"].error_messages["required"] = "Enter a phone number for your authorizing official." class DomainSecurityEmailForm(forms.Form): From 96ab2bc75825c41fdb9cbc6e825ae92703beeea3 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 13:47:55 -0700 Subject: [PATCH 179/245] Add readme instructions --- docs/developer/README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/developer/README.md b/docs/developer/README.md index 9cfdb2149..5595b627b 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -295,7 +295,7 @@ sudo sntp -sS time.nist.gov ``` ## Connection pool -To handle our connection to the registry, we utilize a connection pool to keep a socket open to increase responsiveness. In order to accomplish this, we are utilizing a heavily modified version of the (geventconnpool)[https://github.com/rasky/geventconnpool] library. +To handle our connection to the registry, we utilize a connection pool to keep a socket open to increase responsiveness. In order to accomplish this, we are utilizing a heavily modified version of the [geventconnpool](https://github.com/rasky/geventconnpool) library. ### Settings The config for the connection pool exists inside the `settings.py` file. @@ -319,4 +319,19 @@ Our connection pool has a built-in `pool_status` object which you can call at an 5. `print(registry.pool_status.connection_success)` * Should return true -If you have multiple instances (staging for example), then repeat commands 1-5 for each instance you want to test. \ No newline at end of file +If you have multiple instances (staging for example), then repeat commands 1-5 for each instance you want to test. + +## Adding a S3 instance to your sandbox +This can either be done through the CLI, or through the cloud.gov dashboard. Generally, it is better to do it through the dashboard as it handles app binding for you. + +To associate a S3 instance to your sandbox, follow these steps: +1. Navigate to https://dashboard.fr.cloud.gov/login +2. Select your sandbox from the `Applications` tab +3. Click `Services` on the application nav bar +4. Add a new service (plus symbol) +5. Click `Marketplace Service` +6. On the `Select the service` dropdown, select `s3` +7. Under the dropdown on `Select Plan`, select `basic-sandbox` +8. Under `Service Instance` enter `getgov-s3` for the name + +See this [resource](https://cloud.gov/docs/services/s3/) for information on associating an S3 instance with your sandbox through the CLI. \ No newline at end of file From 1770bd93294db178a563b876009c78cc89fcbabf Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:08:18 -0700 Subject: [PATCH 180/245] Allow analysts to view userdomainrole --- src/registrar/models/user_group.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/registrar/models/user_group.py b/src/registrar/models/user_group.py index cf261286e..e9db70380 100644 --- a/src/registrar/models/user_group.py +++ b/src/registrar/models/user_group.py @@ -61,6 +61,11 @@ class UserGroup(Group): "model": "website", "permissions": ["change_website"], }, + { + "app_label": "registrar", + "model": "userdomainrole", + "permissions": ["view_userdomainrole"], + }, ] # Avoid error: You can't execute queries until the end From 86bb3073d7e4df0e5ae83d7a1b7604ec188837f5 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:19:25 -0700 Subject: [PATCH 181/245] Fix test --- src/registrar/tests/test_migrations.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/registrar/tests/test_migrations.py b/src/registrar/tests/test_migrations.py index 59e724387..22b0ed509 100644 --- a/src/registrar/tests/test_migrations.py +++ b/src/registrar/tests/test_migrations.py @@ -42,6 +42,7 @@ class TestGroups(TestCase): "analyst_access_permission", "change_user", "change_website", + "view_userdomainrole" ] # Get the codenames of actual permissions associated with the group From 23a208d2aa8f7646218fe3a8f401ec82eb5b1577 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:24:19 -0700 Subject: [PATCH 182/245] Update test_migrations.py --- src/registrar/tests/test_migrations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/tests/test_migrations.py b/src/registrar/tests/test_migrations.py index 22b0ed509..05fc8fb17 100644 --- a/src/registrar/tests/test_migrations.py +++ b/src/registrar/tests/test_migrations.py @@ -41,8 +41,8 @@ class TestGroups(TestCase): "change_draftdomain", "analyst_access_permission", "change_user", - "change_website", - "view_userdomainrole" + "view_userdomainrole", + "change_website" ] # Get the codenames of actual permissions associated with the group From 1e48c0b222ce982b67c4e465a90b2775fc73ac09 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:35:53 -0700 Subject: [PATCH 183/245] Add delete role --- src/registrar/models/user_group.py | 2 +- src/registrar/tests/test_migrations.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/registrar/models/user_group.py b/src/registrar/models/user_group.py index e9db70380..0f12a2e84 100644 --- a/src/registrar/models/user_group.py +++ b/src/registrar/models/user_group.py @@ -64,7 +64,7 @@ class UserGroup(Group): { "app_label": "registrar", "model": "userdomainrole", - "permissions": ["view_userdomainrole"], + "permissions": ["view_userdomainrole", "delete_userdomainrole"], }, ] diff --git a/src/registrar/tests/test_migrations.py b/src/registrar/tests/test_migrations.py index 05fc8fb17..69040fe0e 100644 --- a/src/registrar/tests/test_migrations.py +++ b/src/registrar/tests/test_migrations.py @@ -41,6 +41,7 @@ class TestGroups(TestCase): "change_draftdomain", "analyst_access_permission", "change_user", + "delete_userdomainrole", "view_userdomainrole", "change_website" ] From f0d0188c532f9f02f923e813d86e5734f850c69b Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 14:39:54 -0700 Subject: [PATCH 184/245] Linting --- src/registrar/tests/test_migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/tests/test_migrations.py b/src/registrar/tests/test_migrations.py index 69040fe0e..cc9d379e5 100644 --- a/src/registrar/tests/test_migrations.py +++ b/src/registrar/tests/test_migrations.py @@ -43,7 +43,7 @@ class TestGroups(TestCase): "change_user", "delete_userdomainrole", "view_userdomainrole", - "change_website" + "change_website", ] # Get the codenames of actual permissions associated with the group From d2701cc18da9911f5f776abb3b470251f08c9bba Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 15:15:12 -0700 Subject: [PATCH 185/245] Add better comments --- .../generate_current_federal_report.py | 5 +- .../commands/generate_current_full_report.py | 5 +- src/registrar/utility/s3_bucket.py | 70 +++++++++++++++++-- 3 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/registrar/management/commands/generate_current_federal_report.py b/src/registrar/management/commands/generate_current_federal_report.py index 478265ca0..1a123bf5b 100644 --- a/src/registrar/management/commands/generate_current_federal_report.py +++ b/src/registrar/management/commands/generate_current_federal_report.py @@ -11,7 +11,10 @@ logger = logging.getLogger(__name__) class Command(BaseCommand): - help = "" + help = ( + "Generates and uploads a current-federal.csv file to our S3 bucket " + "which is based off of all existing federal Domains." + ) def add_arguments(self, parser): """Add our two filename arguments.""" diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index c41c697a1..7cf6fbb5a 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -11,7 +11,10 @@ logger = logging.getLogger(__name__) class Command(BaseCommand): - help = "" + help = ( + "Generates and uploads a current-full.csv file to our S3 bucket " + "which is based off of all existing Domains." + ) def add_arguments(self, parser): """Add our two filename arguments.""" diff --git a/src/registrar/utility/s3_bucket.py b/src/registrar/utility/s3_bucket.py index 162be37c9..f4e44b0b9 100644 --- a/src/registrar/utility/s3_bucket.py +++ b/src/registrar/utility/s3_bucket.py @@ -22,7 +22,17 @@ class S3ClientErrorCodes(IntEnum): class S3ClientError(RuntimeError): - """Local error for handling all failures with boto3.client""" + """ + Custom exception class for handling errors related to interactions with the S3 storage service via boto3.client. + + This class maps error codes to human-readable error messages. When an instance of S3ClientError is created, + an error code can be passed in to set the error message for that instance. + + Attributes: + _error_mapping: A dictionary mapping error codes to error messages. + code: The error code for a specific instance of S3ClientError. + message: The error message for a specific instance of S3ClientError, determined by the error code. + """ _error_mapping = { S3ClientErrorCodes.ACCESS_S3_CLIENT_ERROR: "Failed to establish a connection with the storage service.", @@ -44,7 +54,15 @@ class S3ClientError(RuntimeError): class S3ClientHelper: - """Helper class that simplifies S3 intialization""" + """ + A helper class for interacting with Amazon S3 via the boto3 client. + + This class simplifies the process of initializing the boto3 client, + uploading files to S3, and retrieving files from S3. + + Attributes: + boto_client: The boto3 client used to interact with S3. + """ def __init__(self): try: @@ -59,11 +77,35 @@ class S3ClientHelper: raise S3ClientError(code=S3ClientErrorCodes.ACCESS_S3_CLIENT_ERROR) from exc def get_bucket_name(self): - """Gets the name of our S3 Bucket""" + """ + Retrieves the name of the S3 bucket. + + This method returns the name of the S3 bucket as defined in the application's settings. + + Returns: + str: The name of the S3 bucket. + """ + return settings.AWS_S3_BUCKET_NAME def upload_file(self, file_path, file_name): - """Uploads a file to our S3 instance""" + """ + Uploads a file to the S3 bucket. + + This method attempts to upload a file to the S3 bucket using the boto3 client. + If an exception occurs during the upload process, it raises an S3ClientError with an UPLOAD_FILE_ERROR code. + + Args: + file_path (str): The path of the file to upload. + file_name (str): The name to give to the file in the S3 bucket. + + Returns: + dict: The response from the boto3 client's upload_file method. + + Raises: + S3ClientError: If the file cannot be uploaded to the S3 bucket. + """ + try: response = self.boto_client.upload_file(file_path, self.get_bucket_name(), file_name) except Exception as exc: @@ -71,7 +113,25 @@ class S3ClientHelper: return response def get_file(self, file_name, decode_to_utf=False): - """Gets a file to our S3 instance and returns the file content""" + """ + Retrieves a file from the S3 bucket and returns its content. + + This method attempts to retrieve a file from the S3 bucket using the boto3 client. + If the file is not found, it raises an S3ClientError with a FILE_NOT_FOUND_ERROR code. + For any other exceptions during the retrieval process, it raises an S3ClientError with a GET_FILE_ERROR code. + + Args: + file_name (str): The name of the file to retrieve from the S3 bucket. + decode_to_utf (bool, optional): If True, the file content is decoded from bytes to a UTF-8 string. + Defaults to False. + + Returns: + bytes or str: The content of the file. If decode_to_utf is True, this is a string. Otherwise, its bytes. + + Raises: + S3ClientError: If the file cannot be retrieved from the S3 bucket. + """ + try: response = self.boto_client.get_object(Bucket=self.get_bucket_name(), Key=file_name) except ClientError as exc: From a2bcc8b9c06efec1bd6c97ed70ce3a7e3363cfc4 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Fri, 1 Dec 2023 15:20:26 -0700 Subject: [PATCH 186/245] Linting pt. 2 --- .../management/commands/generate_current_full_report.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/registrar/management/commands/generate_current_full_report.py b/src/registrar/management/commands/generate_current_full_report.py index 7cf6fbb5a..80c031605 100644 --- a/src/registrar/management/commands/generate_current_full_report.py +++ b/src/registrar/management/commands/generate_current_full_report.py @@ -12,8 +12,7 @@ logger = logging.getLogger(__name__) class Command(BaseCommand): help = ( - "Generates and uploads a current-full.csv file to our S3 bucket " - "which is based off of all existing Domains." + "Generates and uploads a current-full.csv file to our S3 bucket " "which is based off of all existing Domains." ) def add_arguments(self, parser): From 1c657a770485b9528fa7f24fab0af86912ab1460 Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Fri, 1 Dec 2023 18:01:02 -0500 Subject: [PATCH 187/245] Rough JS for adding then enabling/disabling the related widget buttons on the horizontal multi-select --- src/registrar/admin.py | 20 +++ src/registrar/assets/js/get-gov-admin.js | 162 +++++++++++++++++- src/registrar/templates/admin/base_site.html | 1 + .../django/admin/domain_change_form.html | 5 - 4 files changed, 182 insertions(+), 6 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index e8eb206c2..493bc90cd 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -455,7 +455,16 @@ class DomainInformationAdmin(ListHeaderAdmin): "is_policy_acknowledged", ] + # For each filter_horizontal, init in admin js extendFilterHorizontalWidgets + # to activate the edit/delete/view buttons filter_horizontal = ("other_contacts",) + + # lists in filter_horizontal are not sorted properly, sort them + # by first_name + def formfield_for_manytomany(self, db_field, request, **kwargs): + if db_field.name in ("other_contacts",): + kwargs["queryset"] = models.Contact.objects.all().order_by("first_name") # Sort contacts + return super().formfield_for_manytomany(db_field, request, **kwargs) def get_readonly_fields(self, request, obj=None): """Set the read-only state on form elements. @@ -593,6 +602,8 @@ class DomainApplicationAdmin(ListHeaderAdmin): "is_policy_acknowledged", ] + # For each filter_horizontal, init in admin js extendFilterHorizontalWidgets + # to activate the edit/delete/view buttons filter_horizontal = ("current_websites", "alternative_domains") # lists in filter_horizontal are not sorted properly, sort them @@ -730,7 +741,16 @@ class DomainInformationInline(admin.StackedInline): fieldsets = DomainInformationAdmin.fieldsets analyst_readonly_fields = DomainInformationAdmin.analyst_readonly_fields + # For each filter_horizontal, init in admin js extendFilterHorizontalWidgets + # to activate the edit/delete/view buttons filter_horizontal = ("other_contacts",) + + # lists in filter_horizontal are not sorted properly, sort them + # by first_name + def formfield_for_manytomany(self, db_field, request, **kwargs): + if db_field.name in ("other_contacts",): + kwargs["queryset"] = models.Contact.objects.all().order_by("first_name") # Sort contacts + return super().formfield_for_manytomany(db_field, request, **kwargs) def get_readonly_fields(self, request, obj=None): return DomainInformationAdmin.get_readonly_fields(self, request, obj=None) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 3b9f19a49..1e3f53563 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -47,4 +47,164 @@ function openInNewTab(el, removeAttribute = false){ } prepareDjangoAdmin(); -})(); \ No newline at end of file +})(); + +/** + * An IIFE to listen to changes on filter_horizontal and enable or disable the change/delete/view buttons as applicable + * + */ +(function extendFilterHorizontalWidgets() { + // Grab a list of our custom filter_horizontal widgets + let filterHorizontalList = []; + checkElementThenAddToList('id_other_contacts_to', filterHorizontalList, 0); + checkElementThenAddToList('id_domain_info-0-other_contacts_to', filterHorizontalList, 0); + checkElementThenAddToList('id_current_websites_to', filterHorizontalList, 0); + checkElementThenAddToList('id_alternative_domains_to', filterHorizontalList, 0); +})(); + +// Function to check for the existence of the element +function checkElementThenAddToList(id, listOfElements, attempts) { + let dynamicElement = document.getElementById(id); + attempts++; + + if (attempts < 6) { + if ((dynamicElement !== null)) { + // Element found, handle it + // Add an event listener on the element + // Add disabled buttons on the element's great-grandparent + customizeSelectElement(dynamicElement, id); + } else { + // Element not found, check again after a delay + setTimeout(() => checkElementThenAddToList(id, listOfElements, attempts), 1000); // Check every 1000 milliseconds (1 second) + } + } +} + +function createAndCustomizeLink(selectEl, selectElId, className, title, imgSrc, imgAlt, dataMappings, dataPopup, position) { + // Create a link element + var link = document.createElement('a'); + + // Set class attribute for the link + link.className = className; + + // Set id + // Add 'change_' to the beginning of the string + let modifiedLinkString = className.split('-')[0] + '_' + selectElId; + // Remove '_to' from the end of the string + modifiedLinkString = modifiedLinkString.replace('_to', ''); + link.id = modifiedLinkString; + + // Set data-href-template + for (const [idPattern, template] of Object.entries(dataMappings)) { + if (selectElId.includes(idPattern)) { + link.setAttribute('data-href-template', template); + break; // Stop checking once a match is found + } + } + + if (dataPopup) + link.setAttribute('data-popup', 'yes'); + + link.title = title; + + // Create an 'img' element + var img = document.createElement('img'); + + // Set attributes for the new image + img.src = imgSrc; + img.alt = imgAlt; + + // Append the image to the link + link.appendChild(img); + + // Insert the link at the specified position + selectEl.closest('.related-widget-wrapper').insertBefore(link, selectEl.closest('.related-widget-wrapper').children[position]); + + // Return the link, which we'll use in the disable and enable functions + return link; +} + +function customizeSelectElement(el, elId) { + let changeLink = createAndCustomizeLink( + el, + elId, + 'related-widget-wrapper-link change-related', + 'Change selected item', + '/public/admin/img/icon-changelink.svg', + 'Change', + { + 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id&_popup=1', + 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id&_popup=1', + 'alternative_domains': '/admin/registrar/draftdomain/__fk__/change/?_to_field=id&_popup=1', + }, + true, + 0 + ); + + let deleteLink = createAndCustomizeLink( + el, + elId, + 'related-widget-wrapper-link delete-related', + 'Delete selected item', + '/public/admin/img/icon-deletelink.svg', + 'Delete', + { + 'contacts': '/admin/registrar/contact/__fk__/delete/?_to_field=id&_popup=1', + 'websites': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', + 'alternative_domains': '/admin/registrar/draftdomain/__fk__/delete/?_to_field=id&_popup=1', + }, + true, + 2 + ); + + let viewLink = createAndCustomizeLink( + el, + elId, + 'related-widget-wrapper-link view-related', + 'View selected item', + '/public/admin/img/icon-viewlink.svg', + 'View', + { + 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id', + 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id', + 'alternative_domains': '/admin/registrar/draftdomain/__fk__/change/?_to_field=id', + }, + false, + 3 + ); + + el.addEventListener('click', function(event) { + // Access the target element that was clicked + var clickedElement = event.target; + + // If one item is selected enable buttons, otherwise disable them + if (el.selectedOptions.length === 1) { + enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, clickedElement.value); + } else { + disableRelatedWidgetButtons(changeLink, deleteLink, viewLink); + } + + }); + + // Disable buttons when the selectors are interated with (items are moved from one column to the other) + let selectorButtons = []; + selectorButtons.push(el.closest(".selector").querySelector(".selector-chooseall")); + selectorButtons.push(el.closest(".selector").querySelector(".selector-add")); + selectorButtons.push(el.closest(".selector").querySelector(".selector-remove")); + + selectorButtons.forEach((selector) => { + selector.addEventListener("click", ()=>{disableRelatedWidgetButtons(changeLink, deleteLink, viewLink)}); + }); +} + +function disableRelatedWidgetButtons(changeLink, deleteLink, viewLink) { + changeLink.removeAttribute('href'); + deleteLink.removeAttribute('href'); + viewLink.removeAttribute('href'); +} + +function enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, elementPk) { + changeLink.setAttribute('href', changeLink.getAttribute('data-href-template').replace('__fk__', elementPk)); + deleteLink.setAttribute('href', deleteLink.getAttribute('data-href-template').replace('__fk__', elementPk)); + viewLink.setAttribute('href', viewLink.getAttribute('data-href-template').replace('__fk__', elementPk)); +} diff --git a/src/registrar/templates/admin/base_site.html b/src/registrar/templates/admin/base_site.html index dcdd29e2f..c0884c912 100644 --- a/src/registrar/templates/admin/base_site.html +++ b/src/registrar/templates/admin/base_site.html @@ -18,6 +18,7 @@ + {% endblock %} {% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} diff --git a/src/registrar/templates/django/admin/domain_change_form.html b/src/registrar/templates/django/admin/domain_change_form.html index 6c401ad72..c4461d07f 100644 --- a/src/registrar/templates/django/admin/domain_change_form.html +++ b/src/registrar/templates/django/admin/domain_change_form.html @@ -1,11 +1,6 @@ {% extends 'admin/change_form.html' %} {% load i18n static %} -{% block extrahead %} -{{ block.super }} - -{% endblock %} - {% block field_sets %}
From 7d36e4399ea6e8bc66c006b0fd140fff77b03b27 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Fri, 1 Dec 2023 18:53:52 -0500 Subject: [PATCH 188/245] format for linting --- src/registrar/admin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 285de25a5..f79e709fb 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -458,7 +458,7 @@ class DomainInformationAdmin(ListHeaderAdmin): # For each filter_horizontal, init in admin js extendFilterHorizontalWidgets # to activate the edit/delete/view buttons filter_horizontal = ("other_contacts",) - + # lists in filter_horizontal are not sorted properly, sort them # by first_name def formfield_for_manytomany(self, db_field, request, **kwargs): @@ -742,7 +742,7 @@ class DomainInformationInline(admin.StackedInline): # For each filter_horizontal, init in admin js extendFilterHorizontalWidgets # to activate the edit/delete/view buttons filter_horizontal = ("other_contacts",) - + # lists in filter_horizontal are not sorted properly, sort them # by first_name def formfield_for_manytomany(self, db_field, request, **kwargs): From 4e684a7cad88151267c83841b528ab3937c31fd8 Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Mon, 4 Dec 2023 10:24:21 -0500 Subject: [PATCH 189/245] Add a click listener on the 'from' list --- src/registrar/assets/js/get-gov-admin.js | 149 ++++++++++++----------- 1 file changed, 79 insertions(+), 70 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 1e3f53563..37b0f4900 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -80,6 +80,76 @@ function checkElementThenAddToList(id, listOfElements, attempts) { } } +function customizeSelectElement(el, elId) { + let changeLink = createAndCustomizeLink( + el, + elId, + 'related-widget-wrapper-link change-related', + 'Change selected item', + '/public/admin/img/icon-changelink.svg', + 'Change', + { + 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id&_popup=1', + 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id&_popup=1', + 'alternative_domains': '/admin/registrar/website/__fk__/change/?_to_field=id&_popup=1', + }, + true, + 0 + ); + + let deleteLink = createAndCustomizeLink( + el, + elId, + 'related-widget-wrapper-link delete-related', + 'Delete selected item', + '/public/admin/img/icon-deletelink.svg', + 'Delete', + { + 'contacts': '/admin/registrar/contact/__fk__/delete/?_to_field=id&_popup=1', + 'websites': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', + 'alternative_domains': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', + }, + true, + 2 + ); + + let viewLink = createAndCustomizeLink( + el, + elId, + 'related-widget-wrapper-link view-related', + 'View selected item', + '/public/admin/img/icon-viewlink.svg', + 'View', + { + 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id', + 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id', + 'alternative_domains': '/admin/registrar/website/__fk__/change/?_to_field=id', + }, + false, + 3 + ); + + let fromList = el.closest('.selector').querySelector(".selector-available select"); + + fromList.addEventListener('click', function(event) { + handleSelectClick(event, fromList, changeLink, deleteLink, viewLink); + }); + + el.addEventListener('click', function(event) { + handleSelectClick(event, el, changeLink, deleteLink, viewLink); + }); + + // Disable buttons when the selectors are interated with (items are moved from one column to the other) + let selectorButtons = []; + selectorButtons.push(el.closest(".selector").querySelector(".selector-chooseall")); + selectorButtons.push(el.closest(".selector").querySelector(".selector-add")); + selectorButtons.push(el.closest(".selector").querySelector(".selector-remove")); + + selectorButtons.forEach((selector) => { + selector.addEventListener("click", ()=>{disableRelatedWidgetButtons(changeLink, deleteLink, viewLink)}); + }); +} + function createAndCustomizeLink(selectEl, selectElId, className, title, imgSrc, imgAlt, dataMappings, dataPopup, position) { // Create a link element var link = document.createElement('a'); @@ -124,77 +194,16 @@ function createAndCustomizeLink(selectEl, selectElId, className, title, imgSrc, return link; } -function customizeSelectElement(el, elId) { - let changeLink = createAndCustomizeLink( - el, - elId, - 'related-widget-wrapper-link change-related', - 'Change selected item', - '/public/admin/img/icon-changelink.svg', - 'Change', - { - 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id&_popup=1', - 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id&_popup=1', - 'alternative_domains': '/admin/registrar/draftdomain/__fk__/change/?_to_field=id&_popup=1', - }, - true, - 0 - ); +function handleSelectClick(event, selectElement, changeLink, deleteLink, viewLink) { + // Access the target element that was clicked + var clickedElement = event.target; - let deleteLink = createAndCustomizeLink( - el, - elId, - 'related-widget-wrapper-link delete-related', - 'Delete selected item', - '/public/admin/img/icon-deletelink.svg', - 'Delete', - { - 'contacts': '/admin/registrar/contact/__fk__/delete/?_to_field=id&_popup=1', - 'websites': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', - 'alternative_domains': '/admin/registrar/draftdomain/__fk__/delete/?_to_field=id&_popup=1', - }, - true, - 2 - ); - - let viewLink = createAndCustomizeLink( - el, - elId, - 'related-widget-wrapper-link view-related', - 'View selected item', - '/public/admin/img/icon-viewlink.svg', - 'View', - { - 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id', - 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id', - 'alternative_domains': '/admin/registrar/draftdomain/__fk__/change/?_to_field=id', - }, - false, - 3 - ); - - el.addEventListener('click', function(event) { - // Access the target element that was clicked - var clickedElement = event.target; - - // If one item is selected enable buttons, otherwise disable them - if (el.selectedOptions.length === 1) { - enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, clickedElement.value); - } else { - disableRelatedWidgetButtons(changeLink, deleteLink, viewLink); - } - - }); - - // Disable buttons when the selectors are interated with (items are moved from one column to the other) - let selectorButtons = []; - selectorButtons.push(el.closest(".selector").querySelector(".selector-chooseall")); - selectorButtons.push(el.closest(".selector").querySelector(".selector-add")); - selectorButtons.push(el.closest(".selector").querySelector(".selector-remove")); - - selectorButtons.forEach((selector) => { - selector.addEventListener("click", ()=>{disableRelatedWidgetButtons(changeLink, deleteLink, viewLink)}); - }); + // If one item is selected, enable buttons; otherwise, disable them + if (selectElement.selectedOptions.length === 1) { + enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, clickedElement.value); + } else { + disableRelatedWidgetButtons(changeLink, deleteLink, viewLink); + } } function disableRelatedWidgetButtons(changeLink, deleteLink, viewLink) { From 6eabb824ea98bbadee6a4cdf2ad19cf26d8bc6ce Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 11:13:17 -0500 Subject: [PATCH 190/245] update to check both lists when enabling/disabling buttons --- src/registrar/assets/js/get-gov-admin.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 37b0f4900..ea357ed7d 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -132,11 +132,11 @@ function customizeSelectElement(el, elId) { let fromList = el.closest('.selector').querySelector(".selector-available select"); fromList.addEventListener('click', function(event) { - handleSelectClick(event, fromList, changeLink, deleteLink, viewLink); + handleSelectClick(event, fromList, el, changeLink, deleteLink, viewLink); }); el.addEventListener('click', function(event) { - handleSelectClick(event, el, changeLink, deleteLink, viewLink); + handleSelectClick(event, el, fromList, changeLink, deleteLink, viewLink); }); // Disable buttons when the selectors are interated with (items are moved from one column to the other) @@ -194,12 +194,12 @@ function createAndCustomizeLink(selectEl, selectElId, className, title, imgSrc, return link; } -function handleSelectClick(event, selectElement, changeLink, deleteLink, viewLink) { +function handleSelectClick(event, selectElement, relatedSelectElement, changeLink, deleteLink, viewLink) { // Access the target element that was clicked var clickedElement = event.target; // If one item is selected, enable buttons; otherwise, disable them - if (selectElement.selectedOptions.length === 1) { + if (selectElement.selectedOptions.length + relatedSelectElement.selectedOptions.length === 1) { enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, clickedElement.value); } else { disableRelatedWidgetButtons(changeLink, deleteLink, viewLink); From 1859d56ddf5b3f9937adac74cd001f67e92b0917 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 4 Dec 2023 09:19:42 -0700 Subject: [PATCH 191/245] Update test_reports.py --- src/registrar/tests/test_reports.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/tests/test_reports.py b/src/registrar/tests/test_reports.py index 266f7c799..b94316248 100644 --- a/src/registrar/tests/test_reports.py +++ b/src/registrar/tests/test_reports.py @@ -85,7 +85,7 @@ class CsvReportsTest(TestCase): with patch("builtins.open", fake_open): call_command("generate_current_federal_report", checkpath=False) content = fake_open() - # Now you can make assertions about how you expect 'file' to be used. + content.write.assert_has_calls(expected_file_content) @boto3_mocking.patching @@ -105,7 +105,7 @@ class CsvReportsTest(TestCase): with patch("builtins.open", fake_open): call_command("generate_current_full_report", checkpath=False) content = fake_open() - # Now you can make assertions about how you expect 'file' to be used. + content.write.assert_has_calls(expected_file_content) @boto3_mocking.patching From 55d5fce00492e2aad65450e68c590d17c443e603 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 12:22:04 -0500 Subject: [PATCH 192/245] updates for dealing with multiple selects together --- src/registrar/assets/js/get-gov-admin.js | 97 +++++++++++++++--------- 1 file changed, 62 insertions(+), 35 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index ea357ed7d..12f3f24e1 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -54,36 +54,42 @@ function openInNewTab(el, removeAttribute = false){ * */ (function extendFilterHorizontalWidgets() { - // Grab a list of our custom filter_horizontal widgets - let filterHorizontalList = []; - checkElementThenAddToList('id_other_contacts_to', filterHorizontalList, 0); - checkElementThenAddToList('id_domain_info-0-other_contacts_to', filterHorizontalList, 0); - checkElementThenAddToList('id_current_websites_to', filterHorizontalList, 0); - checkElementThenAddToList('id_alternative_domains_to', filterHorizontalList, 0); + // Initialize custom filter_horizontal widgets; each widget has a "from" select list + // and a "to" select list; initialization is based off of the presence of the + // "to" select list + checkToListThenInitWidget('id_other_contacts_to', 0); + checkToListThenInitWidget('id_domain_info-0-other_contacts_to', 0); + checkToListThenInitWidget('id_current_websites_to', 0); + checkToListThenInitWidget('id_alternative_domains_to', 0); })(); -// Function to check for the existence of the element -function checkElementThenAddToList(id, listOfElements, attempts) { - let dynamicElement = document.getElementById(id); +// Function to check for the existence of the "to" select list element in the DOM, and if and when found, +// initialize the associated widget +function checkToListThenInitWidget(toListId, attempts) { + let toList = document.getElementById(toListId); attempts++; if (attempts < 6) { - if ((dynamicElement !== null)) { - // Element found, handle it + if ((toList !== null)) { + // toList found, handle it // Add an event listener on the element // Add disabled buttons on the element's great-grandparent - customizeSelectElement(dynamicElement, id); + initializeWidgetOnToList(toList, toListId); } else { // Element not found, check again after a delay - setTimeout(() => checkElementThenAddToList(id, listOfElements, attempts), 1000); // Check every 1000 milliseconds (1 second) + setTimeout(() => checkToListThenInitWidget(toListId, attempts), 1000); // Check every 1000 milliseconds (1 second) } } } -function customizeSelectElement(el, elId) { +// Initialize the widget: +// add related buttons to the widget for edit, delete and view +// add event listeners on the from list, the to list, and selector buttons which either enable or disable the related buttons +function initializeWidgetOnToList(toList, toListId) { + // create the change button let changeLink = createAndCustomizeLink( - el, - elId, + toList, + toListId, 'related-widget-wrapper-link change-related', 'Change selected item', '/public/admin/img/icon-changelink.svg', @@ -97,9 +103,10 @@ function customizeSelectElement(el, elId) { 0 ); + // create the delete button let deleteLink = createAndCustomizeLink( - el, - elId, + toList, + toListId, 'related-widget-wrapper-link delete-related', 'Delete selected item', '/public/admin/img/icon-deletelink.svg', @@ -113,9 +120,10 @@ function customizeSelectElement(el, elId) { 2 ); + // create the view button let viewLink = createAndCustomizeLink( - el, - elId, + toList, + toListId, 'related-widget-wrapper-link view-related', 'View selected item', '/public/admin/img/icon-viewlink.svg', @@ -129,28 +137,38 @@ function customizeSelectElement(el, elId) { 3 ); - let fromList = el.closest('.selector').querySelector(".selector-available select"); + // identify the fromList element in the DOM + let fromList = toList.closest('.selector').querySelector(".selector-available select"); fromList.addEventListener('click', function(event) { - handleSelectClick(event, fromList, el, changeLink, deleteLink, viewLink); + handleSelectClick(event, fromList, toList, changeLink, deleteLink, viewLink); }); - el.addEventListener('click', function(event) { - handleSelectClick(event, el, fromList, changeLink, deleteLink, viewLink); + toList.addEventListener('click', function(event) { + handleSelectClick(event, toList, fromList, changeLink, deleteLink, viewLink); }); - // Disable buttons when the selectors are interated with (items are moved from one column to the other) + // Disable buttons when the selectors are interacted with (items are moved from one column to the other) let selectorButtons = []; - selectorButtons.push(el.closest(".selector").querySelector(".selector-chooseall")); - selectorButtons.push(el.closest(".selector").querySelector(".selector-add")); - selectorButtons.push(el.closest(".selector").querySelector(".selector-remove")); + selectorButtons.push(toList.closest(".selector").querySelector(".selector-chooseall")); + selectorButtons.push(toList.closest(".selector").querySelector(".selector-add")); + selectorButtons.push(toList.closest(".selector").querySelector(".selector-remove")); selectorButtons.forEach((selector) => { selector.addEventListener("click", ()=>{disableRelatedWidgetButtons(changeLink, deleteLink, viewLink)}); }); } -function createAndCustomizeLink(selectEl, selectElId, className, title, imgSrc, imgAlt, dataMappings, dataPopup, position) { +// create and customize the button, then add to the DOM, relative to the toList +// toList - the element in the DOM for the toList +// toListId - the ID of the element in the DOM +// className - className to add to the created link +// imgSrc - the img.src for the created link +// imgAlt - the img.alt for the created link +// dataMappings - dictionary which relates toListId to href for the created link +// dataPopup - boolean for whether the link should produce a popup window +// position - the position of the button in the list of buttons in the related-widget-wrapper in the widget +function createAndCustomizeLink(toList, toListId, className, title, imgSrc, imgAlt, dataMappings, dataPopup, position) { // Create a link element var link = document.createElement('a'); @@ -158,15 +176,16 @@ function createAndCustomizeLink(selectEl, selectElId, className, title, imgSrc, link.className = className; // Set id - // Add 'change_' to the beginning of the string - let modifiedLinkString = className.split('-')[0] + '_' + selectElId; + // Determine function {change, link, view} from the className + // Add {function}_ to the beginning of the string + let modifiedLinkString = className.split('-')[0] + '_' + toListId; // Remove '_to' from the end of the string modifiedLinkString = modifiedLinkString.replace('_to', ''); link.id = modifiedLinkString; // Set data-href-template for (const [idPattern, template] of Object.entries(dataMappings)) { - if (selectElId.includes(idPattern)) { + if (toListId.includes(idPattern)) { link.setAttribute('data-href-template', template); break; // Stop checking once a match is found } @@ -188,19 +207,27 @@ function createAndCustomizeLink(selectEl, selectElId, className, title, imgSrc, link.appendChild(img); // Insert the link at the specified position - selectEl.closest('.related-widget-wrapper').insertBefore(link, selectEl.closest('.related-widget-wrapper').children[position]); + toList.closest('.related-widget-wrapper').insertBefore(link, toList.closest('.related-widget-wrapper').children[position]); // Return the link, which we'll use in the disable and enable functions return link; } +// Either enable or disable widget buttons when select is clicked. Select can be in either the from list +// or the to list. Action (enable or disable) taken depends on the tocal count of selected items across +// both lists. If exactly one item is selected, buttons are enabled, and urls for the buttons associated +// with the selected item function handleSelectClick(event, selectElement, relatedSelectElement, changeLink, deleteLink, viewLink) { // Access the target element that was clicked var clickedElement = event.target; - // If one item is selected, enable buttons; otherwise, disable them + // If one item is selected (across selectElement and relatedSelectElement), enable buttons; otherwise, disable them if (selectElement.selectedOptions.length + relatedSelectElement.selectedOptions.length === 1) { - enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, clickedElement.value); + if (selectElement.selectedOptions.length) { + enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, selectElement.selectedOptions[0].value); + } else { + enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, relatedSelectElement.selectedOptions[0].value); + } } else { disableRelatedWidgetButtons(changeLink, deleteLink, viewLink); } From 15489a71e2511a94f9a7cf1a9c2e902d58151c71 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 12:23:41 -0500 Subject: [PATCH 193/245] small refinement in handleSelectClick --- src/registrar/assets/js/get-gov-admin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 12f3f24e1..6a5d0a206 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -218,14 +218,14 @@ function createAndCustomizeLink(toList, toListId, className, title, imgSrc, imgA // both lists. If exactly one item is selected, buttons are enabled, and urls for the buttons associated // with the selected item function handleSelectClick(event, selectElement, relatedSelectElement, changeLink, deleteLink, viewLink) { - // Access the target element that was clicked - var clickedElement = event.target; // If one item is selected (across selectElement and relatedSelectElement), enable buttons; otherwise, disable them if (selectElement.selectedOptions.length + relatedSelectElement.selectedOptions.length === 1) { if (selectElement.selectedOptions.length) { + // enable buttons for selected item in selectElement enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, selectElement.selectedOptions[0].value); } else { + // enable buttons for selected item in relatedSelectElement enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, relatedSelectElement.selectedOptions[0].value); } } else { From ff446aa56a67c91871945af968041acaf90d2c8e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:29:49 -0700 Subject: [PATCH 194/245] Add instructions for .env --- docs/developer/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/developer/README.md b/docs/developer/README.md index 5595b627b..57985d6e2 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -334,4 +334,21 @@ To associate a S3 instance to your sandbox, follow these steps: 7. Under the dropdown on `Select Plan`, select `basic-sandbox` 8. Under `Service Instance` enter `getgov-s3` for the name -See this [resource](https://cloud.gov/docs/services/s3/) for information on associating an S3 instance with your sandbox through the CLI. \ No newline at end of file +See this [resource](https://cloud.gov/docs/services/s3/) for information on associating an S3 instance with your sandbox through the CLI. + +### Testing your S3 instance locally +To test the S3 bucket associated with your sandbox, you will need to add four additional variables to your `.env` file. These are as follows: + +``` +AWS_S3_ACCESS_KEY_ID = "{string value of `access_key_id` in getgov-s3}" +AWS_S3_SECRET_ACCESS_KEY = "{string value of `secret_access_key` in getgov-s3}" +AWS_S3_REGION = "{string value of `region` in getgov-s3}" +AWS_S3_BUCKET_NAME = "{string value of `bucket` in getgov-s3}" +``` + +You can view these variables by running the following command: +``` +cf env getgov-{app name} +``` + +Then, copy the variables under the section labled `s3`. \ No newline at end of file From f5edd64c92d89801b87cb6afd84d090deaa3709c Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 4 Dec 2023 11:35:31 -0800 Subject: [PATCH 195/245] Move manage your domain --- src/registrar/templates/base.html | 12 +++++++++++- src/registrar/templates/domain_base.html | 10 ---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html index caecee9f3..6179798b8 100644 --- a/src/registrar/templates/base.html +++ b/src/registrar/templates/base.html @@ -148,8 +148,18 @@ + + + + Manage your domains + + + + + + {% endblock %}
diff --git a/src/registrar/templates/domain_base.html b/src/registrar/templates/domain_base.html index b5f70d341..530f97e66 100644 --- a/src/registrar/templates/domain_base.html +++ b/src/registrar/templates/domain_base.html @@ -42,16 +42,6 @@

- {% else %} - - - -

- Back to manage your domains -

-
{% endif %} {# messages block is under the back breadcrumb link #} {% if messages %} From b0d95be7a27269afdb103cc13219cf8e605ee453 Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Mon, 4 Dec 2023 15:28:31 -0500 Subject: [PATCH 196/245] layout and CSS for the back to manage domains button --- src/registrar/assets/sass/_theme/_base.scss | 4 --- .../assets/sass/_theme/_buttons.scss | 11 ++++++++ .../assets/sass/_theme/_nav-primary.scss | 9 +++++++ src/registrar/assets/sass/_theme/styles.scss | 1 + src/registrar/templates/base.html | 27 ++++++++----------- 5 files changed, 32 insertions(+), 20 deletions(-) create mode 100644 src/registrar/assets/sass/_theme/_nav-primary.scss diff --git a/src/registrar/assets/sass/_theme/_base.scss b/src/registrar/assets/sass/_theme/_base.scss index 668a6ace6..b5efc63bd 100644 --- a/src/registrar/assets/sass/_theme/_base.scss +++ b/src/registrar/assets/sass/_theme/_base.scss @@ -37,10 +37,6 @@ body { @include typeset('sans', 'xl', 2); color: color('primary-darker'); } - -.usa-nav__primary { - margin-top: units(1); -} .section--outlined { background-color: color('white'); diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss index 02089ec6d..8e6aeef56 100644 --- a/src/registrar/assets/sass/_theme/_buttons.scss +++ b/src/registrar/assets/sass/_theme/_buttons.scss @@ -7,6 +7,17 @@ a[href$="todo"]::after { content: " [link TBD]"; font-style: italic; } + +a.manage_domain_back { + // Slight vertical and horizontal alignment fixes + position: relative; + top: -2px; + left: -5px; + font-weight: bold; + &:visited { + color: color('primary'); + } +} a.breadcrumb__back { display:flex; diff --git a/src/registrar/assets/sass/_theme/_nav-primary.scss b/src/registrar/assets/sass/_theme/_nav-primary.scss new file mode 100644 index 000000000..754abfa2e --- /dev/null +++ b/src/registrar/assets/sass/_theme/_nav-primary.scss @@ -0,0 +1,9 @@ +@use "uswds-core" as *; + +.usa-nav__primary { + margin-top: units(1); +} + +.usa-logo-group { + flex: 1 1 0%; +} diff --git a/src/registrar/assets/sass/_theme/styles.scss b/src/registrar/assets/sass/_theme/styles.scss index 8a2e1d2d3..32681f379 100644 --- a/src/registrar/assets/sass/_theme/styles.scss +++ b/src/registrar/assets/sass/_theme/styles.scss @@ -9,6 +9,7 @@ /*-------------------------------------------------- --- Custom Styles ---------------------------------*/ @forward "base"; +@forward "nav-primary"; @forward "typography"; @forward "buttons"; @forward "forms"; diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html index 6179798b8..03eec88ac 100644 --- a/src/registrar/templates/base.html +++ b/src/registrar/templates/base.html @@ -144,23 +144,18 @@
- {% block logo %} - - - - +
+ {% block logo %} + + {% endblock %} + Manage your domains - - - - - - - {% endblock %} + +
{% block usa_nav %} From 61e05a438b6a793651ea8a6f9f4bfdaf19d5a940 Mon Sep 17 00:00:00 2001 From: Rachid Mrad Date: Mon, 4 Dec 2023 15:33:46 -0500 Subject: [PATCH 197/245] Move manage button CSS from buttons to nav partial --- src/registrar/assets/sass/_theme/_buttons.scss | 11 ----------- src/registrar/assets/sass/_theme/_nav-primary.scss | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/registrar/assets/sass/_theme/_buttons.scss b/src/registrar/assets/sass/_theme/_buttons.scss index 8e6aeef56..02089ec6d 100644 --- a/src/registrar/assets/sass/_theme/_buttons.scss +++ b/src/registrar/assets/sass/_theme/_buttons.scss @@ -7,17 +7,6 @@ a[href$="todo"]::after { content: " [link TBD]"; font-style: italic; } - -a.manage_domain_back { - // Slight vertical and horizontal alignment fixes - position: relative; - top: -2px; - left: -5px; - font-weight: bold; - &:visited { - color: color('primary'); - } -} a.breadcrumb__back { display:flex; diff --git a/src/registrar/assets/sass/_theme/_nav-primary.scss b/src/registrar/assets/sass/_theme/_nav-primary.scss index 754abfa2e..72cf35b42 100644 --- a/src/registrar/assets/sass/_theme/_nav-primary.scss +++ b/src/registrar/assets/sass/_theme/_nav-primary.scss @@ -7,3 +7,14 @@ .usa-logo-group { flex: 1 1 0%; } + +a.manage_domain_back { + // Slight vertical and horizontal alignment fixes + position: relative; + top: -2px; + left: -5px; + font-weight: bold; + &:visited { + color: color('primary'); + } +} From ee9fc789c78852b5baf21c57c30f91dc99df0589 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 4 Dec 2023 13:46:38 -0700 Subject: [PATCH 198/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 3b9918713..2f703ae21 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,8 +2,6 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: - # pull_request will be removed when merged - pull_request: workflow_dispatch: inputs: environment: From 43448101077c18d799838816fd8ab84339c73a78 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 16:52:41 -0500 Subject: [PATCH 199/245] wip --- src/registrar/admin.py | 5 ++ src/registrar/assets/js/get-gov-admin.js | 99 ++++++++++++++---------- 2 files changed, 61 insertions(+), 43 deletions(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index f79e709fb..ee5d8ddc7 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -117,6 +117,11 @@ class ListHeaderAdmin(AuditedAdmin): ) return filters + # customize the help_text for all formfields for manytomany + def formfield_for_manytomany(self, db_field, request, **kwargs): + formfield = super().formfield_for_manytomany(db_field, request, **kwargs) + formfield.help_text = formfield.help_text + " If more than one value is selected, the change/delete/view actions will be disabled." + return formfield class UserContactInline(admin.StackedInline): """Edit a user's profile on the user page.""" diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 6a5d0a206..40397c1a2 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -91,9 +91,8 @@ function initializeWidgetOnToList(toList, toListId) { toList, toListId, 'related-widget-wrapper-link change-related', - 'Change selected item', - '/public/admin/img/icon-changelink.svg', 'Change', + '/public/admin/img/icon-changelink.svg', { 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id&_popup=1', 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id&_popup=1', @@ -103,49 +102,53 @@ function initializeWidgetOnToList(toList, toListId) { 0 ); - // create the delete button - let deleteLink = createAndCustomizeLink( - toList, - toListId, - 'related-widget-wrapper-link delete-related', - 'Delete selected item', - '/public/admin/img/icon-deletelink.svg', - 'Delete', - { - 'contacts': '/admin/registrar/contact/__fk__/delete/?_to_field=id&_popup=1', - 'websites': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', - 'alternative_domains': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', - }, - true, - 2 - ); + let hasDeletePermission = hasDeletePermissionOnPage(); + console.log("hasDeletePermission = " + hasDeletePermission); + + let deleteLink = null; + if (hasDeletePermission) { + // create the delete button + deleteLink = createAndCustomizeLink( + toList, + toListId, + 'related-widget-wrapper-link delete-related', + 'Delete', + '/public/admin/img/icon-deletelink.svg', + { + 'contacts': '/admin/registrar/contact/__fk__/delete/?_to_field=id&_popup=1', + 'websites': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', + 'alternative_domains': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', + }, + true, + 2 + ); + } // create the view button let viewLink = createAndCustomizeLink( toList, toListId, 'related-widget-wrapper-link view-related', - 'View selected item', - '/public/admin/img/icon-viewlink.svg', 'View', + '/public/admin/img/icon-viewlink.svg', { 'contacts': '/admin/registrar/contact/__fk__/change/?_to_field=id', 'websites': '/admin/registrar/website/__fk__/change/?_to_field=id', 'alternative_domains': '/admin/registrar/website/__fk__/change/?_to_field=id', }, false, - 3 + hasDeletePermission ? 3 : 2 ); // identify the fromList element in the DOM let fromList = toList.closest('.selector').querySelector(".selector-available select"); fromList.addEventListener('click', function(event) { - handleSelectClick(event, fromList, toList, changeLink, deleteLink, viewLink); + handleSelectClick(fromList, changeLink, deleteLink, viewLink); }); toList.addEventListener('click', function(event) { - handleSelectClick(event, toList, fromList, changeLink, deleteLink, viewLink); + handleSelectClick(toList, changeLink, deleteLink, viewLink); }); // Disable buttons when the selectors are interacted with (items are moved from one column to the other) @@ -168,7 +171,7 @@ function initializeWidgetOnToList(toList, toListId) { // dataMappings - dictionary which relates toListId to href for the created link // dataPopup - boolean for whether the link should produce a popup window // position - the position of the button in the list of buttons in the related-widget-wrapper in the widget -function createAndCustomizeLink(toList, toListId, className, title, imgSrc, imgAlt, dataMappings, dataPopup, position) { +function createAndCustomizeLink(toList, toListId, className, action, imgSrc, dataMappings, dataPopup, position) { // Create a link element var link = document.createElement('a'); @@ -194,14 +197,15 @@ function createAndCustomizeLink(toList, toListId, className, title, imgSrc, imgA if (dataPopup) link.setAttribute('data-popup', 'yes'); - link.title = title; + link.setAttribute('title-template', action + " selected item") + link.title = link.getAttribute('title-template'); // Create an 'img' element var img = document.createElement('img'); // Set attributes for the new image img.src = imgSrc; - img.alt = imgAlt; + img.alt = action; // Append the image to the link link.appendChild(img); @@ -217,30 +221,39 @@ function createAndCustomizeLink(toList, toListId, className, title, imgSrc, imgA // or the to list. Action (enable or disable) taken depends on the tocal count of selected items across // both lists. If exactly one item is selected, buttons are enabled, and urls for the buttons associated // with the selected item -function handleSelectClick(event, selectElement, relatedSelectElement, changeLink, deleteLink, viewLink) { +function handleSelectClick(selectElement, changeLink, deleteLink, viewLink) { // If one item is selected (across selectElement and relatedSelectElement), enable buttons; otherwise, disable them - if (selectElement.selectedOptions.length + relatedSelectElement.selectedOptions.length === 1) { - if (selectElement.selectedOptions.length) { - // enable buttons for selected item in selectElement - enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, selectElement.selectedOptions[0].value); - } else { - // enable buttons for selected item in relatedSelectElement - enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, relatedSelectElement.selectedOptions[0].value); - } + if (selectElement.selectedOptions.length === 1) { + // enable buttons for selected item in selectElement + enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, selectElement.selectedOptions[0].value, selectElement.selectedOptions[0].text); } else { disableRelatedWidgetButtons(changeLink, deleteLink, viewLink); } } -function disableRelatedWidgetButtons(changeLink, deleteLink, viewLink) { - changeLink.removeAttribute('href'); - deleteLink.removeAttribute('href'); - viewLink.removeAttribute('href'); +function hasDeletePermissionOnPage() { + return document.querySelector('.delete-related') != null } -function enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, elementPk) { - changeLink.setAttribute('href', changeLink.getAttribute('data-href-template').replace('__fk__', elementPk)); - deleteLink.setAttribute('href', deleteLink.getAttribute('data-href-template').replace('__fk__', elementPk)); - viewLink.setAttribute('href', viewLink.getAttribute('data-href-template').replace('__fk__', elementPk)); +function disableRelatedWidgetButtons(changeLink, deleteLink, viewLink) { + changeLink.removeAttribute('href'); + changeLink.setAttribute('title', changeLink.getAttribute('title-template')); + if (deleteLink) { + deleteLink.removeAttribute('href'); + deleteLink.setAttribute('title', deleteLink.getAttribute('title-template')); + } + viewLink.removeAttribute('href'); + viewLink.setAttribute('title', viewLink.getAttribute('title-template')); +} + +function enableRelatedWidgetButtons(changeLink, deleteLink, viewLink, elementPk, elementText) { + changeLink.setAttribute('href', changeLink.getAttribute('data-href-template').replace('__fk__', elementPk)); + changeLink.setAttribute('title', changeLink.getAttribute('title-template').replace('selected item', elementText)); + if (deleteLink) { + deleteLink.setAttribute('href', deleteLink.getAttribute('data-href-template').replace('__fk__', elementPk)); + deleteLink.setAttribute('title', deleteLink.getAttribute('title-template').replace('selected item', elementText)); + } + viewLink.setAttribute('href', viewLink.getAttribute('data-href-template').replace('__fk__', elementPk)); + viewLink.setAttribute('title', viewLink.getAttribute('title-template').replace('selected item', elementText)); } From 7bc77ac4f91221db9d757427cad5f3a6580d95d5 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:28:34 -0700 Subject: [PATCH 200/245] Update migration-troubleshooting.md --- docs/developer/migration-troubleshooting.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docs/developer/migration-troubleshooting.md b/docs/developer/migration-troubleshooting.md index ff451bfdd..64d94c520 100644 --- a/docs/developer/migration-troubleshooting.md +++ b/docs/developer/migration-troubleshooting.md @@ -13,12 +13,6 @@ Some common commands: - ./manage.py showmigrations -- the migration changes should now have a [x] by it -On occasion, you will need to run this set of commands to refresh your environment: -- docker-compose down -- docker-compose build -- docker-compose up - - ## Scenarios ### Scenario 1: Conflicting migrations on local @@ -60,7 +54,6 @@ This has happened when updating user perms (so running a new data migration). So - `cf run-task getgov- --wait --command 'python manage.py migrate registrar 39_penultimate_miration --fake' --name migrate` - `cf run-task getgov- --wait --command 'python manage.py migrate' --name migrate` - ### Scenario 4: All migrations refuse to load due to existing duplicates on sandboxes This typically happens with a DB conflict that prevents 001_initial from loading. For instance, let's say all migrations have ran successfully before, and a zero command is ran to reset everything. This can lead to a catastrophic issue with your postgres database. @@ -83,7 +76,6 @@ Afterwards, go back to your psql instance. Run the following for each problemati Then, run `./manage.py migrate` again and repeat step 7 for each table which returns this error. After these errors are resolved, follow instructions in the other scenarios if applicable. - ### Scenario 5: Permissions group exist, but my users cannot log onto the sandbox This is most likely due to fixtures not running or fixtures running before the data creating migration. Simple run fixtures again (WARNING: This applies to dev sandboxes only. We never want to rerun fixtures on a stable environment) @@ -105,7 +97,6 @@ Example: there are extra columns created on a table by an old migration long sin - `SELECT * FROM {bad_table};` - `alter table registrar_domain drop {bad_column};` - ### Scenario 7: Continual 500 error for the registrar + your requests (login, clicking around, etc) are not showing up in the logstream Example: You are able to log in and access the /admin page, but when you arrive at the registrar you keep getting 500 errors and your log-ins any API calls you make via the UI does not show up in the log stream. And you feel like you’re starting to lose your marbles. From 5dcdb4a48e31afbef90537b0e8859c58e7a26ec9 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 17:39:43 -0500 Subject: [PATCH 201/245] wip --- src/registrar/assets/js/get-gov-admin.js | 27 ++++++++++++++++++------ 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index 40397c1a2..b2eb1bb17 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -99,11 +99,10 @@ function initializeWidgetOnToList(toList, toListId) { 'alternative_domains': '/admin/registrar/website/__fk__/change/?_to_field=id&_popup=1', }, true, - 0 + true ); let hasDeletePermission = hasDeletePermissionOnPage(); - console.log("hasDeletePermission = " + hasDeletePermission); let deleteLink = null; if (hasDeletePermission) { @@ -120,7 +119,7 @@ function initializeWidgetOnToList(toList, toListId) { 'alternative_domains': '/admin/registrar/website/__fk__/delete/?_to_field=id&_popup=1', }, true, - 2 + false ); } @@ -137,7 +136,7 @@ function initializeWidgetOnToList(toList, toListId) { 'alternative_domains': '/admin/registrar/website/__fk__/change/?_to_field=id', }, false, - hasDeletePermission ? 3 : 2 + false ); // identify the fromList element in the DOM @@ -170,8 +169,8 @@ function initializeWidgetOnToList(toList, toListId) { // imgAlt - the img.alt for the created link // dataMappings - dictionary which relates toListId to href for the created link // dataPopup - boolean for whether the link should produce a popup window -// position - the position of the button in the list of buttons in the related-widget-wrapper in the widget -function createAndCustomizeLink(toList, toListId, className, action, imgSrc, dataMappings, dataPopup, position) { +// firstPosition - boolean indicating if link should be first position in list of links, otherwise, just before last link +function createAndCustomizeLink(toList, toListId, className, action, imgSrc, dataMappings, dataPopup, firstPosition) { // Create a link element var link = document.createElement('a'); @@ -210,8 +209,22 @@ function createAndCustomizeLink(toList, toListId, className, action, imgSrc, dat // Append the image to the link link.appendChild(img); + let relatedWidgetWrapper = toList.closest('.related-widget-wrapper'); // Insert the link at the specified position - toList.closest('.related-widget-wrapper').insertBefore(link, toList.closest('.related-widget-wrapper').children[position]); + if (firstPosition) { + relatedWidgetWrapper.insertBefore(link, relatedWidgetWrapper.children[0]); + } else { + var lastChild = relatedWidgetWrapper.lastChild; + + // Check if lastChild is an element node (not a text node, comment, etc.) + if (lastChild.nodeType === 1) { + var previousSibling = lastChild.previousSibling; + while (previousSibling.nodeType !== 1) { + previousSibling = previousSibling.previousSibling; + } + relatedWidgetWrapper.insertBefore(link, previousSibling.nextSibling); + } + } // Return the link, which we'll use in the disable and enable functions return link; From bf3f9e67fc97d371ccdc819ebcd5f6936aa8fdcc Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Mon, 4 Dec 2023 14:43:06 -0800 Subject: [PATCH 202/245] Only have Manage Your Domains show up on Domain Overview page --- src/registrar/templates/base.html | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html index 03eec88ac..aad526f37 100644 --- a/src/registrar/templates/base.html +++ b/src/registrar/templates/base.html @@ -1,5 +1,7 @@ {# keep this on the first line #} {% load i18n static %} +{% load static url_helpers %} + @@ -148,13 +150,16 @@ {% block logo %} {% endblock %} - + {% url 'domain' pk=domain.id as url %} + {% if request.path == url %} + Manage your domains - + + {% endif %}
From 3cf7d5138e959fed1bfa8750a292f1cbe0a252cc Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 17:57:39 -0500 Subject: [PATCH 203/245] wip --- src/registrar/models/domain_application.py | 1 + src/registrar/models/domain_information.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 86b8a0f7a..babf51757 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -487,6 +487,7 @@ class DomainApplication(TimeStampedModel): "registrar.Website", blank=True, related_name="current+", + verbose_name="websites", ) approved_domain = models.OneToOneField( diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index d2bc5c53d..9f0d654b0 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -179,6 +179,7 @@ class DomainInformation(TimeStampedModel): "registrar.Contact", blank=True, related_name="contact_applications_information", + verbose_name="contacts", ) no_other_contacts_rationale = models.TextField( From 8ddd5e7b1fc3ec70c9ae41c8215bb672d6c782ac Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 18:08:26 -0500 Subject: [PATCH 204/245] updated comments --- src/registrar/assets/js/get-gov-admin.js | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/registrar/assets/js/get-gov-admin.js b/src/registrar/assets/js/get-gov-admin.js index b2eb1bb17..53eeb22a3 100644 --- a/src/registrar/assets/js/get-gov-admin.js +++ b/src/registrar/assets/js/get-gov-admin.js @@ -106,7 +106,7 @@ function initializeWidgetOnToList(toList, toListId) { let deleteLink = null; if (hasDeletePermission) { - // create the delete button + // create the delete button if user has permission to delete deleteLink = createAndCustomizeLink( toList, toListId, @@ -165,11 +165,11 @@ function initializeWidgetOnToList(toList, toListId) { // toList - the element in the DOM for the toList // toListId - the ID of the element in the DOM // className - className to add to the created link +// action - the action to perform on the item {change, delete, view} // imgSrc - the img.src for the created link -// imgAlt - the img.alt for the created link // dataMappings - dictionary which relates toListId to href for the created link // dataPopup - boolean for whether the link should produce a popup window -// firstPosition - boolean indicating if link should be first position in list of links, otherwise, just before last link +// firstPosition - boolean indicating if link should be first position in list of links, otherwise, should be last link function createAndCustomizeLink(toList, toListId, className, action, imgSrc, dataMappings, dataPopup, firstPosition) { // Create a link element var link = document.createElement('a'); @@ -210,15 +210,19 @@ function createAndCustomizeLink(toList, toListId, className, action, imgSrc, dat link.appendChild(img); let relatedWidgetWrapper = toList.closest('.related-widget-wrapper'); - // Insert the link at the specified position + // If firstPosition is true, insert link as the first child element if (firstPosition) { relatedWidgetWrapper.insertBefore(link, relatedWidgetWrapper.children[0]); } else { + // otherwise, insert the link prior to the last child (which is a div) + // and also prior to any text elements immediately preceding the last + // child node var lastChild = relatedWidgetWrapper.lastChild; // Check if lastChild is an element node (not a text node, comment, etc.) if (lastChild.nodeType === 1) { var previousSibling = lastChild.previousSibling; + // need to work around some white space which has been inserted into the dom while (previousSibling.nodeType !== 1) { previousSibling = previousSibling.previousSibling; } @@ -230,10 +234,9 @@ function createAndCustomizeLink(toList, toListId, className, action, imgSrc, dat return link; } -// Either enable or disable widget buttons when select is clicked. Select can be in either the from list -// or the to list. Action (enable or disable) taken depends on the tocal count of selected items across -// both lists. If exactly one item is selected, buttons are enabled, and urls for the buttons associated -// with the selected item +// Either enable or disable widget buttons when select is clicked. Action (enable or disable) taken depends on the count +// of selected items in selectElement. If exactly one item is selected, buttons are enabled, and urls for the buttons are +// associated with the selected item function handleSelectClick(selectElement, changeLink, deleteLink, viewLink) { // If one item is selected (across selectElement and relatedSelectElement), enable buttons; otherwise, disable them @@ -245,6 +248,8 @@ function handleSelectClick(selectElement, changeLink, deleteLink, viewLink) { } } +// return true if there exist elements on the page with classname of delete-related. +// presence of one or more of these elements indicates user has permission to delete function hasDeletePermissionOnPage() { return document.querySelector('.delete-related') != null } From 2c355353b6cb8ca8d21ab127a070df427ef06ef2 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Mon, 4 Dec 2023 18:37:23 -0500 Subject: [PATCH 205/245] updated helper_text in admin for multi selects; formatted for linter --- src/registrar/admin.py | 6 +++++- src/registrar/models/domain_application.py | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index ee5d8ddc7..421e8d53c 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -120,9 +120,13 @@ class ListHeaderAdmin(AuditedAdmin): # customize the help_text for all formfields for manytomany def formfield_for_manytomany(self, db_field, request, **kwargs): formfield = super().formfield_for_manytomany(db_field, request, **kwargs) - formfield.help_text = formfield.help_text + " If more than one value is selected, the change/delete/view actions will be disabled." + formfield.help_text = ( + formfield.help_text + + " If more than one value is selected, the change/delete/view actions will be disabled." + ) return formfield + class UserContactInline(admin.StackedInline): """Edit a user's profile on the user page.""" diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index babf51757..9ab3908d4 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -533,6 +533,7 @@ class DomainApplication(TimeStampedModel): "registrar.Contact", blank=True, related_name="contact_applications", + verbose_name="contacts", ) no_other_contacts_rationale = models.TextField( From aa51a325e24f49497ca74d3a5486243ad533678d Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Mon, 4 Dec 2023 15:48:59 -0800 Subject: [PATCH 206/245] hotfix for domain invitation not sending to existing user --- src/registrar/views/domain.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 4d91ddc66..4dcdf3e5c 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -642,18 +642,9 @@ class DomainAddUserView(DomainFormBaseView): def _domain_abs_url(self): """Get an absolute URL for this domain.""" return self.request.build_absolute_uri(reverse("domain", kwargs={"pk": self.object.id})) - - def _make_invitation(self, email_address): - """Make a Domain invitation for this email and redirect with a message.""" - invitation, created = DomainInvitation.objects.get_or_create(email=email_address, domain=self.object) - if not created: - # that invitation already existed - messages.warning( - self.request, - f"{email_address} has already been invited to this domain.", - ) - else: - # created a new invitation in the database, so send an email + + def _send_domain_invitation_email(self, email_address:str): + # created a new invitation in the database, so send an email domaininfo = DomainInformation.objects.filter(domain=self.object) first = domaininfo.first().creator.first_name last = domaininfo.first().creator.last_name @@ -681,6 +672,17 @@ class DomainAddUserView(DomainFormBaseView): else: messages.success(self.request, f"Invited {email_address} to this domain.") + def _make_invitation(self, email_address:str): + """Make a Domain invitation for this email and redirect with a message.""" + invitation, created = DomainInvitation.objects.get_or_create(email=email_address, domain=self.object) + if not created: + # that invitation already existed + messages.warning( + self.request, + f"{email_address} has already been invited to this domain.", + ) + else: + self._send_domain_invitation_email(email_address=email_address) return redirect(self.get_success_url()) def form_valid(self, form): @@ -692,6 +694,9 @@ class DomainAddUserView(DomainFormBaseView): except User.DoesNotExist: # no matching user, go make an invitation return self._make_invitation(requested_email) + else: + #if user already exists then just send an email + self._send_domain_invitation_email(requested_email) try: UserDomainRole.objects.create( From 0b929379f32176c1174cf80371511fbc09bfb9ec Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Mon, 4 Dec 2023 16:01:27 -0800 Subject: [PATCH 207/245] linter update --- src/registrar/views/domain.py | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index 4dcdf3e5c..ddb3d72f5 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -642,37 +642,37 @@ class DomainAddUserView(DomainFormBaseView): def _domain_abs_url(self): """Get an absolute URL for this domain.""" return self.request.build_absolute_uri(reverse("domain", kwargs={"pk": self.object.id})) - - def _send_domain_invitation_email(self, email_address:str): + + def _send_domain_invitation_email(self, email_address: str): # created a new invitation in the database, so send an email - domaininfo = DomainInformation.objects.filter(domain=self.object) - first = domaininfo.first().creator.first_name - last = domaininfo.first().creator.last_name - full_name = f"{first} {last}" + domaininfo = DomainInformation.objects.filter(domain=self.object) + first = domaininfo.first().creator.first_name + last = domaininfo.first().creator.last_name + full_name = f"{first} {last}" - try: - send_templated_email( - "emails/domain_invitation.txt", - "emails/domain_invitation_subject.txt", - to_address=email_address, - context={ - "domain_url": self._domain_abs_url(), - "domain": self.object, - "full_name": full_name, - }, - ) - except EmailSendingError: - messages.warning(self.request, "Could not send email invitation.") - logger.warn( - "Could not sent email invitation to %s for domain %s", - email_address, - self.object, - exc_info=True, - ) - else: - messages.success(self.request, f"Invited {email_address} to this domain.") + try: + send_templated_email( + "emails/domain_invitation.txt", + "emails/domain_invitation_subject.txt", + to_address=email_address, + context={ + "domain_url": self._domain_abs_url(), + "domain": self.object, + "full_name": full_name, + }, + ) + except EmailSendingError: + messages.warning(self.request, "Could not send email invitation.") + logger.warn( + "Could not sent email invitation to %s for domain %s", + email_address, + self.object, + exc_info=True, + ) + else: + messages.success(self.request, f"Invited {email_address} to this domain.") - def _make_invitation(self, email_address:str): + def _make_invitation(self, email_address: str): """Make a Domain invitation for this email and redirect with a message.""" invitation, created = DomainInvitation.objects.get_or_create(email=email_address, domain=self.object) if not created: @@ -695,7 +695,7 @@ class DomainAddUserView(DomainFormBaseView): # no matching user, go make an invitation return self._make_invitation(requested_email) else: - #if user already exists then just send an email + # if user already exists then just send an email self._send_domain_invitation_email(requested_email) try: From ae2ab3c415b565325f598a6c61411918a8b4ed4a Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Mon, 4 Dec 2023 16:56:20 -0800 Subject: [PATCH 208/245] fixed linter error and removed excess message --- src/registrar/views/domain.py | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index ddb3d72f5..ad4d77111 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -643,18 +643,27 @@ class DomainAddUserView(DomainFormBaseView): """Get an absolute URL for this domain.""" return self.request.build_absolute_uri(reverse("domain", kwargs={"pk": self.object.id})) - def _send_domain_invitation_email(self, email_address: str): + def _send_domain_invitation_email(self, email: str, add_success=True): + """Performs the sending of the domain invitation email, + does not make a domain information object + email: string- email to send to + add_success: bool- default True indicates: + adding a success message to the view if the email sending succeeds""" # created a new invitation in the database, so send an email - domaininfo = DomainInformation.objects.filter(domain=self.object) - first = domaininfo.first().creator.first_name - last = domaininfo.first().creator.last_name + domainInfoResults = DomainInformation.objects.filter(domain=self.object) + domainInfo = domainInfoResults.first() + first = "" + last = "" + if not domainInfo is None: + first = domainInfo.creator.first_name + last = domainInfo.creator.last_name full_name = f"{first} {last}" try: send_templated_email( "emails/domain_invitation.txt", "emails/domain_invitation_subject.txt", - to_address=email_address, + to_address=email, context={ "domain_url": self._domain_abs_url(), "domain": self.object, @@ -665,12 +674,13 @@ class DomainAddUserView(DomainFormBaseView): messages.warning(self.request, "Could not send email invitation.") logger.warn( "Could not sent email invitation to %s for domain %s", - email_address, + email, self.object, exc_info=True, ) else: - messages.success(self.request, f"Invited {email_address} to this domain.") + if add_success: + messages.success(self.request, f"Invited {email} to this domain.") def _make_invitation(self, email_address: str): """Make a Domain invitation for this email and redirect with a message.""" @@ -682,7 +692,7 @@ class DomainAddUserView(DomainFormBaseView): f"{email_address} has already been invited to this domain.", ) else: - self._send_domain_invitation_email(email_address=email_address) + self._send_domain_invitation_email(email=email_address) return redirect(self.get_success_url()) def form_valid(self, form): From c89400a72d978a9a66b40f7e427948f91a119dda Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Mon, 4 Dec 2023 16:57:34 -0800 Subject: [PATCH 209/245] added missing flag --- src/registrar/views/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index ad4d77111..dc8f3d18c 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -706,7 +706,7 @@ class DomainAddUserView(DomainFormBaseView): return self._make_invitation(requested_email) else: # if user already exists then just send an email - self._send_domain_invitation_email(requested_email) + self._send_domain_invitation_email(requested_email, add_success=False) try: UserDomainRole.objects.create( From 9fdd78bf60766922e378b79493f163f8e01dfbae Mon Sep 17 00:00:00 2001 From: Alysia Broddrick Date: Mon, 4 Dec 2023 17:07:46 -0800 Subject: [PATCH 210/245] fixed linter issue --- src/registrar/views/domain.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py index dc8f3d18c..8bcebc20a 100644 --- a/src/registrar/views/domain.py +++ b/src/registrar/views/domain.py @@ -654,7 +654,7 @@ class DomainAddUserView(DomainFormBaseView): domainInfo = domainInfoResults.first() first = "" last = "" - if not domainInfo is None: + if domainInfo is not None: first = domainInfo.creator.first_name last = domainInfo.creator.last_name full_name = f"{first} {last}" From e11db7fbd36853c40931d6b5d4e4eadcc32b6d66 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Tue, 5 Dec 2023 04:51:33 -0500 Subject: [PATCH 211/245] migrations for model changes --- ...inapplication_current_websites_and_more.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py diff --git a/src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py new file mode 100644 index 000000000..1548032cd --- /dev/null +++ b/src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.7 on 2023-12-05 09:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0047_transitiondomain_address_line_transitiondomain_city_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="current_websites", + field=models.ManyToManyField( + blank=True, related_name="current+", to="registrar.website", verbose_name="websites" + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="other_contacts", + field=models.ManyToManyField( + blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="contacts" + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_applications_information", + to="registrar.contact", + verbose_name="contacts", + ), + ), + ] From 41f7a882b4562cf53cda6bb3b912cab3b52ec2af Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Tue, 5 Dec 2023 04:59:34 -0500 Subject: [PATCH 212/245] undo a migration merge conflict --- ...inapplication_current_websites_and_more.py | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py diff --git a/src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py deleted file mode 100644 index 1548032cd..000000000 --- a/src/registrar/migrations/0048_alter_domainapplication_current_websites_and_more.py +++ /dev/null @@ -1,36 +0,0 @@ -# Generated by Django 4.2.7 on 2023-12-05 09:50 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("registrar", "0047_transitiondomain_address_line_transitiondomain_city_and_more"), - ] - - operations = [ - migrations.AlterField( - model_name="domainapplication", - name="current_websites", - field=models.ManyToManyField( - blank=True, related_name="current+", to="registrar.website", verbose_name="websites" - ), - ), - migrations.AlterField( - model_name="domainapplication", - name="other_contacts", - field=models.ManyToManyField( - blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="contacts" - ), - ), - migrations.AlterField( - model_name="domaininformation", - name="other_contacts", - field=models.ManyToManyField( - blank=True, - related_name="contact_applications_information", - to="registrar.contact", - verbose_name="contacts", - ), - ), - ] From 7f282fd4566ffd7dcc0a8ba5f73625dc73045bd6 Mon Sep 17 00:00:00 2001 From: David Kennedy Date: Tue, 5 Dec 2023 05:01:02 -0500 Subject: [PATCH 213/245] updated migrations --- ...inapplication_current_websites_and_more.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py diff --git a/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py new file mode 100644 index 000000000..4341bdad6 --- /dev/null +++ b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.7 on 2023-12-05 10:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0048_alter_transitiondomain_status"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="current_websites", + field=models.ManyToManyField( + blank=True, related_name="current+", to="registrar.website", verbose_name="websites" + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="other_contacts", + field=models.ManyToManyField( + blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="contacts" + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_applications_information", + to="registrar.contact", + verbose_name="contacts", + ), + ), + ] From 125758183b426160313aa52e9fec25acefbfcab2 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:02:33 -0700 Subject: [PATCH 214/245] Add migration --- .../migrations/0049_create_groups_v03.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/registrar/migrations/0049_create_groups_v03.py diff --git a/src/registrar/migrations/0049_create_groups_v03.py b/src/registrar/migrations/0049_create_groups_v03.py new file mode 100644 index 000000000..c8f471ea0 --- /dev/null +++ b/src/registrar/migrations/0049_create_groups_v03.py @@ -0,0 +1,37 @@ +# This migration creates the create_full_access_group and create_cisa_analyst_group groups +# It is dependent on 0035 (which populates ContentType and Permissions) +# If permissions on the groups need changing, edit CISA_ANALYST_GROUP_PERMISSIONS +# in the user_group model then: +# [NOT RECOMMENDED] +# step 1: docker-compose exec app ./manage.py migrate --fake registrar 0035_contenttypes_permissions +# step 2: docker-compose exec app ./manage.py migrate registrar 0036_create_groups +# step 3: fake run the latest migration in the migrations list +# [RECOMMENDED] +# Alternatively: +# step 1: duplicate the migration that loads data +# step 2: docker-compose exec app ./manage.py migrate + +from django.db import migrations +from registrar.models import UserGroup +from typing import Any + + +# For linting: RunPython expects a function reference, +# so let's give it one +def create_groups(apps, schema_editor) -> Any: + UserGroup.create_cisa_analyst_group(apps, schema_editor) + UserGroup.create_full_access_group(apps, schema_editor) + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0048_alter_transitiondomain_status"), + ] + + operations = [ + migrations.RunPython( + create_groups, + reverse_code=migrations.RunPython.noop, + atomic=True, + ), + ] From b7265598ba683f18fa24fc85676b8b1ae638cf7e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 09:27:55 -0700 Subject: [PATCH 215/245] Rename migration --- .../{0049_create_groups_v03.py => 0049_create_groups_v05.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/registrar/migrations/{0049_create_groups_v03.py => 0049_create_groups_v05.py} (100%) diff --git a/src/registrar/migrations/0049_create_groups_v03.py b/src/registrar/migrations/0049_create_groups_v05.py similarity index 100% rename from src/registrar/migrations/0049_create_groups_v03.py rename to src/registrar/migrations/0049_create_groups_v05.py From d0c793cfbee3acf696e75a9327eef7205f0acac9 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:36:02 -0700 Subject: [PATCH 216/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 2f703ae21..45ab176f8 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -11,24 +11,15 @@ on: - stable - staging - development - - ky - - es - - nl - - rh - za - - gd - - rb - - ko - - ab - - bl - - rjm - - dk schedule: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" jobs: - variables: + variables: + env: + report_environment: CF_REPORT_ENV outputs: environment: ${{ steps.var.outputs.environment}} runs-on: "ubuntu-latest" @@ -38,7 +29,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : "ZA"; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[env.report_environment] }}; core.setOutput('environment', environment); upload-reports: From 3424121a33e9493615ae7c131138b421a450b13c Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:44:49 -0700 Subject: [PATCH 217/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 45ab176f8..22b579c48 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,6 +2,7 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} on: + pull_request: workflow_dispatch: inputs: environment: From 28b966402c08a55dc0a7e74d636ee1647e144b49 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:47:01 -0700 Subject: [PATCH 218/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 22b579c48..5070e342a 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -19,8 +19,6 @@ on: jobs: variables: - env: - report_environment: CF_REPORT_ENV outputs: environment: ${{ steps.var.outputs.environment}} runs-on: "ubuntu-latest" @@ -30,7 +28,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[env.report_environment] }}; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[CF_REPORT_ENV] }}; core.setOutput('environment', environment); upload-reports: From 3b10a6b023f8ceab91d3dfe6efa4ca64dc335a04 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:49:33 -0700 Subject: [PATCH 219/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 5070e342a..aaaaac5fd 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -28,7 +28,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[CF_REPORT_ENV] }}; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets["CF_REPORT_ENV"] }}; core.setOutput('environment', environment); upload-reports: From 1c52e73fe4e4fdf9eb63c50b088d9bfaeb51fcb5 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 11:58:44 -0700 Subject: [PATCH 220/245] Test env var --- .github/workflows/daily-csv-upload.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index aaaaac5fd..0e240bb3d 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -19,6 +19,8 @@ on: jobs: variables: + env: + DEFAULT_ENV: CF_REPORT_ENV outputs: environment: ${{ steps.var.outputs.environment}} runs-on: "ubuntu-latest" @@ -28,7 +30,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets["CF_REPORT_ENV"] }}; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[env.DEFAULT_ENV]] }}; core.setOutput('environment', environment); upload-reports: From 99c2dc4de3789c2ef9df3700cf00c8a2569ffdc6 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:02:49 -0700 Subject: [PATCH 221/245] Fix typo --- .github/workflows/daily-csv-upload.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 0e240bb3d..c4d954d34 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -30,7 +30,7 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[env.DEFAULT_ENV]] }}; + const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[env.DEFAULT_ENV] }}; core.setOutput('environment', environment); upload-reports: From 20005b71408bf16cb5ce85ec34484fad4fc14eda Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:11:52 -0700 Subject: [PATCH 222/245] Set default --- .github/workflows/daily-csv-upload.yaml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index c4d954d34..82bb81657 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -3,24 +3,12 @@ run-name: Upload current-full.csv and current-federal.csv for branch ${{ github. on: pull_request: - workflow_dispatch: - inputs: - environment: - type: choice - description: Which environment do you wish to load reports for? - options: - - stable - - staging - - development - - za schedule: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" jobs: variables: - env: - DEFAULT_ENV: CF_REPORT_ENV outputs: environment: ${{ steps.var.outputs.environment}} runs-on: "ubuntu-latest" @@ -30,7 +18,8 @@ jobs: id: var with: script: | - const environment = (github && github.event && github.event.inputs) ? github.event.inputs.environment : ${{ secrets[env.DEFAULT_ENV] }}; + const default = "CF_REPORT_ENV" + const environment = ${{ secrets[default] }}; core.setOutput('environment', environment); upload-reports: @@ -39,6 +28,7 @@ jobs: env: CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD + CF_DEFAULT_ENV: CF_REPORT_ENV steps: - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main From 546a65ccee9cf8c95fbf3ca5a8d72fe434f2c2fe Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:18:12 -0700 Subject: [PATCH 223/245] Test default --- .github/workflows/daily-csv-upload.yaml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 82bb81657..574be9e00 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -8,7 +8,14 @@ on: - cron: "0 5 * * *" jobs: + default: + outputs: + default: CF_REPORT_ENV + variables: + needs: [default] + env: + CF_DEFAULT: $ {{ needs.default.outputs.default }} outputs: environment: ${{ steps.var.outputs.environment}} runs-on: "ubuntu-latest" @@ -18,9 +25,8 @@ jobs: id: var with: script: | - const default = "CF_REPORT_ENV" - const environment = ${{ secrets[default] }}; - core.setOutput('environment', environment); + const environment = ${{ secrets[env.CF_DEFAULT] }}; + core.setOutput("environment", environment); upload-reports: runs-on: ubuntu-latest From 184c17156fc3da0528f91a8e25f77a32ea6c4eca Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:19:30 -0700 Subject: [PATCH 224/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 574be9e00..c023da000 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -10,7 +10,15 @@ on: jobs: default: outputs: - default: CF_REPORT_ENV + default: ${{ steps.var.outputs.default}} + runs-on: "ubuntu-latest" + steps: + - name: Setting global variables + uses: actions/github-script@v6 + id: var + with: + script: | + core.setOutput("default", "CF_REPORT_ENV"); variables: needs: [default] From 3a4329927741d52e2749b564aec0fdc52ac84e45 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:24:35 -0700 Subject: [PATCH 225/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index c023da000..42fe35e87 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -1,5 +1,5 @@ name: Upload current-full.csv and current-federal.csv -run-name: Upload current-full.csv and current-federal.csv for branch ${{ github.head_ref }} +run-name: Upload current-full.csv and current-federal.csv on: pull_request: @@ -7,23 +7,9 @@ on: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" -jobs: - default: - outputs: - default: ${{ steps.var.outputs.default}} - runs-on: "ubuntu-latest" - steps: - - name: Setting global variables - uses: actions/github-script@v6 - id: var - with: - script: | - core.setOutput("default", "CF_REPORT_ENV"); - variables: - needs: [default] env: - CF_DEFAULT: $ {{ needs.default.outputs.default }} + CF_DEFAULT: CF_REPORT_ENV outputs: environment: ${{ steps.var.outputs.environment}} runs-on: "ubuntu-latest" From 9ced76a27a399db88ec3cc7fbb4d4c4bd72e4254 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 5 Dec 2023 11:28:21 -0800 Subject: [PATCH 226/245] renaming migration files to avoid issues --- ...ondomain_status.py => 0051_alter_transitiondomain_status.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/registrar/migrations/{0048_alter_transitiondomain_status.py => 0051_alter_transitiondomain_status.py} (87%) diff --git a/src/registrar/migrations/0048_alter_transitiondomain_status.py b/src/registrar/migrations/0051_alter_transitiondomain_status.py similarity index 87% rename from src/registrar/migrations/0048_alter_transitiondomain_status.py rename to src/registrar/migrations/0051_alter_transitiondomain_status.py index d67c91e4b..73386bada 100644 --- a/src/registrar/migrations/0048_alter_transitiondomain_status.py +++ b/src/registrar/migrations/0051_alter_transitiondomain_status.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0047_transitiondomain_address_line_transitiondomain_city_and_more"), + ("registrar", "0050_alter_domainapplication_anything_else_and_more"), ] operations = [ From d3da6d40e5768e19a30b5c80da6e6fa00ae5248e Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:29:15 -0700 Subject: [PATCH 227/245] Access secret --- .github/workflows/daily-csv-upload.yaml | 28 ++++++------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 42fe35e87..43ca094db 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -7,28 +7,12 @@ on: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" - variables: - env: - CF_DEFAULT: CF_REPORT_ENV - outputs: - environment: ${{ steps.var.outputs.environment}} - runs-on: "ubuntu-latest" - steps: - - name: Setting global variables - uses: actions/github-script@v6 - id: var - with: - script: | - const environment = ${{ secrets[env.CF_DEFAULT] }}; - core.setOutput("environment", environment); - upload-reports: runs-on: ubuntu-latest needs: [variables] env: - CF_USERNAME: CF_${{ needs.variables.outputs.environment }}_USERNAME - CF_PASSWORD: CF_${{ needs.variables.outputs.environment }}_PASSWORD - CF_DEFAULT_ENV: CF_REPORT_ENV + CF_USERNAME: CF_${{ secrets.CF_REPORT_ENV }}_USERNAME + CF_PASSWORD: CF_${{ secrets.CF_REPORT_ENV }}_PASSWORD steps: - name: Generate current-federal.csv uses: cloud-gov/cg-cli-tools@main @@ -36,8 +20,8 @@ on: cf_username: ${{ secrets[env.CF_USERNAME] }} cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov - cf_space: ${{ needs.variables.outputs.environment }} - cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_federal_report' --name federal" + cf_space: ${{ secrets.CF_REPORT_ENV }} + cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py generate_current_federal_report' --name federal" - name: Generate current-full.csv uses: cloud-gov/cg-cli-tools@main @@ -45,6 +29,6 @@ on: cf_username: ${{ secrets[env.CF_USERNAME] }} cf_password: ${{ secrets[env.CF_PASSWORD] }} cf_org: cisa-dotgov - cf_space: ${{ needs.variables.outputs.environment }} - cf_command: "run-task getgov-${{ needs.variables.outputs.environment }} --command 'python manage.py generate_current_full_report' --name full" + cf_space: ${{ secrets.CF_REPORT_ENV }} + cf_command: "run-task getgov-${{ secrets.CF_REPORT_ENV }} --command 'python manage.py generate_current_full_report' --name full" From fd3b178d857624b89021882be8a91623dfc1dc39 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:30:27 -0700 Subject: [PATCH 228/245] Update daily-csv-upload.yaml --- .github/workflows/daily-csv-upload.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 43ca094db..0addb3a98 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -9,7 +9,6 @@ on: upload-reports: runs-on: ubuntu-latest - needs: [variables] env: CF_USERNAME: CF_${{ secrets.CF_REPORT_ENV }}_USERNAME CF_PASSWORD: CF_${{ secrets.CF_REPORT_ENV }}_PASSWORD From 03d4fe88fce6922c98a4c4b4b7f3e092cbbb4c77 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:32:45 -0700 Subject: [PATCH 229/245] Add back "jobs" --- .github/workflows/daily-csv-upload.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 0addb3a98..6f2dd8448 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -7,6 +7,7 @@ on: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" +jobs: upload-reports: runs-on: ubuntu-latest env: From 7c94e280805d947817bc816124f1c1cd596164ab Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:36:33 -0700 Subject: [PATCH 230/245] Remove pull_request --- .github/workflows/daily-csv-upload.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/daily-csv-upload.yaml b/.github/workflows/daily-csv-upload.yaml index 6f2dd8448..724a19457 100644 --- a/.github/workflows/daily-csv-upload.yaml +++ b/.github/workflows/daily-csv-upload.yaml @@ -2,7 +2,6 @@ name: Upload current-full.csv and current-federal.csv run-name: Upload current-full.csv and current-federal.csv on: - pull_request: schedule: # Runs every day at 5 AM UTC. - cron: "0 5 * * *" From f3916a28376c7c2cf15934498d348668216a6207 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Tue, 5 Dec 2023 13:14:37 -0700 Subject: [PATCH 231/245] Remove if --- .github/workflows/deploy-development.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/deploy-development.yaml b/.github/workflows/deploy-development.yaml index 13aeb3993..562b2b11f 100644 --- a/.github/workflows/deploy-development.yaml +++ b/.github/workflows/deploy-development.yaml @@ -15,7 +15,6 @@ on: jobs: deploy-development: - if: ${{ github.ref_type == 'tag' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 From 39b930baa7507d9d1a632c2b633bec886bdffbb8 Mon Sep 17 00:00:00 2001 From: Neil Martinsen-Burrell Date: Tue, 5 Dec 2023 14:45:14 -0600 Subject: [PATCH 232/245] Switch to allowing non-identity-verified logins --- src/registrar/config/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/registrar/config/settings.py b/src/registrar/config/settings.py index 7f20c8129..192f90f79 100644 --- a/src/registrar/config/settings.py +++ b/src/registrar/config/settings.py @@ -518,7 +518,7 @@ OIDC_PROVIDERS = { "response_type": "code", "scope": ["email", "profile:name", "phone"], "user_info_request": ["email", "first_name", "last_name", "phone"], - "acr_value": "http://idmanagement.gov/ns/assurance/ial/2", + "acr_value": "http://idmanagement.gov/ns/assurance/ial/1", }, "client_registration": { "client_id": "cisa_dotgov_registrar", @@ -535,7 +535,7 @@ OIDC_PROVIDERS = { "response_type": "code", "scope": ["email", "profile:name", "phone"], "user_info_request": ["email", "first_name", "last_name", "phone"], - "acr_value": "http://idmanagement.gov/ns/assurance/ial/2", + "acr_value": "http://idmanagement.gov/ns/assurance/ial/1", }, "client_registration": { "client_id": ("urn:gov:cisa:openidconnect.profiles:sp:sso:cisa:dotgov_registrar"), From f2afd293179e2682ef74939b8a1fd121447f0d13 Mon Sep 17 00:00:00 2001 From: Kristina Yin Date: Tue, 5 Dec 2023 13:27:43 -0800 Subject: [PATCH 233/245] solved migrations issues --- ... => 0048_alter_transitiondomain_status.py} | 2 +- ...inapplication_current_websites_and_more.py | 36 +++++++++++++++++++ ...050_alter_contact_middle_name_and_more.py} | 2 +- ...omainapplication_urbanization_and_more.py} | 2 +- ...mainapplication_anything_else_and_more.py} | 2 +- 5 files changed, 40 insertions(+), 4 deletions(-) rename src/registrar/migrations/{0051_alter_transitiondomain_status.py => 0048_alter_transitiondomain_status.py} (87%) create mode 100644 src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py rename src/registrar/migrations/{0048_alter_contact_middle_name_and_more.py => 0050_alter_contact_middle_name_and_more.py} (92%) rename src/registrar/migrations/{0049_alter_domainapplication_urbanization_and_more.py => 0051_alter_domainapplication_urbanization_and_more.py} (92%) rename src/registrar/migrations/{0050_alter_domainapplication_anything_else_and_more.py => 0052_alter_domainapplication_anything_else_and_more.py} (90%) diff --git a/src/registrar/migrations/0051_alter_transitiondomain_status.py b/src/registrar/migrations/0048_alter_transitiondomain_status.py similarity index 87% rename from src/registrar/migrations/0051_alter_transitiondomain_status.py rename to src/registrar/migrations/0048_alter_transitiondomain_status.py index 73386bada..d67c91e4b 100644 --- a/src/registrar/migrations/0051_alter_transitiondomain_status.py +++ b/src/registrar/migrations/0048_alter_transitiondomain_status.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0050_alter_domainapplication_anything_else_and_more"), + ("registrar", "0047_transitiondomain_address_line_transitiondomain_city_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py new file mode 100644 index 000000000..4341bdad6 --- /dev/null +++ b/src/registrar/migrations/0049_alter_domainapplication_current_websites_and_more.py @@ -0,0 +1,36 @@ +# Generated by Django 4.2.7 on 2023-12-05 10:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0048_alter_transitiondomain_status"), + ] + + operations = [ + migrations.AlterField( + model_name="domainapplication", + name="current_websites", + field=models.ManyToManyField( + blank=True, related_name="current+", to="registrar.website", verbose_name="websites" + ), + ), + migrations.AlterField( + model_name="domainapplication", + name="other_contacts", + field=models.ManyToManyField( + blank=True, related_name="contact_applications", to="registrar.contact", verbose_name="contacts" + ), + ), + migrations.AlterField( + model_name="domaininformation", + name="other_contacts", + field=models.ManyToManyField( + blank=True, + related_name="contact_applications_information", + to="registrar.contact", + verbose_name="contacts", + ), + ), + ] diff --git a/src/registrar/migrations/0048_alter_contact_middle_name_and_more.py b/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py similarity index 92% rename from src/registrar/migrations/0048_alter_contact_middle_name_and_more.py rename to src/registrar/migrations/0050_alter_contact_middle_name_and_more.py index 271264fc7..4009d17d9 100644 --- a/src/registrar/migrations/0048_alter_contact_middle_name_and_more.py +++ b/src/registrar/migrations/0050_alter_contact_middle_name_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0047_transitiondomain_address_line_transitiondomain_city_and_more"), + ("registrar", "0049_alter_domainapplication_current_websites_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0049_alter_domainapplication_urbanization_and_more.py b/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py similarity index 92% rename from src/registrar/migrations/0049_alter_domainapplication_urbanization_and_more.py rename to src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py index 36a32cb25..9b012042d 100644 --- a/src/registrar/migrations/0049_alter_domainapplication_urbanization_and_more.py +++ b/src/registrar/migrations/0051_alter_domainapplication_urbanization_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0048_alter_contact_middle_name_and_more"), + ("registrar", "0050_alter_contact_middle_name_and_more"), ] operations = [ diff --git a/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py b/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py similarity index 90% rename from src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py rename to src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py index a84e7e1c4..1d5607aad 100644 --- a/src/registrar/migrations/0050_alter_domainapplication_anything_else_and_more.py +++ b/src/registrar/migrations/0052_alter_domainapplication_anything_else_and_more.py @@ -5,7 +5,7 @@ from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("registrar", "0049_alter_domainapplication_urbanization_and_more"), + ("registrar", "0051_alter_domainapplication_urbanization_and_more"), ] operations = [ From 4386218f462630e97290cd422908f6c1bc5d6270 Mon Sep 17 00:00:00 2001 From: Rebecca Hsieh Date: Tue, 5 Dec 2023 14:48:53 -0800 Subject: [PATCH 234/245] Changes per designers request of updating naming to .gov registrar, moving the breadcrumb to the footer and fixing column grid alignment --- src/registrar/templates/base.html | 9 ++------- src/registrar/templates/domain_base.html | 18 +++++++++--------- src/registrar/templates/includes/footer.html | 4 ++++ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html index aad526f37..df22da7ba 100644 --- a/src/registrar/templates/base.html +++ b/src/registrar/templates/base.html @@ -150,16 +150,11 @@ {% block logo %} {% endblock %} - {% url 'domain' pk=domain.id as url %} - {% if request.path == url %} - - Manage your domains - - {% endif %} + diff --git a/src/registrar/templates/domain_base.html b/src/registrar/templates/domain_base.html index 530f97e66..9d23e4abd 100644 --- a/src/registrar/templates/domain_base.html +++ b/src/registrar/templates/domain_base.html @@ -5,17 +5,17 @@ {% block content %}
-
- {% if not is_analyst_or_superuser or not analyst_action or analyst_action_location != domain.pk %} -

- Domain name: {{ domain.name }} -

- {% endif %} -
+
+ {% if not is_analyst_or_superuser or not analyst_action or analyst_action_location != domain.pk %} +

+ Domain name: {{ domain.name }} +

+ {% endif %} + {% if domain.domain_info %} {% include 'domain_sidebar.html' %} {% endif %} diff --git a/src/registrar/templates/includes/footer.html b/src/registrar/templates/includes/footer.html index 47d4836f1..74d61c7cb 100644 --- a/src/registrar/templates/includes/footer.html +++ b/src/registrar/templates/includes/footer.html @@ -26,6 +26,10 @@ >