diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 439dfd9f9..c8d48024b 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -1,11 +1,13 @@ +import logging from django.contrib import admin from django.contrib.auth.admin import UserAdmin from django.contrib.contenttypes.models import ContentType from django.http.response import HttpResponseRedirect from django.urls import reverse - from . import models +logger = logging.getLogger(__name__) + class AuditedAdmin(admin.ModelAdmin): @@ -50,13 +52,37 @@ class MyHostAdmin(AuditedAdmin): inlines = [HostIPInline] +class DomainApplicationAdmin(AuditedAdmin): + + """Customize the applications listing view.""" + + # Trigger action when a fieldset is changed + def save_model(self, request, obj, form, change): + if change: # Check if the application is being edited + # Get the original application from the database + original_obj = models.DomainApplication.objects.get(pk=obj.pk) + + if ( + obj.status != original_obj.status + and obj.status == models.DomainApplication.INVESTIGATING + ): + # This is a transition annotated method in model which will throw an + # error if the condition is violated. To make this work, we need to + # call it on the original object which has the right status value, + # but pass the current object which contains the up-to-date data + # for the email. + original_obj.in_review(obj) + + super().save_model(request, obj, form, change) + + admin.site.register(models.User, MyUserAdmin) admin.site.register(models.UserDomainRole, AuditedAdmin) admin.site.register(models.Contact, AuditedAdmin) admin.site.register(models.DomainInvitation, AuditedAdmin) -admin.site.register(models.DomainApplication, AuditedAdmin) admin.site.register(models.DomainInformation, AuditedAdmin) admin.site.register(models.Domain, AuditedAdmin) admin.site.register(models.Host, MyHostAdmin) admin.site.register(models.Nameserver, MyHostAdmin) admin.site.register(models.Website, AuditedAdmin) +admin.site.register(models.DomainApplication, DomainApplicationAdmin) diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 4caf26924..57be80b36 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -490,9 +490,38 @@ class DomainApplication(TimeStampedModel): self.submitter.email, context={"application": self}, ) + logger.info( + f"Submission confirmation email sent to: {self.submitter.email}" + ) except EmailSendingError: logger.warning("Failed to send confirmation email", exc_info=True) + def _send_in_review_email(self): + """Send an email that this application is now in review. + + The email goes to the email address that the submitter gave as their + contact information. If there is not submitter information, then do + nothing. + """ + if self.submitter is None or self.submitter.email is None: + logger.warning( + "Cannot send status change (in review) email," + "no submitter email address." + ) + return + try: + send_templated_email( + "emails/status_change_in_review.txt", + "emails/status_change_in_review_subject.txt", + self.submitter.email, + context={"application": self}, + ) + logging.info(f"In review email sent to: {self.submitter.email}") + except EmailSendingError: + logger.warning( + "Failed to send status change (in review) email", exc_info=True + ) + @transition(field="status", source=[STARTED, WITHDRAWN], target=SUBMITTED) def submit(self): """Submit an application that is started.""" @@ -541,6 +570,19 @@ class DomainApplication(TimeStampedModel): user=self.creator, domain=created_domain, role=UserDomainRole.Roles.ADMIN ) + @transition(field="status", source=SUBMITTED, target=INVESTIGATING) + def in_review(self, updated_domain_application): + """Investigate an application that has been submitted. + + This method is called in admin.py on the original application + which has the correct status value, but is passed the changed + application which has the up-to-date data that we'll use + in the email.""" + + # When an application is moved to in review, we need to send a + # confirmation email. This is a side-effect of the state transition + updated_domain_application._send_in_review_email() + @transition(field="status", source=[SUBMITTED, INVESTIGATING], target=WITHDRAWN) def withdraw(self): """Withdraw an application that has been submitted.""" diff --git a/src/registrar/templates/emails/includes/application_summary.txt b/src/registrar/templates/emails/includes/application_summary.txt new file mode 100644 index 000000000..07519a8f0 --- /dev/null +++ b/src/registrar/templates/emails/includes/application_summary.txt @@ -0,0 +1,39 @@ +SUMMARY OF YOUR DOMAIN REQUEST + +Type of organization: +{{ application.get_organization_type_display }} + +Organization name and mailing address: +{% spaceless %}{{ application.organization_name }} +{{ application.address_line1 }}{% if application.address_line2 %} +{{ application.address_line2 }}{% endif %} +{{ application.city }}, {{ application.state_territory }} +{{ application.zipcode }}{% if application.urbanization %} +{{ application.urbanization }}{% endif %}{% endspaceless %} +{% if application.type_of_work %}{# if block makes one newline if it's false #} +Type of work: +{% spaceless %}{{ application.type_of_work }}{% endspaceless %} +{% endif %} +Authorizing official: +{% spaceless %}{% include "emails/includes/contact.txt" with contact=application.authorizing_official %}{% endspaceless %} +{% if application.current_websites.exists %}{# if block makes a newline #} +Current website for your organization: {% for site in application.current_websites.all %} +{% spaceless %}{{ site.website }}{% endspaceless %} +{% endfor %}{% endif %} +.gov domain: +{{ application.requested_domain.name }} +{% for site in application.alternative_domains.all %}{% spaceless %}{{ site.website }}{% endspaceless %} +{% endfor %} +Purpose of your domain: +{{ application.purpose }} + +Your contact information: +{% spaceless %}{% include "emails/includes/contact.txt" with contact=application.submitter %}{% endspaceless %} +{% if application.other_contacts.all %} +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? +{{ application.anything_else }} +{% endif %} \ No newline at end of file diff --git a/src/registrar/templates/emails/status_change_in_review.txt b/src/registrar/templates/emails/status_change_in_review.txt new file mode 100644 index 000000000..63df669eb --- /dev/null +++ b/src/registrar/templates/emails/status_change_in_review.txt @@ -0,0 +1,43 @@ +{% autoescape off %}{# In a text file, we don't want to have HTML entities escaped #} +Hi {{ application.submitter.first_name }}. + +Your .gov domain request is being reviewed. + +DOMAIN REQUESTED: {{ application.requested_domain.name }} +REQUEST RECEIVED ON: {{ application.updated_at|date }} +REQUEST #: {{ application.id }} +STATUS: In review + + +NEED TO MAKE CHANGES? + +If you need to change your request you have to first withdraw it. Once you +withdraw the request you can edit it and submit it again. Changing your request +might add to the wait time. Learn more about withdrawing your request. +. + + +NEXT STEPS + +- We’re reviewing your request. This usually takes 20 business days. + +- You can check the status of your request at any time. + + +- We’ll email you with questions or when we complete our review. + + +THANK YOU + +.Gov helps the public identify official, trusted information. Thank you for +requesting a .gov domain. + +---------------------------------------------------------------- + +{% include 'emails/includes/application_summary.txt' %} +---------------------------------------------------------------- + +The .gov team +Contact us: +Visit +{% endautoescape %} diff --git a/src/registrar/templates/emails/status_change_in_review_subject.txt b/src/registrar/templates/emails/status_change_in_review_subject.txt new file mode 100644 index 000000000..e4e43138b --- /dev/null +++ b/src/registrar/templates/emails/status_change_in_review_subject.txt @@ -0,0 +1 @@ +Your .gov domain request is being reviewed \ No newline at end of file diff --git a/src/registrar/templates/emails/submission_confirmation.txt b/src/registrar/templates/emails/submission_confirmation.txt index 6da239065..41fab8005 100644 --- a/src/registrar/templates/emails/submission_confirmation.txt +++ b/src/registrar/templates/emails/submission_confirmation.txt @@ -33,45 +33,7 @@ requesting a .gov domain. ---------------------------------------------------------------- -SUMMARY OF YOUR DOMAIN REQUEST - -Type of organization: -{{ application.get_organization_type_display }} - -Organization name and mailing address: -{% spaceless %}{{ application.organization_name }} -{{ application.address_line1 }}{% if application.address_line2 %} -{{ application.address_line2 }}{% endif %} -{{ application.city }}, {{ application.state_territory }} -{{ application.zipcode }}{% if application.urbanization %} -{{ application.urbanization }}{% endif %}{% endspaceless %} -{% if application.type_of_work %}{# if block makes one newline if it's false #} -Type of work: -{% spaceless %}{{ application.type_of_work }}{% endspaceless %} -{% endif %} -Authorizing official: -{% spaceless %}{% include "emails/includes/contact.txt" with contact=application.authorizing_official %}{% endspaceless %} -{% if application.current_websites.exists %}{# if block makes a newline #} -Current website for your organization: {% for site in application.current_websites.all %} -{% spaceless %}{{ site.website }}{% endspaceless %} -{% endfor %}{% endif %} -.gov domain: -{{ application.requested_domain.name }} -{% for site in application.alternative_domains.all %}{% spaceless %}{{ site.website }}{% endspaceless %} -{% endfor %} -Purpose of your domain: -{{ application.purpose }} - -Your contact information: -{% spaceless %}{% include "emails/includes/contact.txt" with contact=application.submitter %}{% endspaceless %} -{% if application.other_contacts.all %} -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? -{{ application.anything_else }} -{% endif %} +{% include 'emails/includes/application_summary.txt' %} ---------------------------------------------------------------- The .gov team diff --git a/src/registrar/tests/common.py b/src/registrar/tests/common.py index 332b04c0e..dfc0787af 100644 --- a/src/registrar/tests/common.py +++ b/src/registrar/tests/common.py @@ -8,6 +8,8 @@ from typing import List, Dict from django.conf import settings from django.contrib.auth import get_user_model, login +from registrar.models import Contact, DraftDomain, Website, DomainApplication + def get_handlers(): """Obtain pointers to all StreamHandlers.""" @@ -84,3 +86,74 @@ class MockSESClient(Mock): def send_email(self, *args, **kwargs): self.EMAILS_SENT.append({"args": args, "kwargs": kwargs}) + + +def completed_application( + has_other_contacts=True, + has_current_website=True, + has_alternative_gov_domain=True, + has_type_of_work=True, + has_anything_else=True, + status=DomainApplication.STARTED, + user=False, +): + """A completed domain application.""" + if not user: + user = get_user_model().objects.create(username="username") + ao, _ = Contact.objects.get_or_create( + first_name="Testy", + last_name="Tester", + title="Chief Tester", + email="testy@town.com", + phone="(555) 555 5555", + ) + domain, _ = DraftDomain.objects.get_or_create(name="city.gov") + alt, _ = Website.objects.get_or_create(website="city1.gov") + current, _ = Website.objects.get_or_create(website="city.com") + you, _ = Contact.objects.get_or_create( + first_name="Testy you", + last_name="Tester you", + title="Admin Tester", + email="mayor@igorville.gov", + phone="(555) 555 5556", + ) + other, _ = Contact.objects.get_or_create( + first_name="Testy2", + last_name="Tester2", + title="Another Tester", + email="testy2@town.com", + phone="(555) 555 5557", + ) + domain_application_kwargs = dict( + organization_type="federal", + federal_type="executive", + purpose="Purpose of the site", + is_policy_acknowledged=True, + organization_name="Testorg", + address_line1="address 1", + address_line2="address 2", + state_territory="NY", + zipcode="10002", + authorizing_official=ao, + requested_domain=domain, + submitter=you, + creator=user, + status=status, + ) + if has_type_of_work: + domain_application_kwargs["type_of_work"] = "e-Government" + if has_anything_else: + domain_application_kwargs["anything_else"] = "There is more" + + application, _ = DomainApplication.objects.get_or_create( + **domain_application_kwargs + ) + + if has_other_contacts: + application.other_contacts.add(other) + if has_current_website: + application.current_websites.add(current) + if has_alternative_gov_domain: + application.alternative_domains.add(alt) + + return application diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py new file mode 100644 index 000000000..2f2e1190b --- /dev/null +++ b/src/registrar/tests/test_admin.py @@ -0,0 +1,64 @@ +from django.test import TestCase, RequestFactory +from django.contrib.admin.sites import AdminSite +from registrar.admin import DomainApplicationAdmin +from registrar.models import DomainApplication, User +from .common import completed_application + +from django.conf import settings +from unittest.mock import MagicMock +import boto3_mocking # type: ignore + + +class TestDomainApplicationAdmin(TestCase): + def setUp(self): + self.site = AdminSite() + self.factory = RequestFactory() + + @boto3_mocking.patching + def test_save_model_sends_email_on_property_change(self): + # make sure there is no user with this email + EMAIL = "mayor@igorville.gov" + User.objects.filter(email=EMAIL).delete() + + mock_client = MagicMock() + mock_client_instance = mock_client.return_value + + with boto3_mocking.clients.handler_for("sesv2", mock_client): + # Create a sample application + application = completed_application(status=DomainApplication.SUBMITTED) + + # Create a mock request + request = self.factory.post( + "/admin/registrar/domainapplication/{}/change/".format(application.pk) + ) + + # Create an instance of the model admin + model_admin = DomainApplicationAdmin(DomainApplication, self.site) + + # Modify the application's property + application.status = DomainApplication.INVESTIGATING + + # Use the model admin's save_model method + model_admin.save_model(request, application, form=None, change=True) + + # Access the arguments passed to send_email + call_args = mock_client_instance.send_email.call_args + args, kwargs = call_args + + # Retrieve the email details from the arguments + from_email = kwargs.get("FromEmailAddress") + to_email = kwargs["Destination"]["ToAddresses"][0] + email_content = kwargs["Content"] + email_body = email_content["Simple"]["Body"]["Text"]["Data"] + + # Assert or perform other checks on the email details + expected_string = "Your .gov domain request is being reviewed" + self.assertEqual(from_email, settings.DEFAULT_FROM_EMAIL) + self.assertEqual(to_email, EMAIL) + self.assertIn(expected_string, email_body) + + # Perform assertions on the mock call itself + mock_client_instance.send_email.assert_called_once() + + # Cleanup + application.delete() diff --git a/src/registrar/tests/test_emails.py b/src/registrar/tests/test_emails.py index 4d7b22d01..b5c6cd428 100644 --- a/src/registrar/tests/test_emails.py +++ b/src/registrar/tests/test_emails.py @@ -2,82 +2,14 @@ from unittest.mock import MagicMock -from django.contrib.auth import get_user_model from django.test import TestCase +from .common import completed_application -from registrar.models import Contact, DraftDomain, Website, DomainApplication import boto3_mocking # type: ignore class TestEmails(TestCase): - def _completed_application( - self, - has_other_contacts=True, - has_current_website=True, - has_alternative_gov_domain=True, - has_type_of_work=True, - has_anything_else=True, - ): - """A completed domain application.""" - user = get_user_model().objects.create(username="username") - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(555) 555 5555", - ) - domain, _ = DraftDomain.objects.get_or_create(name="city.gov") - alt, _ = Website.objects.get_or_create(website="city1.gov") - current, _ = Website.objects.get_or_create(website="city.com") - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(555) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(555) 555 5557", - ) - domain_application_kwargs = dict( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - address_line2="address 2", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - requested_domain=domain, - submitter=you, - creator=user, - ) - if has_type_of_work: - domain_application_kwargs["type_of_work"] = "e-Government" - if has_anything_else: - domain_application_kwargs["anything_else"] = "There is more" - - application, _ = DomainApplication.objects.get_or_create( - **domain_application_kwargs - ) - - if has_other_contacts: - application.other_contacts.add(other) - if has_current_website: - application.current_websites.add(current) - if has_alternative_gov_domain: - application.alternative_domains.add(alt) - - return application - def setUp(self): self.mock_client_class = MagicMock() self.mock_client = self.mock_client_class.return_value @@ -85,7 +17,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation(self): """Submission confirmation email works.""" - application = self._completed_application() + application = completed_application() with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() @@ -122,7 +54,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_current_website_spacing(self): """Test line spacing without current_website.""" - application = self._completed_application(has_current_website=False) + application = completed_application(has_current_website=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -134,7 +66,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_current_website_spacing(self): """Test line spacing with current_website.""" - application = self._completed_application(has_current_website=True) + application = completed_application(has_current_website=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -147,7 +79,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_other_contacts_spacing(self): """Test line spacing with other contacts.""" - application = self._completed_application(has_other_contacts=True) + application = completed_application(has_other_contacts=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -160,7 +92,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_other_contacts_spacing(self): """Test line spacing without other contacts.""" - application = self._completed_application(has_other_contacts=False) + application = completed_application(has_other_contacts=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -172,7 +104,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_alternative_govdomain_spacing(self): """Test line spacing with alternative .gov domain.""" - application = self._completed_application(has_alternative_gov_domain=True) + application = completed_application(has_alternative_gov_domain=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -184,7 +116,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_alternative_govdomain_spacing(self): """Test line spacing without alternative .gov domain.""" - application = self._completed_application(has_alternative_gov_domain=False) + application = completed_application(has_alternative_gov_domain=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -196,7 +128,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_type_of_work_spacing(self): """Test line spacing with type of work.""" - application = self._completed_application(has_type_of_work=True) + application = completed_application(has_type_of_work=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -208,7 +140,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_type_of_work_spacing(self): """Test line spacing without type of work.""" - application = self._completed_application(has_type_of_work=False) + application = completed_application(has_type_of_work=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -220,7 +152,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_anything_else_spacing(self): """Test line spacing with anything else.""" - application = self._completed_application(has_anything_else=True) + application = completed_application(has_anything_else=True) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args @@ -231,7 +163,7 @@ class TestEmails(TestCase): @boto3_mocking.patching def test_submission_confirmation_no_anything_else_spacing(self): """Test line spacing without anything else.""" - application = self._completed_application(has_anything_else=False) + application = completed_application(has_anything_else=False) with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class): application.submit() _, kwargs = self.mock_client.send_email.call_args diff --git a/src/registrar/tests/test_views.py b/src/registrar/tests/test_views.py index ffe4cb671..ee3d7d946 100644 --- a/src/registrar/tests/test_views.py +++ b/src/registrar/tests/test_views.py @@ -5,6 +5,7 @@ from django.conf import settings from django.test import Client, TestCase from django.urls import reverse from django.contrib.auth import get_user_model +from .common import completed_application from django_webtest import WebTest # type: ignore import boto3_mocking # type: ignore @@ -1407,85 +1408,18 @@ class TestApplicationStatus(TestWithUser, WebTest): self.app.set_user(self.user.username) self.client.force_login(self.user) - def _completed_application( - self, - has_other_contacts=True, - has_current_website=True, - has_alternative_gov_domain=True, - has_type_of_work=True, - has_anything_else=True, - ): - """A completed domain application.""" - ao, _ = Contact.objects.get_or_create( - first_name="Testy", - last_name="Tester", - title="Chief Tester", - email="testy@town.com", - phone="(555) 555 5555", - ) - domain, _ = DraftDomain.objects.get_or_create(name="citystatus.gov") - alt, _ = Website.objects.get_or_create(website="city1.gov") - current, _ = Website.objects.get_or_create(website="city.com") - you, _ = Contact.objects.get_or_create( - first_name="Testy you", - last_name="Tester you", - title="Admin Tester", - email="testy-admin@town.com", - phone="(555) 555 5556", - ) - other, _ = Contact.objects.get_or_create( - first_name="Testy2", - last_name="Tester2", - title="Another Tester", - email="testy2@town.com", - phone="(555) 555 5557", - ) - domain_application_kwargs = dict( - organization_type="federal", - federal_type="executive", - purpose="Purpose of the site", - is_policy_acknowledged=True, - organization_name="Testorg", - address_line1="address 1", - address_line2="address 2", - state_territory="NY", - zipcode="10002", - authorizing_official=ao, - requested_domain=domain, - submitter=you, - creator=self.user, - ) - if has_type_of_work: - domain_application_kwargs["type_of_work"] = "e-Government" - if has_anything_else: - domain_application_kwargs["anything_else"] = "There is more" - - application, _ = DomainApplication.objects.get_or_create( - **domain_application_kwargs - ) - - application.status = DomainApplication.SUBMITTED - application.save() - - if has_other_contacts: - application.other_contacts.add(other) - if has_current_website: - application.current_websites.add(current) - if has_alternative_gov_domain: - application.alternative_domains.add(alt) - - return application - def test_application_status(self): """Checking application status page""" - application = self._completed_application() + application = completed_application( + status=DomainApplication.SUBMITTED, user=self.user + ) application.save() home_page = self.app.get("/") - self.assertContains(home_page, "citystatus.gov") + self.assertContains(home_page, "city.gov") # click the "Manage" link detail_page = home_page.click("Manage") - self.assertContains(detail_page, "citystatus.gov") + self.assertContains(detail_page, "city.gov") self.assertContains(detail_page, "Chief Tester") self.assertContains(detail_page, "testy@town.com") self.assertContains(detail_page, "Admin Tester") @@ -1493,14 +1427,16 @@ class TestApplicationStatus(TestWithUser, WebTest): def test_application_withdraw(self): """Checking application status page""" - application = self._completed_application() + application = completed_application( + status=DomainApplication.SUBMITTED, user=self.user + ) application.save() home_page = self.app.get("/") - self.assertContains(home_page, "citystatus.gov") + self.assertContains(home_page, "city.gov") # click the "Manage" link detail_page = home_page.click("Manage") - self.assertContains(detail_page, "citystatus.gov") + self.assertContains(detail_page, "city.gov") self.assertContains(detail_page, "Chief Tester") self.assertContains(detail_page, "testy@town.com") self.assertContains(detail_page, "Admin Tester") @@ -1522,7 +1458,9 @@ class TestApplicationStatus(TestWithUser, WebTest): def test_application_status_no_permissions(self): """Can't access applications without being the creator.""" - application = self._completed_application() + application = completed_application( + status=DomainApplication.SUBMITTED, user=self.user + ) other_user = User() other_user.save() application.creator = other_user