diff --git a/src/registrar/admin.py b/src/registrar/admin.py
index 6aabfdd52..6f4c7e75c 100644
--- a/src/registrar/admin.py
+++ b/src/registrar/admin.py
@@ -1500,6 +1500,8 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
"authorizing_official",
"other_contacts",
"no_other_contacts_rationale",
+ "cisa_representative_first_name",
+ "cisa_representative_last_name",
"cisa_representative_email",
]
},
@@ -1575,6 +1577,8 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin):
"no_other_contacts_rationale",
"anything_else",
"is_policy_acknowledged",
+ "cisa_representative_first_name",
+ "cisa_representative_last_name",
"cisa_representative_email",
]
autocomplete_fields = [
diff --git a/src/registrar/forms/domain_request_wizard.py b/src/registrar/forms/domain_request_wizard.py
index fc176ce82..61afd6b57 100644
--- a/src/registrar/forms/domain_request_wizard.py
+++ b/src/registrar/forms/domain_request_wizard.py
@@ -648,20 +648,27 @@ class NoOtherContactsForm(BaseDeletableRegistrarForm):
class CisaRepresentativeForm(BaseDeletableRegistrarForm):
+ cisa_representative_first_name = forms.CharField(
+ label="First name / given name",
+ error_messages={"required": "Enter the first name / given name of the CISA regional representative."},
+ )
+ cisa_representative_last_name = forms.CharField(
+ label="Last name / family name",
+ error_messages={"required": "Enter the last name / family name of the CISA regional representative."},
+ )
cisa_representative_email = forms.EmailField(
- required=True,
+ label="Your representative’s email (optional)",
max_length=None,
- label="Your representative’s email",
+ required=False,
+ error_messages={
+ "invalid": ("Enter your representative’s email address in the required format, like name@example.com."),
+ },
validators=[
MaxLengthValidator(
320,
message="Response must be less than 320 characters.",
)
],
- error_messages={
- "invalid": ("Enter your email address in the required format, like name@example.com."),
- "required": ("Enter the email address of your CISA regional representative."),
- },
)
diff --git a/src/registrar/migrations/0101_domaininformation_cisa_representative_first_name_and_more.py b/src/registrar/migrations/0101_domaininformation_cisa_representative_first_name_and_more.py
new file mode 100644
index 000000000..89f24a5e1
--- /dev/null
+++ b/src/registrar/migrations/0101_domaininformation_cisa_representative_first_name_and_more.py
@@ -0,0 +1,69 @@
+# Generated by Django 4.2.10 on 2024-06-12 20:50
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("registrar", "0100_domainrequest_action_needed_reason"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="domaininformation",
+ name="cisa_representative_first_name",
+ field=models.CharField(
+ blank=True, db_index=True, null=True, verbose_name="CISA regional representative first name"
+ ),
+ ),
+ migrations.AddField(
+ model_name="domaininformation",
+ name="cisa_representative_last_name",
+ field=models.CharField(
+ blank=True, db_index=True, null=True, verbose_name="CISA regional representative last name"
+ ),
+ ),
+ migrations.AddField(
+ model_name="domaininformation",
+ name="has_anything_else_text",
+ field=models.BooleanField(
+ blank=True, help_text="Determines if the user has a anything_else or not", null=True
+ ),
+ ),
+ migrations.AddField(
+ model_name="domaininformation",
+ name="has_cisa_representative",
+ field=models.BooleanField(
+ blank=True, help_text="Determines if the user has a representative email or not", null=True
+ ),
+ ),
+ migrations.AddField(
+ model_name="domainrequest",
+ name="cisa_representative_first_name",
+ field=models.CharField(
+ blank=True, db_index=True, null=True, verbose_name="CISA regional representative first name"
+ ),
+ ),
+ migrations.AddField(
+ model_name="domainrequest",
+ name="cisa_representative_last_name",
+ field=models.CharField(
+ blank=True, db_index=True, null=True, verbose_name="CISA regional representative last name"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="domaininformation",
+ name="cisa_representative_email",
+ field=models.EmailField(
+ blank=True, max_length=320, null=True, verbose_name="CISA regional representative email"
+ ),
+ ),
+ migrations.AlterField(
+ model_name="domainrequest",
+ name="cisa_representative_email",
+ field=models.EmailField(
+ blank=True, max_length=320, null=True, verbose_name="CISA regional representative email"
+ ),
+ ),
+ ]
diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py
index bc35d4e30..62db04ac8 100644
--- a/src/registrar/models/domain_information.py
+++ b/src/registrar/models/domain_information.py
@@ -214,13 +214,45 @@ class DomainInformation(TimeStampedModel):
verbose_name="Additional details",
)
+ # This is a drop-in replacement for a has_anything_else_text() function.
+ # In order to track if the user has clicked the yes/no field (while keeping a none default), we need
+ # a tertiary state. We should not display this in /admin.
+ has_anything_else_text = models.BooleanField(
+ null=True,
+ blank=True,
+ help_text="Determines if the user has a anything_else or not",
+ )
+
cisa_representative_email = models.EmailField(
null=True,
blank=True,
- verbose_name="CISA regional representative",
+ verbose_name="CISA regional representative email",
max_length=320,
)
+ cisa_representative_first_name = models.CharField(
+ null=True,
+ blank=True,
+ verbose_name="CISA regional representative first name",
+ db_index=True,
+ )
+
+ cisa_representative_last_name = models.CharField(
+ null=True,
+ blank=True,
+ verbose_name="CISA regional representative last name",
+ db_index=True,
+ )
+
+ # This is a drop-in replacement for an has_cisa_representative() function.
+ # In order to track if the user has clicked the yes/no field (while keeping a none default), we need
+ # a tertiary state. We should not display this in /admin.
+ has_cisa_representative = models.BooleanField(
+ null=True,
+ blank=True,
+ help_text="Determines if the user has a representative email or not",
+ )
+
is_policy_acknowledged = models.BooleanField(
null=True,
blank=True,
@@ -241,6 +273,30 @@ class DomainInformation(TimeStampedModel):
except Exception:
return ""
+ def sync_yes_no_form_fields(self):
+ """Some yes/no forms use a db field to track whether it was checked or not.
+ We handle that here for def save().
+ """
+ # This ensures that if we have prefilled data, the form is prepopulated
+ if self.cisa_representative_first_name is not None or self.cisa_representative_last_name is not None:
+ self.has_cisa_representative = (
+ self.cisa_representative_first_name != "" and self.cisa_representative_last_name != ""
+ )
+
+ # This check is required to ensure that the form doesn't start out checked
+ if self.has_cisa_representative is not None:
+ self.has_cisa_representative = (
+ self.cisa_representative_first_name != "" and self.cisa_representative_first_name is not None
+ ) and (self.cisa_representative_last_name != "" and self.cisa_representative_last_name is not None)
+
+ # This ensures that if we have prefilled data, the form is prepopulated
+ if self.anything_else is not None:
+ self.has_anything_else_text = self.anything_else != ""
+
+ # This check is required to ensure that the form doesn't start out checked.
+ if self.has_anything_else_text is not None:
+ self.has_anything_else_text = self.anything_else != "" and self.anything_else is not None
+
def sync_organization_type(self):
"""
Updates the organization_type (without saving) to match
@@ -275,6 +331,7 @@ class DomainInformation(TimeStampedModel):
def save(self, *args, **kwargs):
"""Save override for custom properties"""
+ self.sync_yes_no_form_fields()
self.sync_organization_type()
super().save(*args, **kwargs)
diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py
index 8dfa419c9..1ad8ae7b3 100644
--- a/src/registrar/models/domain_request.py
+++ b/src/registrar/models/domain_request.py
@@ -477,10 +477,24 @@ class DomainRequest(TimeStampedModel):
cisa_representative_email = models.EmailField(
null=True,
blank=True,
- verbose_name="CISA regional representative",
+ verbose_name="CISA regional representative email",
max_length=320,
)
+ cisa_representative_first_name = models.CharField(
+ null=True,
+ blank=True,
+ verbose_name="CISA regional representative first name",
+ db_index=True,
+ )
+
+ cisa_representative_last_name = models.CharField(
+ null=True,
+ blank=True,
+ verbose_name="CISA regional representative last name",
+ db_index=True,
+ )
+
# This is a drop-in replacement for an has_cisa_representative() function.
# In order to track if the user has clicked the yes/no field (while keeping a none default), we need
# a tertiary state. We should not display this in /admin.
@@ -577,16 +591,17 @@ class DomainRequest(TimeStampedModel):
"""Some yes/no forms use a db field to track whether it was checked or not.
We handle that here for def save().
"""
-
# This ensures that if we have prefilled data, the form is prepopulated
- if self.cisa_representative_email is not None:
- self.has_cisa_representative = self.cisa_representative_email != ""
+ if self.cisa_representative_first_name is not None or self.cisa_representative_last_name is not None:
+ self.has_cisa_representative = (
+ self.cisa_representative_first_name != "" and self.cisa_representative_last_name != ""
+ )
# This check is required to ensure that the form doesn't start out checked
if self.has_cisa_representative is not None:
self.has_cisa_representative = (
- self.cisa_representative_email != "" and self.cisa_representative_email is not None
- )
+ self.cisa_representative_first_name != "" and self.cisa_representative_first_name is not None
+ ) and (self.cisa_representative_last_name != "" and self.cisa_representative_last_name is not None)
# This ensures that if we have prefilled data, the form is prepopulated
if self.anything_else is not None:
@@ -984,11 +999,12 @@ class DomainRequest(TimeStampedModel):
def has_additional_details(self) -> bool:
"""Combines the has_anything_else_text and has_cisa_representative fields,
then returns if this domain request has either of them."""
- # Split out for linter
- has_details = False
- if self.has_anything_else_text or self.has_cisa_representative:
- has_details = True
+ # Split out for linter
+ has_details = True
+
+ if self.has_anything_else_text is None or self.has_cisa_representative is None:
+ has_details = False
return has_details
def is_federal(self) -> Union[bool, None]:
@@ -1097,14 +1113,19 @@ class DomainRequest(TimeStampedModel):
return True
return False
- def _cisa_rep_and_email_check(self):
- # Has a CISA rep + email is NOT empty or NOT an empty string OR doesn't have CISA rep
- return (
+ def _cisa_rep_check(self):
+ # Either does not have a CISA rep, OR has a CISA rep + both first name
+ # and last name are NOT empty and are NOT an empty string
+ to_return = (
self.has_cisa_representative is True
- and self.cisa_representative_email is not None
- and self.cisa_representative_email != ""
+ and self.cisa_representative_first_name is not None
+ and self.cisa_representative_first_name != ""
+ and self.cisa_representative_last_name is not None
+ and self.cisa_representative_last_name != ""
) or self.has_cisa_representative is False
+ return to_return
+
def _anything_else_radio_button_and_text_field_check(self):
# Anything else boolean is True + filled text field and it's not an empty string OR the boolean is No
return (
@@ -1112,7 +1133,7 @@ class DomainRequest(TimeStampedModel):
) or self.has_anything_else_text is False
def _is_additional_details_complete(self):
- return self._cisa_rep_and_email_check() and self._anything_else_radio_button_and_text_field_check()
+ return self._cisa_rep_check() and self._anything_else_radio_button_and_text_field_check()
def _is_policy_acknowledgement_complete(self):
return self.is_policy_acknowledged is not None
diff --git a/src/registrar/templates/domain_request_additional_details.html b/src/registrar/templates/domain_request_additional_details.html
index e13d3c7ee..96c89d8ad 100644
--- a/src/registrar/templates/domain_request_additional_details.html
+++ b/src/registrar/templates/domain_request_additional_details.html
@@ -9,7 +9,6 @@
{# commented out so it does not appear at this point on this page #}
{% endblock %}
-
{% block form_fields %}
-
+
+ {% input_with_errors forms.1.cisa_representative_first_name %}
+ {% input_with_errors forms.1.cisa_representative_last_name %}
{% input_with_errors forms.1.cisa_representative_email %}
{# forms.1 is a form for inputting the e-mail of a cisa representative #}
-
@@ -42,7 +41,6 @@
{% input_with_errors forms.2.has_anything_else_text %}
{% endwith %}
{# forms.2 is a small yes/no form that toggles the visibility of "cisa representative" formset #}
-
@@ -50,6 +48,5 @@
{% input_with_errors forms.3.anything_else %}
{% endwith %}
{# forms.3 is a form for inputting the e-mail of a cisa representative #}
-
{% endblock %}
diff --git a/src/registrar/templates/domain_request_review.html b/src/registrar/templates/domain_request_review.html
index 1f21683a5..bb8ad498e 100644
--- a/src/registrar/templates/domain_request_review.html
+++ b/src/registrar/templates/domain_request_review.html
@@ -157,18 +157,33 @@
{% if step == Step.ADDITIONAL_DETAILS %}
{% namespaced_url 'domain-request' step as domain_request_url %}
- {% with title=form_titles|get_item:step value=domain_request.requested_domain.name|default:"Incomplete"|safe %}
- {% include "includes/summary_item.html" with title=title sub_header_text='CISA regional representative' value=domain_request.cisa_representative_email heading_level=heading_level editable=True edit_link=domain_request_url custom_text_for_value_none='No' %}
- {% endwith %}
+ {% with title=form_titles|get_item:step %}
+ {% if domain_request.has_additional_details %}
+ {% include "includes/summary_item.html" with title="Additional Details" value=" " heading_level=heading_level editable=True edit_link=domain_request_url %}
+
CISA Regional Representative
+
+ {% if domain_request.cisa_representative_first_name %}
+
diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py
index f049388df..f6ad8d3e9 100644
--- a/src/registrar/tests/common.py
+++ b/src/registrar/tests/common.py
@@ -808,12 +808,13 @@ def create_ready_domain():
# TODO in 1793: Remove the federal agency/updated federal agency fields
-def completed_domain_request(
+def completed_domain_request( # noqa
has_other_contacts=True,
has_current_website=True,
has_alternative_gov_domain=True,
has_about_your_organization=True,
has_anything_else=True,
+ has_cisa_representative=True,
status=DomainRequest.DomainRequestStatus.STARTED,
user=False,
submitter=False,
@@ -895,6 +896,10 @@ def completed_domain_request(
domain_request.current_websites.add(current)
if has_alternative_gov_domain:
domain_request.alternative_domains.add(alt)
+ if has_cisa_representative:
+ domain_request.cisa_representative_first_name = "CISA-first-name"
+ domain_request.cisa_representative_last_name = "CISA-last-name"
+ domain_request.cisa_representative_email = "cisaRep@igorville.gov"
return domain_request
diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py
index ff19d06be..e567f9329 100644
--- a/src/registrar/tests/test_admin.py
+++ b/src/registrar/tests/test_admin.py
@@ -2326,6 +2326,8 @@ class TestDomainRequestAdmin(MockEppLib):
"anything_else",
"has_anything_else_text",
"cisa_representative_email",
+ "cisa_representative_first_name",
+ "cisa_representative_last_name",
"has_cisa_representative",
"is_policy_acknowledged",
"submission_date",
@@ -2358,6 +2360,8 @@ class TestDomainRequestAdmin(MockEppLib):
"no_other_contacts_rationale",
"anything_else",
"is_policy_acknowledged",
+ "cisa_representative_first_name",
+ "cisa_representative_last_name",
"cisa_representative_email",
]
diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py
index e42451be9..53af1674e 100644
--- a/src/registrar/tests/test_models.py
+++ b/src/registrar/tests/test_models.py
@@ -1802,93 +1802,129 @@ class TestDomainRequestIncomplete(TestCase):
def test_is_additional_details_complete(self):
test_cases = [
# CISA Rep - Yes
+ # Firstname - Yes
+ # Lastname - Yes
# Email - Yes
# Anything Else Radio - Yes
# Anything Else Text - Yes
{
"has_cisa_representative": True,
+ "cisa_representative_first_name": "cisa-first-name",
+ "cisa_representative_last_name": "cisa-last-name",
"cisa_representative_email": "some@cisarepemail.com",
"has_anything_else_text": True,
"anything_else": "Some text",
"expected": True,
},
# CISA Rep - Yes
+ # Firstname - Yes
+ # Lastname - Yes
# Email - Yes
# Anything Else Radio - Yes
# Anything Else Text - None
{
"has_cisa_representative": True,
+ "cisa_representative_first_name": "cisa-first-name",
+ "cisa_representative_last_name": "cisa-last-name",
"cisa_representative_email": "some@cisarepemail.com",
"has_anything_else_text": True,
"anything_else": None,
"expected": True,
},
# CISA Rep - Yes
- # Email - Yes
+ # Firstname - Yes
+ # Lastname - Yes
+ # Email - None >> e-mail is optional so it should not change anything setting this to None
# Anything Else Radio - No
# Anything Else Text - No
{
"has_cisa_representative": True,
- "cisa_representative_email": "some@cisarepemail.com",
+ "cisa_representative_first_name": "cisa-first-name",
+ "cisa_representative_last_name": "cisa-last-name",
+ "cisa_representative_email": None,
"has_anything_else_text": False,
"anything_else": None,
"expected": True,
},
# CISA Rep - Yes
- # Email - Yes
- # Anything Else Radio - None
- # Anything Else Text - None
- {
- "has_cisa_representative": True,
- "cisa_representative_email": "some@cisarepemail.com",
- "has_anything_else_text": None,
- "anything_else": None,
- "expected": False,
- },
- # CISA Rep - Yes
+ # Firstname - Yes
+ # Lastname - Yes
# Email - None
# Anything Else Radio - None
# Anything Else Text - None
{
"has_cisa_representative": True,
+ "cisa_representative_first_name": "cisa-first-name",
+ "cisa_representative_last_name": "cisa-last-name",
"cisa_representative_email": None,
"has_anything_else_text": None,
"anything_else": None,
"expected": False,
},
# CISA Rep - Yes
+ # Firstname - None
+ # Lastname - None
+ # Email - None
+ # Anything Else Radio - None
+ # Anything Else Text - None
+ {
+ "has_cisa_representative": True,
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
+ "cisa_representative_email": None,
+ "has_anything_else_text": None,
+ "anything_else": None,
+ "expected": False,
+ },
+ # CISA Rep - Yes
+ # Firstname - None
+ # Lastname - None
# Email - None
# Anything Else Radio - No
# Anything Else Text - No
- # sync_yes_no will override has_cisa_representative to be False if cisa_representative_email is None
+ # sync_yes_no will override has_cisa_representative to be False if cisa_representative_first_name is None
# therefore, our expected will be True
{
"has_cisa_representative": True,
- # Above will be overridden to False if cisa_rep_email is None bc of sync_yes_no_form_fields
+ # Above will be overridden to False if cisa_representative_first_name is None
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": False,
"anything_else": None,
"expected": True,
},
# CISA Rep - Yes
+ # Firstname - None
+ # Lastname - None
# Email - None
# Anything Else Radio - Yes
# Anything Else Text - None
+ # NOTE: We should never have an instance where only firstname or only lastname are populated
+ # (they are both required)
{
"has_cisa_representative": True,
- # Above will be overridden to False if cisa_rep_email is None bc of sync_yes_no_form_fields
+ # Above will be overridden to False if cisa_representative_first_name is None or
+ # cisa_representative_last_name is None bc of sync_yes_no_form_fields
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": True,
"anything_else": None,
"expected": True,
},
# CISA Rep - Yes
+ # Firstname - None
+ # Lastname - None
# Email - None
# Anything Else Radio - Yes
# Anything Else Text - Yes
{
"has_cisa_representative": True,
- # Above will be overridden to False if cisa_rep_email is None bc of sync_yes_no_form_fields
+ # Above will be overridden to False if cisa_representative_first_name is None or
+ # cisa_representative_last_name is None bc of sync_yes_no_form_fields
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": True,
"anything_else": "Some text",
@@ -1899,6 +1935,8 @@ class TestDomainRequestIncomplete(TestCase):
# Anything Else Text - Yes
{
"has_cisa_representative": False,
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": True,
"anything_else": "Some text",
@@ -1909,6 +1947,8 @@ class TestDomainRequestIncomplete(TestCase):
# Anything Else Text - None
{
"has_cisa_representative": False,
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": True,
"anything_else": None,
@@ -1919,6 +1959,8 @@ class TestDomainRequestIncomplete(TestCase):
# Anything Else Text - None
{
"has_cisa_representative": False,
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": None,
"anything_else": None,
@@ -1930,6 +1972,8 @@ class TestDomainRequestIncomplete(TestCase):
# Anything Else Text - No
{
"has_cisa_representative": False,
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": False,
"anything_else": None,
@@ -1939,6 +1983,8 @@ class TestDomainRequestIncomplete(TestCase):
# Anything Else Radio - None
{
"has_cisa_representative": None,
+ "cisa_representative_first_name": None,
+ "cisa_representative_last_name": None,
"cisa_representative_email": None,
"has_anything_else_text": None,
"anything_else": None,
diff --git a/src/registrar/tests/test_views_request.py b/src/registrar/tests/test_views_request.py
index 4f2170c87..b46b89b9a 100644
--- a/src/registrar/tests/test_views_request.py
+++ b/src/registrar/tests/test_views_request.py
@@ -366,6 +366,8 @@ class DomainRequestTests(TestWithUser, WebTest):
additional_details_form["additional_details-has_cisa_representative"] = "True"
additional_details_form["additional_details-has_anything_else_text"] = "True"
+ additional_details_form["additional_details-cisa_representative_first_name"] = "CISA-first-name"
+ additional_details_form["additional_details-cisa_representative_last_name"] = "CISA-last-name"
additional_details_form["additional_details-cisa_representative_email"] = "FakeEmail@gmail.com"
additional_details_form["additional_details-anything_else"] = "Nothing else."
@@ -374,6 +376,8 @@ class DomainRequestTests(TestWithUser, WebTest):
additional_details_result = additional_details_form.submit()
# validate that data from this step are being saved
domain_request = DomainRequest.objects.get() # there's only one
+ self.assertEqual(domain_request.cisa_representative_first_name, "CISA-first-name")
+ self.assertEqual(domain_request.cisa_representative_last_name, "CISA-last-name")
self.assertEqual(domain_request.cisa_representative_email, "FakeEmail@gmail.com")
self.assertEqual(domain_request.anything_else, "Nothing else.")
# the post request should return a redirect to the next form in
@@ -719,6 +723,8 @@ class DomainRequestTests(TestWithUser, WebTest):
additional_details_form["additional_details-has_cisa_representative"] = "True"
additional_details_form["additional_details-has_anything_else_text"] = "True"
+ additional_details_form["additional_details-cisa_representative_first_name"] = "cisa-first-name"
+ additional_details_form["additional_details-cisa_representative_last_name"] = "cisa-last-name"
additional_details_form["additional_details-cisa_representative_email"] = "FakeEmail@gmail.com"
additional_details_form["additional_details-anything_else"] = "Nothing else."
@@ -727,6 +733,8 @@ class DomainRequestTests(TestWithUser, WebTest):
additional_details_result = additional_details_form.submit()
# validate that data from this step are being saved
domain_request = DomainRequest.objects.get() # there's only one
+ self.assertEqual(domain_request.cisa_representative_first_name, "cisa-first-name")
+ self.assertEqual(domain_request.cisa_representative_last_name, "cisa-last-name")
self.assertEqual(domain_request.cisa_representative_email, "FakeEmail@gmail.com")
self.assertEqual(domain_request.anything_else, "Nothing else.")
# the post request should return a redirect to the next form in
@@ -1125,11 +1133,10 @@ class DomainRequestTests(TestWithUser, WebTest):
def test_yes_no_form_inits_yes_for_cisa_representative_and_anything_else(self):
"""On the Additional Details page, the yes/no form gets initialized with YES selected
- for both yes/no radios if the domain request has a value for cisa_representative and
+ for both yes/no radios if the domain request has a values for cisa_representative_first_name and
anything_else"""
- domain_request = completed_domain_request(user=self.user, has_anything_else=True)
- domain_request.cisa_representative_email = "test@igorville.gov"
+ domain_request = completed_domain_request(user=self.user, has_anything_else=True, has_cisa_representative=True)
domain_request.anything_else = "1234"
domain_request.save()
@@ -1181,12 +1188,13 @@ class DomainRequestTests(TestWithUser, WebTest):
"""On the Additional details page, the form preselects "no" when has_cisa_representative
and anything_else is no"""
- domain_request = completed_domain_request(user=self.user, has_anything_else=False)
+ domain_request = completed_domain_request(
+ user=self.user, has_anything_else=False, has_cisa_representative=False
+ )
# Unlike the other contacts form, the no button is tracked with these boolean fields.
# This means that we should expect this to correlate with the no button.
domain_request.has_anything_else_text = False
- domain_request.has_cisa_representative = False
domain_request.save()
# prime the form by visiting /edit
@@ -1205,7 +1213,7 @@ class DomainRequestTests(TestWithUser, WebTest):
# Check the cisa representative yes/no field
yes_no_cisa = additional_details_form["additional_details-has_cisa_representative"].value
- self.assertEquals(yes_no_cisa, "False")
+ self.assertEquals(yes_no_cisa, None)
# Check the anything else yes/no field
yes_no_anything_else = additional_details_form["additional_details-has_anything_else_text"].value
@@ -1215,11 +1223,15 @@ class DomainRequestTests(TestWithUser, WebTest):
"""When a user submits the Additional Details form with no selected for all fields,
the domain request's data gets wiped when submitted"""
domain_request = completed_domain_request(name="nocisareps.gov", user=self.user)
+ domain_request.cisa_representative_first_name = "cisa-firstname1"
+ domain_request.cisa_representative_last_name = "cisa-lastname1"
domain_request.cisa_representative_email = "fake@faketown.gov"
domain_request.save()
# Make sure we have the data we need for the test
self.assertEqual(domain_request.anything_else, "There is more")
+ self.assertEqual(domain_request.cisa_representative_first_name, "cisa-firstname1")
+ self.assertEqual(domain_request.cisa_representative_last_name, "cisa-lastname1")
self.assertEqual(domain_request.cisa_representative_email, "fake@faketown.gov")
# prime the form by visiting /edit
@@ -1253,25 +1265,31 @@ class DomainRequestTests(TestWithUser, WebTest):
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # Verify that the anything_else and cisa_representative have been deleted from the DB
+ # Verify that the anything_else and cisa_representative information have been deleted from the DB
domain_request = DomainRequest.objects.get(requested_domain__name="nocisareps.gov")
# Check that our data has been cleared
self.assertEqual(domain_request.anything_else, None)
+ self.assertEqual(domain_request.cisa_representative_first_name, None)
+ self.assertEqual(domain_request.cisa_representative_last_name, None)
self.assertEqual(domain_request.cisa_representative_email, None)
# Double check the yes/no fields
self.assertEqual(domain_request.has_anything_else_text, False)
- self.assertEqual(domain_request.has_cisa_representative, False)
+ self.assertEqual(domain_request.cisa_representative_first_name, None)
+ self.assertEqual(domain_request.cisa_representative_last_name, None)
+ self.assertEqual(domain_request.cisa_representative_email, None)
def test_submitting_additional_details_populates_cisa_representative_and_anything_else(self):
"""When a user submits the Additional Details form,
the domain request's data gets submitted"""
- domain_request = completed_domain_request(name="cisareps.gov", user=self.user, has_anything_else=False)
+ domain_request = completed_domain_request(
+ name="cisareps.gov", user=self.user, has_anything_else=False, has_cisa_representative=False
+ )
# Make sure we have the data we need for the test
self.assertEqual(domain_request.anything_else, None)
- self.assertEqual(domain_request.cisa_representative_email, None)
+ self.assertEqual(domain_request.cisa_representative_first_name, None)
# These fields should not be selected at all, since we haven't initialized the form yet
self.assertEqual(domain_request.has_anything_else_text, None)
@@ -1294,6 +1312,8 @@ class DomainRequestTests(TestWithUser, WebTest):
# Set fields to true, and set data on those fields
additional_details_form["additional_details-has_cisa_representative"] = "True"
additional_details_form["additional_details-has_anything_else_text"] = "True"
+ additional_details_form["additional_details-cisa_representative_first_name"] = "cisa-firstname"
+ additional_details_form["additional_details-cisa_representative_last_name"] = "cisa-lastname"
additional_details_form["additional_details-cisa_representative_email"] = "test@faketest.gov"
additional_details_form["additional_details-anything_else"] = "redandblue"
@@ -1302,10 +1322,12 @@ class DomainRequestTests(TestWithUser, WebTest):
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- # Verify that the anything_else and cisa_representative exist in the db
+ # Verify that the anything_else and cisa_representative information exist in the db
domain_request = DomainRequest.objects.get(requested_domain__name="cisareps.gov")
self.assertEqual(domain_request.anything_else, "redandblue")
+ self.assertEqual(domain_request.cisa_representative_first_name, "cisa-firstname")
+ self.assertEqual(domain_request.cisa_representative_last_name, "cisa-lastname")
self.assertEqual(domain_request.cisa_representative_email, "test@faketest.gov")
self.assertEqual(domain_request.has_cisa_representative, True)
@@ -1313,7 +1335,9 @@ class DomainRequestTests(TestWithUser, WebTest):
def test_if_cisa_representative_yes_no_form_is_yes_then_field_is_required(self):
"""Applicants with a cisa representative must provide a value"""
- domain_request = completed_domain_request(name="cisareps.gov", user=self.user, has_anything_else=False)
+ domain_request = completed_domain_request(
+ name="cisareps.gov", user=self.user, has_anything_else=False, has_cisa_representative=False
+ )
# prime the form by visiting /edit
self.app.get(reverse("edit-domain-request", kwargs={"id": domain_request.pk}))
@@ -1338,7 +1362,8 @@ class DomainRequestTests(TestWithUser, WebTest):
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
- self.assertContains(response, "Enter the email address of your CISA regional representative.")
+ self.assertContains(response, "Enter the first name / given name of the CISA regional representative.")
+ self.assertContains(response, "Enter the last name / family name of the CISA regional representative.")
def test_if_anything_else_yes_no_form_is_yes_then_field_is_required(self):
"""Applicants with a anything else must provide a value"""
@@ -1373,7 +1398,9 @@ class DomainRequestTests(TestWithUser, WebTest):
def test_additional_details_form_fields_required(self):
"""When a user submits the Additional Details form without checking the
has_cisa_representative and has_anything_else_text fields, the form should deny this action"""
- domain_request = completed_domain_request(name="cisareps.gov", user=self.user, has_anything_else=False)
+ domain_request = completed_domain_request(
+ name="cisareps.gov", user=self.user, has_anything_else=False, has_cisa_representative=False
+ )
self.assertEqual(domain_request.has_anything_else_text, None)
self.assertEqual(domain_request.has_cisa_representative, None)
diff --git a/src/registrar/utility/csv_export.py b/src/registrar/utility/csv_export.py
index 3f6cc6b0e..6d3079bc1 100644
--- a/src/registrar/utility/csv_export.py
+++ b/src/registrar/utility/csv_export.py
@@ -381,6 +381,7 @@ def export_data_type_to_csv(csv_file):
"""
All domains report with extra columns.
This maps to the "All domain metadata" button.
+ Exports domains of all statuses.
"""
writer = csv.writer(csv_file)
@@ -408,15 +409,8 @@ def export_data_type_to_csv(csv_file):
"federal_agency",
"domain__name",
]
- filter_condition = {
- "domain__state__in": [
- Domain.State.READY,
- Domain.State.DNS_NEEDED,
- Domain.State.ON_HOLD,
- ],
- }
write_csv_for_domains(
- writer, columns, sort_fields, filter_condition, should_get_domain_managers=True, should_write_header=True
+ writer, columns, sort_fields, filter_condition={}, should_get_domain_managers=True, should_write_header=True
)
diff --git a/src/registrar/views/domain_request.py b/src/registrar/views/domain_request.py
index 95a139211..d14262107 100644
--- a/src/registrar/views/domain_request.py
+++ b/src/registrar/views/domain_request.py
@@ -369,7 +369,7 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
or self.domain_request.no_other_contacts_rationale is not None
),
"additional_details": (
- (self.domain_request.anything_else is not None and self.domain_request.cisa_representative_email)
+ (self.domain_request.anything_else is not None and self.domain_request.has_cisa_representative)
or self.domain_request.is_policy_acknowledged is not None
),
"requirements": self.domain_request.is_policy_acknowledged is not None,
@@ -380,7 +380,6 @@ class DomainRequestWizard(DomainRequestWizardPermissionView, TemplateView):
def get_context_data(self):
"""Define context for access on all wizard pages."""
has_profile_flag = flag_is_active(self.request, "profile_feature")
- logger.debug("PROFILE FLAG is %s" % has_profile_flag)
context_stuff = {}
if DomainRequest._form_complete(self.domain_request):