mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-05 17:28:31 +02:00
Merge pull request #1876 from cisagov/za/1701-prevent-federal-agency-modifying-AO
(Not on a sandbox) Ticket #1701: Prevent AO modification for federal and tribal
This commit is contained in:
commit
8f8402ffc5
9 changed files with 473 additions and 23 deletions
|
@ -38,3 +38,18 @@ legend.float-left-tablet + button.float-right-tablet {
|
|||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
// Custom style for disabled inputs
|
||||
@media (prefers-color-scheme: light) {
|
||||
.usa-input:disabled, .usa-select:disabled, .usa-textarea:disabled {
|
||||
background-color: #eeeeee;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.usa-input:disabled, .usa-select:disabled, .usa-textarea:disabled {
|
||||
background-color: var(--body-fg);
|
||||
color: var(--close-button-hover-bg);
|
||||
}
|
||||
}
|
|
@ -126,7 +126,6 @@ in the form $setting: value,
|
|||
----------------------------*/
|
||||
$theme-input-line-height: 5,
|
||||
|
||||
|
||||
/*---------------------------
|
||||
# Component settings
|
||||
-----------------------------
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
"""Forms for domain management."""
|
||||
|
||||
import logging
|
||||
from django import forms
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator, RegexValidator
|
||||
from django.forms import formset_factory
|
||||
|
||||
from registrar.models import DomainRequest
|
||||
from phonenumber_field.widgets import RegionalPhoneNumberWidget
|
||||
from registrar.models.utility.domain_helper import DomainHelper
|
||||
from registrar.utility.errors import (
|
||||
NameserverError,
|
||||
NameserverErrorCodes as nsErrorCodes,
|
||||
|
@ -23,6 +25,9 @@ from .common import (
|
|||
import re
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class DomainAddUserForm(forms.Form):
|
||||
"""Form for adding a user to a domain."""
|
||||
|
||||
|
@ -205,6 +210,13 @@ class ContactForm(forms.ModelForm):
|
|||
"required": "Enter your email address in the required format, like name@example.com."
|
||||
}
|
||||
self.fields["phone"].error_messages["required"] = "Enter your phone number."
|
||||
self.domainInfo = None
|
||||
|
||||
def set_domain_info(self, domainInfo):
|
||||
"""Set the domain information for the form.
|
||||
The form instance is associated with the contact itself. In order to access the associated
|
||||
domain information object, this needs to be set in the form by the view."""
|
||||
self.domainInfo = domainInfo
|
||||
|
||||
|
||||
class AuthorizingOfficialContactForm(ContactForm):
|
||||
|
@ -212,7 +224,7 @@ class AuthorizingOfficialContactForm(ContactForm):
|
|||
|
||||
JOIN = "authorizing_official"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
def __init__(self, disable_fields=False, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Overriding bc phone not required in this form
|
||||
|
@ -232,20 +244,36 @@ class AuthorizingOfficialContactForm(ContactForm):
|
|||
self.fields["email"].error_messages = {
|
||||
"required": "Enter an email address in the required format, like name@example.com."
|
||||
}
|
||||
self.domainInfo = None
|
||||
|
||||
def set_domain_info(self, domainInfo):
|
||||
"""Set the domain information for the form.
|
||||
The form instance is associated with the contact itself. In order to access the associated
|
||||
domain information object, this needs to be set in the form by the view."""
|
||||
self.domainInfo = domainInfo
|
||||
# All fields should be disabled if the domain is federal or tribal
|
||||
if disable_fields:
|
||||
DomainHelper.mass_disable_fields(fields=self.fields, disable_required=True, disable_maxlength=True)
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Override the save() method of the BaseModelForm."""
|
||||
"""
|
||||
Override the save() method of the BaseModelForm.
|
||||
Used to perform checks on the underlying domain_information object.
|
||||
If this doesn't exist, we just save as normal.
|
||||
"""
|
||||
|
||||
# If the underlying Domain doesn't have a domainInfo object,
|
||||
# just let the default super handle it.
|
||||
if not self.domainInfo:
|
||||
return super().save()
|
||||
|
||||
# Determine if the domain is federal or tribal
|
||||
is_federal = self.domainInfo.organization_type == DomainRequest.OrganizationChoices.FEDERAL
|
||||
is_tribal = self.domainInfo.organization_type == DomainRequest.OrganizationChoices.TRIBAL
|
||||
|
||||
# Get the Contact object from the db for the Authorizing Official
|
||||
db_ao = Contact.objects.get(id=self.instance.id)
|
||||
if self.domainInfo and db_ao.has_more_than_one_join("information_authorizing_official"):
|
||||
|
||||
if (is_federal or is_tribal) and self.has_changed():
|
||||
# This action should be blocked by the UI, as the text fields are readonly.
|
||||
# If they get past this point, we forbid it this way.
|
||||
# This could be malicious, so lets reserve information for the backend only.
|
||||
raise ValueError("Authorizing Official cannot be modified for federal or tribal domains.")
|
||||
elif db_ao.has_more_than_one_join("information_authorizing_official"):
|
||||
# Handle the case where the domain information object is available and the AO Contact
|
||||
# has more than one joined object.
|
||||
# In this case, create a new Contact, and update the new Contact with form data.
|
||||
|
@ -254,6 +282,7 @@ class AuthorizingOfficialContactForm(ContactForm):
|
|||
self.domainInfo.authorizing_official = Contact.objects.create(**data)
|
||||
self.domainInfo.save()
|
||||
else:
|
||||
# If all checks pass, just save normally
|
||||
super().save()
|
||||
|
||||
|
||||
|
@ -304,11 +333,11 @@ class DomainOrgNameAddressForm(forms.ModelForm):
|
|||
},
|
||||
}
|
||||
widgets = {
|
||||
# We need to set the required attributed for federal_agency and
|
||||
# state/territory because for these fields we are creating an individual
|
||||
# We need to set the required attributed for State/territory
|
||||
# because for this fields we are creating an individual
|
||||
# instance of the Select. For the other fields we use the for loop to set
|
||||
# the class's required attribute to true.
|
||||
"federal_agency": forms.Select(attrs={"required": True}, choices=DomainInformation.AGENCY_CHOICES),
|
||||
"federal_agency": forms.TextInput,
|
||||
"organization_name": forms.TextInput,
|
||||
"address_line1": forms.TextInput,
|
||||
"address_line2": forms.TextInput,
|
||||
|
@ -334,6 +363,46 @@ class DomainOrgNameAddressForm(forms.ModelForm):
|
|||
self.fields["state_territory"].widget.attrs.pop("maxlength", None)
|
||||
self.fields["zipcode"].widget.attrs.pop("maxlength", None)
|
||||
|
||||
self.is_federal = self.instance.organization_type == DomainRequest.OrganizationChoices.FEDERAL
|
||||
self.is_tribal = self.instance.organization_type == DomainRequest.OrganizationChoices.TRIBAL
|
||||
|
||||
field_to_disable = None
|
||||
if self.is_federal:
|
||||
field_to_disable = "federal_agency"
|
||||
elif self.is_tribal:
|
||||
field_to_disable = "organization_name"
|
||||
|
||||
# Disable any field that should be disabled, if applicable
|
||||
if field_to_disable is not None:
|
||||
DomainHelper.disable_field(self.fields[field_to_disable], disable_required=True)
|
||||
|
||||
def save(self, commit=True):
|
||||
"""Override the save() method of the BaseModelForm."""
|
||||
if self.has_changed():
|
||||
|
||||
# This action should be blocked by the UI, as the text fields are readonly.
|
||||
# If they get past this point, we forbid it this way.
|
||||
# This could be malicious, so lets reserve information for the backend only.
|
||||
if self.is_federal and not self._field_unchanged("federal_agency"):
|
||||
raise ValueError("federal_agency cannot be modified when the organization_type is federal")
|
||||
elif self.is_tribal and not self._field_unchanged("organization_name"):
|
||||
raise ValueError("organization_name cannot be modified when the organization_type is tribal")
|
||||
|
||||
else:
|
||||
super().save()
|
||||
|
||||
def _field_unchanged(self, field_name) -> bool:
|
||||
"""
|
||||
Checks if a specified field has not changed between the old value
|
||||
and the new value.
|
||||
|
||||
The old value is grabbed from self.initial.
|
||||
The new value is grabbed from self.cleaned_data.
|
||||
"""
|
||||
old_value = self.initial.get(field_name, None)
|
||||
new_value = self.cleaned_data.get(field_name, None)
|
||||
return old_value == new_value
|
||||
|
||||
|
||||
class DomainDnssecForm(forms.Form):
|
||||
"""Form for enabling and disabling dnssec"""
|
||||
|
|
|
@ -198,6 +198,7 @@ class Domain(TimeStampedModel, DomainHelper):
|
|||
is called in the validate function on the request/domain page
|
||||
|
||||
throws- RegistryError or InvalidDomainError"""
|
||||
|
||||
if not cls.string_could_be_domain(domain):
|
||||
logger.warning("Not a valid domain: %s" % str(domain))
|
||||
# throw invalid domain error so that it can be caught in
|
||||
|
|
|
@ -188,3 +188,33 @@ class DomainHelper:
|
|||
common_fields = model_1_fields & model_2_fields
|
||||
|
||||
return common_fields
|
||||
|
||||
@staticmethod
|
||||
def mass_disable_fields(fields, disable_required=False, disable_maxlength=False):
|
||||
"""
|
||||
Given some fields, invoke .disabled = True on them.
|
||||
disable_required: bool -> invokes .required = False on each field.
|
||||
disable_maxlength: bool -> pops "maxlength" from each field.
|
||||
"""
|
||||
for field in fields.values():
|
||||
field = DomainHelper.disable_field(field, disable_required, disable_maxlength)
|
||||
return fields
|
||||
|
||||
@staticmethod
|
||||
def disable_field(field, disable_required=False, disable_maxlength=False):
|
||||
"""
|
||||
Given a fields, invoke .disabled = True on it.
|
||||
disable_required: bool -> invokes .required = False for the field.
|
||||
disable_maxlength: bool -> pops "maxlength" for the field.
|
||||
"""
|
||||
field.disabled = True
|
||||
|
||||
if disable_required:
|
||||
# if a field is disabled, it can't be required
|
||||
field.required = False
|
||||
|
||||
if disable_maxlength:
|
||||
# Remove the maxlength dialog
|
||||
if "maxlength" in field.widget.attrs:
|
||||
field.widget.attrs.pop("maxlength", None)
|
||||
return field
|
||||
|
|
|
@ -11,12 +11,28 @@
|
|||
|
||||
<p>Your authorizing official is a person within your organization who can
|
||||
authorize domain requests. This person must be in a role of significant, executive responsibility within the organization. Read more about <a class="usa-link" rel="noopener noreferrer" target="_blank" href="{% public_site_url 'domains/eligibility/#you-must-have-approval-from-an-authorizing-official-within-your-organization' %}">who can serve as an authorizing official</a>.</p>
|
||||
|
||||
|
||||
{% if organization_type == "federal" or organization_type == "tribal" %}
|
||||
<p>
|
||||
The authorizing official for your organization can’t be updated here.
|
||||
To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||
</p>
|
||||
{% else %}
|
||||
{% include "includes/required_fields.html" %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
<form class="usa-form usa-form--large" method="post" novalidate id="form-container">
|
||||
{% csrf_token %}
|
||||
|
||||
{% if organization_type == "federal" or organization_type == "tribal" %}
|
||||
{# If all fields are disabled, add SR content #}
|
||||
<div class="usa-sr-only" aria-labelledby="id_first_name" id="sr-ao-first-name">{{ form.first_name.value }}</div>
|
||||
<div class="usa-sr-only" aria-labelledby="id_last_name" id="sr-ao-last-name">{{ form.last_name.value }}</div>
|
||||
<div class="usa-sr-only" aria-labelledby="id_title" id="sr-ao-title">{{ form.title.value }}</div>
|
||||
<div class="usa-sr-only" aria-labelledby="id_email" id="sr-ao-email">{{ form.email.value }}</div>
|
||||
{% endif %}
|
||||
|
||||
{% input_with_errors form.first_name %}
|
||||
|
||||
{% input_with_errors form.last_name %}
|
||||
|
@ -24,11 +40,9 @@
|
|||
{% input_with_errors form.title %}
|
||||
|
||||
{% input_with_errors form.email %}
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="usa-button"
|
||||
>Save</button>
|
||||
</form>
|
||||
|
||||
|
||||
{% if organization_type != "federal" and organization_type != "tribal" %}
|
||||
<button type="submit" class="usa-button">Save</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endblock %} {# domain_content #}
|
||||
|
|
|
@ -11,6 +11,18 @@
|
|||
|
||||
<p>The name of your organization will be publicly listed as the domain registrant.</p>
|
||||
|
||||
{% if domain.domain_info.organization_type == "federal" %}
|
||||
<p>
|
||||
The federal agency for your organization can’t be updated here.
|
||||
To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||
</p>
|
||||
{% elif domain.domain_info.organization_type == "tribal" %}
|
||||
<p>
|
||||
Your organization name can’t be updated here.
|
||||
To suggest an update, email <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% include "includes/required_fields.html" %}
|
||||
|
||||
<form class="usa-form usa-form--large" method="post" novalidate id="form-container">
|
||||
|
|
|
@ -1021,6 +1021,144 @@ class TestDomainAuthorizingOfficial(TestDomainOverview):
|
|||
self.assertEqual("Testy2", self.domain_information.authorizing_official.first_name)
|
||||
self.assertEqual(ao_pk, self.domain_information.authorizing_official.id)
|
||||
|
||||
def assert_all_form_fields_have_expected_values(self, form, test_cases, test_for_disabled=False):
|
||||
"""
|
||||
Asserts that each specified form field has the expected value and, optionally, checks if the field is disabled.
|
||||
|
||||
This method iterates over a list of tuples, where each
|
||||
tuple contains a field name and the expected value for that field.
|
||||
It uses subtests to isolate each assertion, allowing multiple field
|
||||
checks within a single test method without stopping at the first failure.
|
||||
|
||||
Example usage:
|
||||
test_cases = [
|
||||
("first_name", "John"),
|
||||
("last_name", "Doe"),
|
||||
("email", "john.doe@example.com"),
|
||||
]
|
||||
self.assert_all_form_fields_have_expected_values(my_form, test_cases, test_for_disabled=True)
|
||||
"""
|
||||
for field_name, expected_value in test_cases:
|
||||
with self.subTest(field_name=field_name, expected_value=expected_value):
|
||||
# Test that each field has the value we expect
|
||||
self.assertEqual(expected_value, form[field_name].value)
|
||||
|
||||
if test_for_disabled:
|
||||
# Test for disabled on each field
|
||||
self.assertTrue("disabled" in form[field_name].attrs)
|
||||
|
||||
def test_domain_edit_authorizing_official_federal(self):
|
||||
"""Tests that no edit can occur when the underlying domain is federal"""
|
||||
|
||||
# Set the org type to federal
|
||||
self.domain_information.organization_type = DomainInformation.OrganizationChoices.FEDERAL
|
||||
self.domain_information.save()
|
||||
|
||||
# Add an AO. We can do this at the model level, just not the form level.
|
||||
self.domain_information.authorizing_official = Contact(
|
||||
first_name="Apple", last_name="Tester", title="CIO", email="nobody@igorville.gov"
|
||||
)
|
||||
self.domain_information.authorizing_official.save()
|
||||
self.domain_information.save()
|
||||
|
||||
ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
|
||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
|
||||
# Test if the form is populating data correctly
|
||||
ao_form = ao_page.forms[0]
|
||||
|
||||
test_cases = [
|
||||
("first_name", "Apple"),
|
||||
("last_name", "Tester"),
|
||||
("title", "CIO"),
|
||||
("email", "nobody@igorville.gov"),
|
||||
]
|
||||
self.assert_all_form_fields_have_expected_values(ao_form, test_cases, test_for_disabled=True)
|
||||
|
||||
# Attempt to change data on each field. Because this domain is federal,
|
||||
# this should not succeed.
|
||||
ao_form["first_name"] = "Orange"
|
||||
ao_form["last_name"] = "Smoothie"
|
||||
ao_form["title"] = "Cat"
|
||||
ao_form["email"] = "somebody@igorville.gov"
|
||||
|
||||
submission = ao_form.submit()
|
||||
|
||||
# A 302 indicates this page underwent a redirect.
|
||||
self.assertEqual(submission.status_code, 302)
|
||||
|
||||
followed_submission = submission.follow()
|
||||
|
||||
# Test the returned form for data accuracy. These values should be unchanged.
|
||||
new_form = followed_submission.forms[0]
|
||||
self.assert_all_form_fields_have_expected_values(new_form, test_cases, test_for_disabled=True)
|
||||
|
||||
# refresh domain information. Test these values in the DB.
|
||||
self.domain_information.refresh_from_db()
|
||||
|
||||
# All values should be unchanged. These are defined manually for code clarity.
|
||||
self.assertEqual("Apple", self.domain_information.authorizing_official.first_name)
|
||||
self.assertEqual("Tester", self.domain_information.authorizing_official.last_name)
|
||||
self.assertEqual("CIO", self.domain_information.authorizing_official.title)
|
||||
self.assertEqual("nobody@igorville.gov", self.domain_information.authorizing_official.email)
|
||||
|
||||
def test_domain_edit_authorizing_official_tribal(self):
|
||||
"""Tests that no edit can occur when the underlying domain is tribal"""
|
||||
|
||||
# Set the org type to federal
|
||||
self.domain_information.organization_type = DomainInformation.OrganizationChoices.TRIBAL
|
||||
self.domain_information.save()
|
||||
|
||||
# Add an AO. We can do this at the model level, just not the form level.
|
||||
self.domain_information.authorizing_official = Contact(
|
||||
first_name="Apple", last_name="Tester", title="CIO", email="nobody@igorville.gov"
|
||||
)
|
||||
self.domain_information.authorizing_official.save()
|
||||
self.domain_information.save()
|
||||
|
||||
ao_page = self.app.get(reverse("domain-authorizing-official", kwargs={"pk": self.domain.id}))
|
||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
|
||||
# Test if the form is populating data correctly
|
||||
ao_form = ao_page.forms[0]
|
||||
|
||||
test_cases = [
|
||||
("first_name", "Apple"),
|
||||
("last_name", "Tester"),
|
||||
("title", "CIO"),
|
||||
("email", "nobody@igorville.gov"),
|
||||
]
|
||||
self.assert_all_form_fields_have_expected_values(ao_form, test_cases, test_for_disabled=True)
|
||||
|
||||
# Attempt to change data on each field. Because this domain is federal,
|
||||
# this should not succeed.
|
||||
ao_form["first_name"] = "Orange"
|
||||
ao_form["last_name"] = "Smoothie"
|
||||
ao_form["title"] = "Cat"
|
||||
ao_form["email"] = "somebody@igorville.gov"
|
||||
|
||||
submission = ao_form.submit()
|
||||
|
||||
# A 302 indicates this page underwent a redirect.
|
||||
self.assertEqual(submission.status_code, 302)
|
||||
|
||||
followed_submission = submission.follow()
|
||||
|
||||
# Test the returned form for data accuracy. These values should be unchanged.
|
||||
new_form = followed_submission.forms[0]
|
||||
self.assert_all_form_fields_have_expected_values(new_form, test_cases, test_for_disabled=True)
|
||||
|
||||
# refresh domain information. Test these values in the DB.
|
||||
self.domain_information.refresh_from_db()
|
||||
|
||||
# All values should be unchanged. These are defined manually for code clarity.
|
||||
self.assertEqual("Apple", self.domain_information.authorizing_official.first_name)
|
||||
self.assertEqual("Tester", self.domain_information.authorizing_official.last_name)
|
||||
self.assertEqual("CIO", self.domain_information.authorizing_official.title)
|
||||
self.assertEqual("nobody@igorville.gov", self.domain_information.authorizing_official.email)
|
||||
|
||||
def test_domain_edit_authorizing_official_creates_new(self):
|
||||
"""When editing an authorizing official for domain information and AO IS
|
||||
joined to another object"""
|
||||
|
@ -1088,6 +1226,149 @@ class TestDomainOrganization(TestDomainOverview):
|
|||
self.assertContains(success_result_page, "Not igorville")
|
||||
self.assertContains(success_result_page, "Faketown")
|
||||
|
||||
def test_domain_org_name_address_form_tribal(self):
|
||||
"""
|
||||
Submitting a change to organization_name is blocked for tribal domains
|
||||
"""
|
||||
# Set the current domain to a tribal organization with a preset value.
|
||||
# Save first, so we can test if saving is unaffected (it should be).
|
||||
tribal_org_type = DomainInformation.OrganizationChoices.TRIBAL
|
||||
self.domain_information.organization_type = tribal_org_type
|
||||
self.domain_information.save()
|
||||
try:
|
||||
# Add an org name
|
||||
self.domain_information.organization_name = "Town of Igorville"
|
||||
self.domain_information.save()
|
||||
except ValueError as err:
|
||||
self.fail(f"A ValueError was caught during the test: {err}")
|
||||
|
||||
self.assertEqual(self.domain_information.organization_type, tribal_org_type)
|
||||
|
||||
org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
|
||||
|
||||
form = org_name_page.forms[0]
|
||||
# Check the value of the input field
|
||||
organization_name_input = form.fields["organization_name"][0]
|
||||
self.assertEqual(organization_name_input.value, "Town of Igorville")
|
||||
|
||||
# Check if the input field is disabled
|
||||
self.assertTrue("disabled" in organization_name_input.attrs)
|
||||
self.assertEqual(organization_name_input.attrs.get("disabled"), "")
|
||||
|
||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||
|
||||
org_name_page.form["organization_name"] = "Not igorville"
|
||||
org_name_page.form["city"] = "Faketown"
|
||||
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
|
||||
# Make the change. The org name should be unchanged, but city should be modifiable.
|
||||
success_result_page = org_name_page.form.submit()
|
||||
self.assertEqual(success_result_page.status_code, 200)
|
||||
|
||||
# Check for the old and new value
|
||||
self.assertContains(success_result_page, "Town of Igorville")
|
||||
self.assertNotContains(success_result_page, "Not igorville")
|
||||
|
||||
# Do another check on the form itself
|
||||
form = success_result_page.forms[0]
|
||||
# Check the value of the input field
|
||||
organization_name_input = form.fields["organization_name"][0]
|
||||
self.assertEqual(organization_name_input.value, "Town of Igorville")
|
||||
|
||||
# Check if the input field is disabled
|
||||
self.assertTrue("disabled" in organization_name_input.attrs)
|
||||
self.assertEqual(organization_name_input.attrs.get("disabled"), "")
|
||||
|
||||
# Check for the value we want to update
|
||||
self.assertContains(success_result_page, "Faketown")
|
||||
|
||||
def test_domain_org_name_address_form_federal(self):
|
||||
"""
|
||||
Submitting a change to federal_agency is blocked for federal domains
|
||||
"""
|
||||
# Set the current domain to a tribal organization with a preset value.
|
||||
# Save first, so we can test if saving is unaffected (it should be).
|
||||
fed_org_type = DomainInformation.OrganizationChoices.FEDERAL
|
||||
self.domain_information.organization_type = fed_org_type
|
||||
self.domain_information.save()
|
||||
try:
|
||||
self.domain_information.federal_agency = "AMTRAK"
|
||||
self.domain_information.save()
|
||||
except ValueError as err:
|
||||
self.fail(f"A ValueError was caught during the test: {err}")
|
||||
|
||||
self.assertEqual(self.domain_information.organization_type, fed_org_type)
|
||||
|
||||
org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
|
||||
|
||||
form = org_name_page.forms[0]
|
||||
# Check the value of the input field
|
||||
agency_input = form.fields["federal_agency"][0]
|
||||
self.assertEqual(agency_input.value, "AMTRAK")
|
||||
|
||||
# Check if the input field is disabled
|
||||
self.assertTrue("disabled" in agency_input.attrs)
|
||||
self.assertEqual(agency_input.attrs.get("disabled"), "")
|
||||
|
||||
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
|
||||
|
||||
org_name_page.form["federal_agency"] = "Department of State"
|
||||
org_name_page.form["city"] = "Faketown"
|
||||
|
||||
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
|
||||
|
||||
# Make the change. The agency should be unchanged, but city should be modifiable.
|
||||
success_result_page = org_name_page.form.submit()
|
||||
self.assertEqual(success_result_page.status_code, 200)
|
||||
|
||||
# Check for the old and new value
|
||||
self.assertContains(success_result_page, "AMTRAK")
|
||||
self.assertNotContains(success_result_page, "Department of State")
|
||||
|
||||
# Do another check on the form itself
|
||||
form = success_result_page.forms[0]
|
||||
# Check the value of the input field
|
||||
organization_name_input = form.fields["federal_agency"][0]
|
||||
self.assertEqual(organization_name_input.value, "AMTRAK")
|
||||
|
||||
# Check if the input field is disabled
|
||||
self.assertTrue("disabled" in organization_name_input.attrs)
|
||||
self.assertEqual(organization_name_input.attrs.get("disabled"), "")
|
||||
|
||||
# Check for the value we want to update
|
||||
self.assertContains(success_result_page, "Faketown")
|
||||
|
||||
def test_federal_agency_submit_blocked(self):
|
||||
"""
|
||||
Submitting a change to federal_agency is blocked for federal domains
|
||||
"""
|
||||
# Set the current domain to a tribal organization with a preset value.
|
||||
# Save first, so we can test if saving is unaffected (it should be).
|
||||
federal_org_type = DomainInformation.OrganizationChoices.FEDERAL
|
||||
self.domain_information.organization_type = federal_org_type
|
||||
self.domain_information.save()
|
||||
|
||||
old_federal_agency_value = ("AMTRAK", "AMTRAK")
|
||||
try:
|
||||
# Add a federal agency. Defined as a tuple since this list may change order.
|
||||
self.domain_information.federal_agency = old_federal_agency_value
|
||||
self.domain_information.save()
|
||||
except ValueError as err:
|
||||
self.fail(f"A ValueError was caught during the test: {err}")
|
||||
|
||||
self.assertEqual(self.domain_information.organization_type, federal_org_type)
|
||||
|
||||
new_value = ("Department of State", "Department of State")
|
||||
self.client.post(
|
||||
reverse("domain-org-name-address", kwargs={"pk": self.domain.id}),
|
||||
{
|
||||
"federal_agency": new_value,
|
||||
},
|
||||
)
|
||||
self.assertEqual(self.domain_information.federal_agency, old_federal_agency_value)
|
||||
self.assertNotEqual(self.domain_information.federal_agency, new_value)
|
||||
|
||||
|
||||
class TestDomainContactInformation(TestDomainOverview):
|
||||
def test_domain_your_contact_information(self):
|
||||
|
|
|
@ -18,6 +18,8 @@ from django.conf import settings
|
|||
|
||||
from registrar.models import (
|
||||
Domain,
|
||||
DomainRequest,
|
||||
DomainInformation,
|
||||
DomainInvitation,
|
||||
User,
|
||||
UserDomainRole,
|
||||
|
@ -134,6 +136,20 @@ class DomainFormBaseView(DomainBaseView, FormMixin):
|
|||
# superclass has the redirect
|
||||
return super().form_invalid(form)
|
||||
|
||||
def get_domain_info_from_domain(self) -> DomainInformation | None:
|
||||
"""
|
||||
Grabs the underlying domain_info object based off of self.object.name.
|
||||
Returns None if nothing is found.
|
||||
"""
|
||||
_domain_info = DomainInformation.objects.filter(domain__name=self.object.name)
|
||||
current_domain_info = None
|
||||
if _domain_info.exists() and _domain_info.count() == 1:
|
||||
current_domain_info = _domain_info.get()
|
||||
else:
|
||||
logger.error("Could get domain_info. No domain info exists, or duplicates exist.")
|
||||
|
||||
return current_domain_info
|
||||
|
||||
|
||||
class DomainView(DomainBaseView):
|
||||
"""Domain detail overview page."""
|
||||
|
@ -217,16 +233,29 @@ class DomainAuthorizingOfficialView(DomainFormBaseView):
|
|||
"""Add domain_info.authorizing_official instance to make a bound form."""
|
||||
form_kwargs = super().get_form_kwargs(*args, **kwargs)
|
||||
form_kwargs["instance"] = self.object.domain_info.authorizing_official
|
||||
|
||||
domain_info = self.get_domain_info_from_domain()
|
||||
invalid_fields = [DomainRequest.OrganizationChoices.FEDERAL, DomainRequest.OrganizationChoices.TRIBAL]
|
||||
is_federal_or_tribal = domain_info and (domain_info.organization_type in invalid_fields)
|
||||
|
||||
form_kwargs["disable_fields"] = is_federal_or_tribal
|
||||
return form_kwargs
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Adds custom context."""
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["organization_type"] = self.object.domain_info.organization_type
|
||||
return context
|
||||
|
||||
def get_success_url(self):
|
||||
"""Redirect to the overview page for the domain."""
|
||||
return reverse("domain-authorizing-official", kwargs={"pk": self.object.pk})
|
||||
|
||||
def form_valid(self, form):
|
||||
"""The form is valid, save the authorizing official."""
|
||||
|
||||
# Set the domain information in the form so that it can be accessible
|
||||
# to associate a new Contact as authorizing official, if new Contact is needed
|
||||
# to associate a new Contact, if a new Contact is needed
|
||||
# in the save() method
|
||||
form.set_domain_info(self.object.domain_info)
|
||||
form.save()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue