all tests passing

This commit is contained in:
matthewswspence 2024-09-25 15:24:21 -05:00
parent 9de6831591
commit ab4024bab5
No known key found for this signature in database
GPG key ID: FB458202A7852BA4
4 changed files with 237 additions and 20 deletions

View file

@ -8,8 +8,7 @@
<p>
Domain managers can update all information related to a domain within the
.gov registrar, including contact details, senior official, security
email, and DNS name servers.
.gov registrar, including, security email and DNS name servers.
</p>
<ul class="usa-list">
@ -17,7 +16,8 @@
<li>After adding a domain manager, an email invitation will be sent to that user with
instructions on how to set up an account.</li>
<li>All domain managers must keep their contact information updated and be responsive if contacted by the .gov team.</li>
<li>Domains must have at least one domain manager. You cant remove yourself as a domain manager if youre the only one assigned to this domain. Add another domain manager before you remove yourself from this domain.</li>
<li>All domain managers will be notified when updates are made to this domain.</li>
<li>Domains must have at least one domain manager. You cant remove yourself as a domain manager if youre the only one assigned to this domain.</li>
</ul>
{% if domain.permissions %}

View file

@ -71,7 +71,7 @@ class TestEmails(TestCase):
"doesnotexist@igorville.com",
context={"domain_request": self},
bcc_address=None,
cc=["test_email1@example.com", "test_email2@example.com"]
cc_addresses=["test_email1@example.com", "test_email2@example.com"]
)
# check that an email was sent

View file

@ -8,6 +8,7 @@ from django.contrib.auth import get_user_model
from waffle.testutils import override_flag
from api.tests.common import less_console_noise_decorator
from registrar.models.utility.portfolio_helper import UserPortfolioRoleChoices
from registrar.utility.email import send_templated_email
from .common import MockEppLib, MockSESClient, create_user # type: ignore
from django_webtest import WebTest # type: ignore
import boto3_mocking # type: ignore
@ -67,6 +68,10 @@ class TestWithDomainPermissions(TestWithUser):
datetime.combine(date.today() + timedelta(days=1), datetime.min.time())
),
)
self.domain_dns_needed, _ = Domain.objects.get_or_create(
name="dns-needed.gov",
state=Domain.State.DNS_NEEDED,
)
self.domain_deleted, _ = Domain.objects.get_or_create(
name="deleted.gov",
state=Domain.State.DELETED,
@ -85,6 +90,12 @@ class TestWithDomainPermissions(TestWithUser):
self.domain_information, _ = DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain)
self.security_contact, _ = PublicContact.objects.get_or_create(
domain=self.domain,
contact_type=PublicContact.ContactTypeChoices.SECURITY,
email="security@igorville.gov",
)
DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dsdata)
DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_multdsdata)
DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dnssec_none)
@ -93,6 +104,8 @@ class TestWithDomainPermissions(TestWithUser):
DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_just_nameserver)
DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_on_hold)
DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_deleted)
DomainInformation.objects.get_or_create(creator=self.user, domain=self.domain_dns_needed)
self.role, _ = UserDomainRole.objects.get_or_create(
user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER
@ -101,6 +114,9 @@ class TestWithDomainPermissions(TestWithUser):
UserDomainRole.objects.get_or_create(
user=self.user, domain=self.domain_dsdata, role=UserDomainRole.Roles.MANAGER
)
UserDomainRole.objects.get_or_create(
user=self.user, domain=self.domain_dns_needed, role=UserDomainRole.Roles.MANAGER
)
UserDomainRole.objects.get_or_create(
user=self.user,
domain=self.domain_multdsdata,
@ -1976,6 +1992,7 @@ class TestDomainChangeNotifications(TestDomainOverview):
super().setUpClass()
allowed_emails = [
AllowedEmail(email="info@example.com"),
AllowedEmail(email="doesnotexist@igorville.com"),
]
AllowedEmail.objects.bulk_create(allowed_emails)
@ -1990,10 +2007,15 @@ class TestDomainChangeNotifications(TestDomainOverview):
AllowedEmail.objects.all().delete()
@boto3_mocking.patching
def test_notification_email_sent_on_org_name_change(self):
@less_console_noise_decorator
def test_notification_on_org_name_change(self):
"""Test that an email is sent when the organization name is changed."""
self.domain_information.organization_name = "Town of Igorville"
self.domain_information.address_line1 = "123 Main St"
self.domain_information.city = "Igorville"
self.domain_information.state_territory = "IL"
self.domain_information.zipcode = "62052"
self.domain_information.save()
org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
@ -2003,22 +2025,215 @@ class TestDomainChangeNotifications(TestDomainOverview):
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
success_result_page = org_name_page.form.submit()
# Check that the page loads successfully
self.assertEqual(success_result_page.status_code, 200)
self.assertContains(success_result_page, "Not igorville")
org_name_page.form.submit()
# Check that an email was sent
self.assertTrue(self.mock_client.send_email.called)
# Check email content
# check the call sequence for the email
args, kwargs = self.mock_client.send_email.call_args
_, kwargs = self.mock_client.send_email.call_args
self.assertIn("Content", kwargs)
self.assertIn("Simple", kwargs["Content"])
self.assertIn("Subject", kwargs["Content"]["Simple"])
self.assertIn("Body", kwargs["Content"]["Simple"])
# check for things in the email content (not an exhaustive list)
body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
self.assertIn("DOMAIN:", body)
self.assertIn("DOMAIN: igorville.gov", body)
self.assertIn("UPDATED BY: First Last info@example.com", body)
self.assertIn("INFORMATION UPDATED: Org Name/Address", body)
@boto3_mocking.patching
@less_console_noise_decorator
def test_no_notification_on_org_name_change_with_portfolio(self):
"""Test that an email is not sent on org name change when the domain is in a portfolio"""
portfolio, _ = Portfolio.objects.get_or_create(organization_name="Test org", creator=self.user)
self.domain_information.organization_name = "Town of Igorville"
self.domain_information.address_line1 = "123 Main St"
self.domain_information.city = "Igorville"
self.domain_information.state_territory = "IL"
self.domain_information.zipcode = "62052"
self.domain_information.portfolio = portfolio
self.domain_information.save()
org_name_page = self.app.get(reverse("domain-org-name-address", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
org_name_page.form["organization_name"] = "Not igorville"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
org_name_page.form.submit()
# Check that an email was not sent
self.assertFalse(self.mock_client.send_email.called)
@boto3_mocking.patching
@less_console_noise_decorator
def test_notification_on_security_email_change(self):
"""Test that an email is sent when the security email is changed."""
security_email_page = self.app.get(reverse("domain-security-email", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
security_email_page.form["security_email"] = "new_security@example.com"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
security_email_page.form.submit()
self.assertTrue(self.mock_client.send_email.called)
_, kwargs = self.mock_client.send_email.call_args
body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
self.assertIn("DOMAIN: igorville.gov", body)
self.assertIn("UPDATED BY: First Last info@example.com", body)
self.assertIn("INFORMATION UPDATED: Security Email", body)
@boto3_mocking.patching
@less_console_noise_decorator
def test_notification_on_dnssec_enable(self):
"""Test that an email is sent when DNSSEC is enabled."""
page = self.client.get(reverse("domain-dns-dnssec", kwargs={"pk": self.domain_multdsdata.id}))
self.assertContains(page, "Disable DNSSEC")
# Prepare the data for the POST request
post_data = {
"disable_dnssec": "Disable DNSSEC",
}
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
updated_page = self.client.post(
reverse("domain-dns-dnssec", kwargs={"pk": self.domain.id}),
post_data,
follow=True,
)
self.assertEqual(updated_page.status_code, 200)
self.assertContains(updated_page, "Enable DNSSEC")
self.assertTrue(self.mock_client.send_email.called)
_, kwargs = self.mock_client.send_email.call_args
body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
self.assertIn("DOMAIN: igorville.gov", body)
self.assertIn("UPDATED BY: First Last info@example.com", body)
self.assertIn("INFORMATION UPDATED: DNSSec", body)
@boto3_mocking.patching
@less_console_noise_decorator
def test_notification_on_ds_data_change(self):
"""Test that an email is sent when DS data is changed."""
ds_data_page = self.app.get(reverse("domain-dns-dnssec-dsdata", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
# Add DS data
ds_data_page.forms[0]["form-0-key_tag"] = "12345"
ds_data_page.forms[0]["form-0-algorithm"] = "13"
ds_data_page.forms[0]["form-0-digest_type"] = "2"
ds_data_page.forms[0]["form-0-digest"] = "1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
ds_data_page.forms[0].submit()
# check that the email was sent
self.assertTrue(self.mock_client.send_email.called)
# check some stuff about the email
_, kwargs = self.mock_client.send_email.call_args
body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
self.assertIn("DOMAIN: igorville.gov", body)
self.assertIn("UPDATED BY: First Last info@example.com", body)
self.assertIn("INFORMATION UPDATED: DS Data", body)
@boto3_mocking.patching
@less_console_noise_decorator
def test_notification_on_senior_official_change(self):
"""Test that an email is sent when the senior official information is changed."""
self.domain_information.senior_official = Contact.objects.create(
first_name="Old", last_name="Official", title="Manager", email="old_official@example.com"
)
self.domain_information.save()
senior_official_page = self.app.get(reverse("domain-senior-official", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
senior_official_page.form["first_name"] = "New"
senior_official_page.form["last_name"] = "Official"
senior_official_page.form["title"] = "Director"
senior_official_page.form["email"] = "new_official@example.com"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
senior_official_page.form.submit()
self.assertTrue(self.mock_client.send_email.called)
_, kwargs = self.mock_client.send_email.call_args
body = kwargs["Content"]["Simple"]["Body"]["Text"]["Data"]
self.assertIn("DOMAIN: igorville.gov", body)
self.assertIn("UPDATED BY: First Last info@example.com", body)
self.assertIn("INFORMATION UPDATED: Senior Official", body)
@boto3_mocking.patching
@less_console_noise_decorator
def test_no_notification_on_senior_official_when_portfolio(self):
"""Test that an email is not sent when the senior official information is changed
and the domain is in a portfolio."""
self.domain_information.senior_official = Contact.objects.create(
first_name="Old", last_name="Official", title="Manager", email="old_official@example.com"
)
portfolio, _ =Portfolio.objects.get_or_create(
organization_name="portfolio",
creator=self.user,
)
self.domain_information.portfolio = portfolio
self.domain_information.save()
senior_official_page = self.app.get(reverse("domain-senior-official", kwargs={"pk": self.domain.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
senior_official_page.form["first_name"] = "New"
senior_official_page.form["last_name"] = "Official"
senior_official_page.form["title"] = "Director"
senior_official_page.form["email"] = "new_official@example.com"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
senior_official_page.form.submit()
self.assertFalse(self.mock_client.send_email.called)
@boto3_mocking.patching
@less_console_noise_decorator
def test_no_notification_when_dns_needed(self):
"""Test that an email is not sent when nameservers are changed while the state is DNS_NEEDED."""
nameservers_page = self.app.get(reverse("domain-dns-nameservers", kwargs={"pk": self.domain_dns_needed.id}))
session_id = self.app.cookies[settings.SESSION_COOKIE_NAME]
# add nameservers
nameservers_page.form["form-0-server"] = "ns1-new.igorville.gov"
nameservers_page.form["form-0-ip"] = "192.168.1.1"
nameservers_page.form["form-1-server"] = "ns2-new.igorville.gov"
nameservers_page.form["form-1-ip"] = "192.168.1.2"
self.app.set_cookie(settings.SESSION_COOKIE_NAME, session_id)
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
nameservers_page.form.submit()
# Check that an email was not sent
self.assertFalse(self.mock_client.send_email.called)

View file

@ -119,6 +119,7 @@ class DomainFormBaseView(DomainBaseView, FormMixin):
if form.is_valid():
return self.form_valid(form)
else:
logger.debug(f"Form errors: {form.errors}")
return self.form_invalid(form)
def form_valid(self, form):
@ -164,6 +165,7 @@ class DomainFormBaseView(DomainBaseView, FormMixin):
DomainDsdataFormset: "DS Data",
DomainOrgNameAddressForm: "Org Name/Address",
SeniorOfficialContactForm: "Senior Official",
NameserverFormset: "Nameservers",
}
# forms of these types should not send notifications if they're part of a portfolio/Organization
@ -179,14 +181,13 @@ class DomainFormBaseView(DomainBaseView, FormMixin):
# some forms shouldn't cause notifications if they are in a portfolio
info = self.get_domain_info_from_domain()
if not info or info.portfolio:
logger.info(f"Not notifying because of portfolio")
should_notify = False
else:
# don't notify for any other types of forms
should_notify=False
logger.info(f"Not notifying for {form.__class__}")
if (should_notify and form.has_changed()) or force_send:
logger.info("Sending email to domain managers")
context={
"domain": self.object.name,
"user": self.request.user,
@ -194,6 +195,8 @@ class DomainFormBaseView(DomainBaseView, FormMixin):
"changes": form_label_dict[form.__class__]
}
self.email_domain_managers(self.object, "emails/update_to_approved_domain.txt", "emails/update_to_approved_domain_subject.txt", context)
else:
logger.info(f"Not notifying for {form.__class__}, form changes: {form.has_changed()}, force_send: {force_send}")
def email_domain_managers(self, domain_name, template: str, subject_template: str, context: any = {}):
"""Send a single email built from a template to all managers for a given domain.
@ -489,8 +492,7 @@ class DomainNameserversView(DomainFormBaseView):
This post method harmonizes using DomainBaseView and FormMixin
"""
logger.info("Posted to Namservers View")
logger.info(f"POST request to DomainNameserversView")
self._get_domain(request)
formset = self.get_form()
@ -500,6 +502,7 @@ class DomainNameserversView(DomainFormBaseView):
return HttpResponseRedirect(url)
if formset.is_valid():
logger.info(f"Formset is valid")
return self.form_valid(formset)
else:
return self.form_invalid(formset)
@ -507,8 +510,6 @@ class DomainNameserversView(DomainFormBaseView):
def form_valid(self, formset):
"""The formset is valid, perform something with it."""
logger.info("------ Nameserver Form is valid -------")
self.request.session["nameservers_form_domain"] = self.object
# Set the nameservers from the formset
@ -550,7 +551,8 @@ class DomainNameserversView(DomainFormBaseView):
messages.error(self.request, NameserverError(code=nsErrorCodes.BAD_DATA))
logger.error(f"Registry error: {Err}")
else:
self.send_update_notification(formset)
if self.object.state == Domain.State.READY:
self.send_update_notification(formset)
messages.success(
self.request,
"The name servers for this domain have been updated. "