mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-20 03:19:24 +02:00
Implement 'investigating' email templates and tigger email send on admin domain application save, status change to investidated.
This commit is contained in:
parent
d4162c5d9c
commit
31295053f9
4 changed files with 245 additions and 2 deletions
|
@ -1,11 +1,14 @@
|
||||||
|
import logging
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.http.response import HttpResponseRedirect
|
from django.http.response import HttpResponseRedirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from .utility.email import send_templated_email, EmailSendingError
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class AuditedAdmin(admin.ModelAdmin):
|
class AuditedAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
|
@ -50,13 +53,51 @@ class MyHostAdmin(AuditedAdmin):
|
||||||
inlines = [HostIPInline]
|
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 == "investigating":
|
||||||
|
if (
|
||||||
|
original_obj.submitter is None
|
||||||
|
or original_obj.submitter.email is None
|
||||||
|
):
|
||||||
|
logger.warning(
|
||||||
|
"Cannot send status change (in review) email,"
|
||||||
|
"no submitter email address."
|
||||||
|
)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
print(
|
||||||
|
f"original_obj.submitter.email {original_obj.submitter.email}"
|
||||||
|
)
|
||||||
|
send_templated_email(
|
||||||
|
"emails/status_change_in_review.txt",
|
||||||
|
"emails/status_change_in_review_subject.txt",
|
||||||
|
original_obj.submitter.email,
|
||||||
|
context={"application": obj},
|
||||||
|
)
|
||||||
|
except EmailSendingError:
|
||||||
|
logger.warning(
|
||||||
|
"Failed to send status change (in review) email", exc_info=True
|
||||||
|
)
|
||||||
|
|
||||||
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(models.User, MyUserAdmin)
|
admin.site.register(models.User, MyUserAdmin)
|
||||||
admin.site.register(models.UserDomainRole, AuditedAdmin)
|
admin.site.register(models.UserDomainRole, AuditedAdmin)
|
||||||
admin.site.register(models.Contact, AuditedAdmin)
|
admin.site.register(models.Contact, AuditedAdmin)
|
||||||
admin.site.register(models.DomainInvitation, AuditedAdmin)
|
admin.site.register(models.DomainInvitation, AuditedAdmin)
|
||||||
admin.site.register(models.DomainApplication, AuditedAdmin)
|
|
||||||
admin.site.register(models.DomainInformation, AuditedAdmin)
|
admin.site.register(models.DomainInformation, AuditedAdmin)
|
||||||
admin.site.register(models.Domain, AuditedAdmin)
|
admin.site.register(models.Domain, AuditedAdmin)
|
||||||
admin.site.register(models.Host, MyHostAdmin)
|
admin.site.register(models.Host, MyHostAdmin)
|
||||||
admin.site.register(models.Nameserver, MyHostAdmin)
|
admin.site.register(models.Nameserver, MyHostAdmin)
|
||||||
admin.site.register(models.Website, AuditedAdmin)
|
admin.site.register(models.Website, AuditedAdmin)
|
||||||
|
admin.site.register(models.DomainApplication, DomainApplicationAdmin)
|
||||||
|
|
81
src/registrar/templates/emails/status_change_in_review.txt
Normal file
81
src/registrar/templates/emails/status_change_in_review.txt
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
{% 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.
|
||||||
|
<https://get.gov/help/domain-requests/#withdraw-your-domain-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.
|
||||||
|
<https://registrar.get.gov/application/{{ application.id }}>
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
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 %}
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
The .gov team
|
||||||
|
Contact us: <https://get.gov/contact/>
|
||||||
|
Visit <https://get.gov>
|
||||||
|
{% endautoescape %}
|
|
@ -0,0 +1 @@
|
||||||
|
Your .gov domain request is being reviewed
|
120
src/registrar/tests/test_admin.py
Normal file
120
src/registrar/tests/test_admin.py
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
from django.test import TestCase, RequestFactory
|
||||||
|
from django.contrib.admin.sites import AdminSite
|
||||||
|
from registrar.admin import DomainApplicationAdmin
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from registrar.models import Contact, DraftDomain, Website, DomainApplication, User
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from unittest.mock import MagicMock, ANY
|
||||||
|
import boto3_mocking # type: ignore
|
||||||
|
|
||||||
|
|
||||||
|
class TestDomainApplicationAdmin(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.site = AdminSite()
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
|
||||||
|
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="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,
|
||||||
|
)
|
||||||
|
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
|
||||||
|
|
||||||
|
@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 = self._completed_application()
|
||||||
|
|
||||||
|
# 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 = "investigating"
|
||||||
|
|
||||||
|
# Use the model admin's save_model method
|
||||||
|
model_admin.save_model(request, application, form=None, change=True)
|
||||||
|
|
||||||
|
# Assert that the email was sent
|
||||||
|
|
||||||
|
mock_client_instance.send_email.assert_called_once_with(
|
||||||
|
FromEmailAddress=settings.DEFAULT_FROM_EMAIL,
|
||||||
|
Destination={"ToAddresses": [EMAIL]},
|
||||||
|
Content=ANY,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
application.delete()
|
Loading…
Add table
Add a link
Reference in a new issue