diff --git a/src/registrar/admin.py b/src/registrar/admin.py index a0c14efff..63bb7ff55 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1376,7 +1376,9 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): "authorizing_official", "other_contacts", "no_other_contacts_rationale", - "cisa_representative", + "cisa_representative_first_name", + "cisa_representative_last_name", + "cisa_representative_email", ] }, ), @@ -1452,8 +1454,10 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportModelAdmin): "no_other_contacts_rationale", "anything_else", "is_policy_acknowledged", - "cisa_representative", - ] + "cisa_representative_first_name", + "cisa_representative_last_name", + "cisa_representative_email", +] autocomplete_fields = [ "approved_domain", "requested_domain", diff --git a/src/registrar/forms/domain_request_wizard.py b/src/registrar/forms/domain_request_wizard.py index ecb84e62a..9df4a4c1a 100644 --- a/src/registrar/forms/domain_request_wizard.py +++ b/src/registrar/forms/domain_request_wizard.py @@ -647,47 +647,20 @@ class NoOtherContactsForm(BaseDeletableRegistrarForm): class CisaRepresentativeForm(BaseDeletableRegistrarForm): - JOIN = "cisa_representative" - - def to_database(self, obj): - if not self.is_valid(): - return - contact = getattr(obj, "cisa_representative", None) - if contact is not None and not contact.has_more_than_one_join("cisa_representative_domain_requests"): - if self.form_data_marked_for_deletion: - # remove the CISA contact from this domain request - obj.cisa_representative = None - # QUESTION - should we also delete the contact object if it is not joined to other entities? - else: - # update existing contact if it is not joined to other enttities - super().to_database(contact) - else: - # no contact exists OR contact exists which is joined also to other entities; - # in either case, create a new contact and update it - contact = Contact() - super().to_database(contact) - obj.cisa_representative = contact - obj.save() - - @classmethod - def from_database(cls, obj): - contact = getattr(obj, "cisa_representative", None) - return super().from_database(contact) - - first_name = forms.CharField( + cisa_representative_first_name = forms.CharField( label="First name / given name", error_messages={"required": "Enter your first name / given name."}, ) - last_name = forms.CharField( + cisa_representative_last_name = forms.CharField( label="Last name / family name", error_messages={"required": "Enter your last name / family name."}, ) - email = forms.EmailField( - label="Email", + cisa_representative_email = forms.EmailField( + label="Your representative’s email (optional)", max_length=None, required=False, error_messages={ - "invalid": ("Enter your email address in the required format, like name@example.com."), + "invalid": ("Enter your representative’s email address in the required format, like name@example.com."), }, validators=[ MaxLengthValidator( @@ -698,6 +671,7 @@ class CisaRepresentativeForm(BaseDeletableRegistrarForm): ) + class CisaRepresentativeYesNoForm(BaseYesNoForm): """Yes/no toggle for the CISA regions question on additional details""" diff --git a/src/registrar/migrations/0095_domaininformation_cisa_representative_first_name_and_more.py b/src/registrar/migrations/0095_domaininformation_cisa_representative_first_name_and_more.py new file mode 100644 index 000000000..f6f66ab23 --- /dev/null +++ b/src/registrar/migrations/0095_domaininformation_cisa_representative_first_name_and_more.py @@ -0,0 +1,55 @@ +# Generated by Django 4.2.10 on 2024-05-31 21:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0094_create_groups_v12"), + ] + + 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="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/migrations/0095_remove_domaininformation_cisa_representative_email_and_more.py b/src/registrar/migrations/0095_remove_domaininformation_cisa_representative_email_and_more.py deleted file mode 100644 index 7e7fb5ee6..000000000 --- a/src/registrar/migrations/0095_remove_domaininformation_cisa_representative_email_and_more.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 4.2.10 on 2024-05-16 23:08 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ("registrar", "0094_create_groups_v12"), - ] - - operations = [ - migrations.RemoveField( - model_name="domaininformation", - name="cisa_representative_email", - ), - migrations.RemoveField( - model_name="domainrequest", - name="cisa_representative_email", - ), - migrations.AddField( - model_name="domaininformation", - name="cisa_representative", - field=models.ForeignKey( - blank=True, - help_text='Cisa Representative listed under "additional information" in the request form', - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="cisa_representative_domain_requests_information", - to="registrar.contact", - ), - ), - migrations.AddField( - model_name="domainrequest", - name="cisa_representative", - field=models.ForeignKey( - blank=True, - help_text='Cisa Representative listed under "additional information" in the request form', - null=True, - on_delete=django.db.models.deletion.PROTECT, - related_name="cisa_representative_domain_requests", - to="registrar.contact", - ), - ), - ] diff --git a/src/registrar/models/domain_information.py b/src/registrar/models/domain_information.py index bf6db1a28..d2300c784 100644 --- a/src/registrar/models/domain_information.py +++ b/src/registrar/models/domain_information.py @@ -206,13 +206,25 @@ class DomainInformation(TimeStampedModel): verbose_name="Additional details", ) - cisa_representative = models.ForeignKey( - "registrar.Contact", + cisa_representative_email = models.EmailField( null=True, blank=True, - related_name="cisa_representative_domain_requests_information", - on_delete=models.PROTECT, - help_text='Cisa Representative listed under "additional information" in the request form', + 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, ) is_policy_acknowledged = models.BooleanField( diff --git a/src/registrar/models/domain_request.py b/src/registrar/models/domain_request.py index 5adc3e91b..f84451543 100644 --- a/src/registrar/models/domain_request.py +++ b/src/registrar/models/domain_request.py @@ -457,13 +457,25 @@ class DomainRequest(TimeStampedModel): help_text="Determines if the user has a anything_else or not", ) - cisa_representative = models.ForeignKey( - "registrar.Contact", + cisa_representative_email = models.EmailField( null=True, blank=True, - related_name="cisa_representative_domain_requests", - on_delete=models.PROTECT, - help_text='Cisa Representative listed under "additional information" in the request form', + 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. @@ -536,17 +548,18 @@ class DomainRequest(TimeStampedModel): We handle that here for def save(). """ - cisa_rep_is_not_none = self.cisa_representative is not None - cisa_first_name = None - # This ensures that if we have prefilled data, the form is prepopulated - if cisa_rep_is_not_none: - cisa_first_name = self.cisa_representative.first_name - self.has_cisa_representative = cisa_first_name is not None and cisa_first_name != "" + # NOTE: this relies on the fact that the first and last names of a CISA representative + # are required fields. Because of this, we can simplify the check to only look at the + # first name to determine whether or not a CISA representative was provided. + if self.cisa_representative_first_name is not None: + self.has_cisa_representative = self.cisa_representative_first_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 = cisa_first_name is not None and cisa_first_name != "" + self.has_cisa_representative = ( + self.cisa_representative_first_name != "" and self.cisa_representative_first_name is not None + ) # This ensures that if we have prefilled data, the form is prepopulated if self.anything_else is not None: diff --git a/src/registrar/templates/domain_request_additional_details.html b/src/registrar/templates/domain_request_additional_details.html index e8bdb5620..96c89d8ad 100644 --- a/src/registrar/templates/domain_request_additional_details.html +++ b/src/registrar/templates/domain_request_additional_details.html @@ -23,10 +23,10 @@ {# forms.0 is a small yes/no form that toggles the visibility of "cisa representative" formset #} -