Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2307: send notification emails on changes to domain - [MS] #2827

Open
wants to merge 35 commits into
base: main
Choose a base branch
from

Conversation

Matt-Spence
Copy link
Contributor

@Matt-Spence Matt-Spence commented Sep 19, 2024

Ticket

Resolves #2307

Changes

  • Notifications are sent to all domain managers when the following are changed on a domain:
    • Nameservers
    • DNSSec
    • Senior Official
    • Org name/Address
    • Security Email
  • New additions to email utility to enable CC'ed addresses
  • New email and subject template reflecting content from here
  • Content changes to domain managers page as outlined here
  • Tests
  • Edits to some old tests that broke because of the new email sending logic (nothing major)

Context for reviewers

Setup

Code Review Verification Steps

Go to getgov-ms and add yourself as a domain manager to any domain. Make sure your email is in the whitelist, then go to that domain and make changes. Observe whether emails are sent, and their content.

Repeat for various permutations (multiple domain managers, some managers in/out of whitelist, domains in/out of portfolios, etc).

As the original developer, I have

Satisfied acceptance criteria and met development standards

  • Met the acceptance criteria, or will meet them in a subsequent PR
  • Created/modified automated tests
  • Added at least 2 developers as PR reviewers (only 1 will need to approve)
  • Messaged on Slack or in standup to notify the team that a PR is ready for review
  • Changes to “how we do things” are documented in READMEs and or onboarding guide
  • If any model was updated to modify/add/delete columns, makemigrations was ran and the associated migrations file has been commited.

Ensured code standards are met (Original Developer)

  • All new functions and methods are commented using plain language
  • Did dependency updates in Pipfile also get changed in requirements.txt?
  • Interactions with external systems are wrapped in try/except
  • Error handling exists for unusual or missing values

Validated user-facing changes (if applicable)

  • New pages have been added to .pa11yci file so that they will be tested with our automated accessibility testing
  • Checked keyboard navigability
  • Tested general usability, landmarks, page header structure, and links with a screen reader (such as Voiceover or ANDI)
  • Add at least 1 designer as PR reviewer

As a code reviewer, I have

Reviewed, tested, and left feedback about the changes

  • Pulled this branch locally and tested it
  • Reviewed this code and left comments
  • Checked that all code is adequately covered by tests
  • Made it clear which comments need to be addressed before this work is merged
  • If any model was updated to modify/add/delete columns, makemigrations was ran and the associated migrations file has been commited.

Ensured code standards are met (Code reviewer)

  • All new functions and methods are commented using plain language
  • Interactions with external systems are wrapped in try/except
  • Error handling exists for unusual or missing values
  • (Rarely needed) Did dependency updates in Pipfile also get changed in requirements.txt?

Validated user-facing changes as a developer

  • New pages have been added to .pa11yci file so that they will be tested with our automated accessibility testing

  • Checked keyboard navigability

  • Meets all designs and user flows provided by design/product

  • Tested general usability, landmarks, page header structure, and links with a screen reader (such as Voiceover or ANDI)

  • Tested with multiple browsers, the suggestion is to use ones that the developer didn't (check off which ones were used)

    • Chrome
    • Microsoft Edge
    • FireFox
    • Safari
  • (Rarely needed) Tested as both an analyst and applicant user

Note: Multiple code reviewers can share the checklists above, a second reviewers should not make a duplicate checklist

As a designer reviewer, I have

Verified that the changes match the design intention

  • Checked that the design translated visually
  • Checked behavior
  • Checked different states (empty, one, some, error)
  • Checked for landmarks, page heading structure, and links
  • Tried to break the intended flow

Validated user-facing changes as a designer

  • Checked keyboard navigability

  • Tested general usability, landmarks, page header structure, and links with a screen reader (such as Voiceover or ANDI)

  • Tested with multiple browsers (check off which ones were used)

    • Chrome
    • Microsoft Edge
    • FireFox
    • Safari
  • (Rarely needed) Tested as both an analyst and applicant user

Screenshots

Copy link

🥳 Successfully deployed to developer sandbox ms.

2 similar comments
Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Comment on lines +479 to +480
if not hasattr(record, "server_time"):
record.server_time = self.formatTime(record, self.datefmt)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a minor fix to an edge case where this attribute doesn't exist, causing log formatting to revert back to its old "one log per \n" behavior. I can include it as a separate PR if we want, but thought it was small enough to sneak in.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

@@ -118,6 +119,7 @@ def post(self, request, *args, **kwargs):
if form.is_valid():
return self.form_valid(form)
else:
logger.debug(f"Form errors: {form.errors}")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not strictly necessary, but I found this super useful while debugging this PR so thought I might leave it in.

@abroddrick abroddrick added the carryover Carryover from a previous sprint label Sep 26, 2024
Copy link

🥳 Successfully deployed to developer sandbox ms.

@Matt-Spence Matt-Spence changed the title (draft) #2307: send notification emails on changes to domain - [MS] #2307: send notification emails on changes to domain - [MS] Sep 26, 2024
Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link

🥳 Successfully deployed to developer sandbox ms.

Copy link
Contributor

@zandercymatics zandercymatics left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, I've noted a few changes that should be made though

@@ -61,11 +61,27 @@ def test_disable_email_flag(self):
# Assert that an email wasn't sent
self.assertFalse(self.mock_client.send_email.called)

@boto3_mocking.patching
def test_email_with_cc(self):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(optional) Just in case, I'd also recommend test with the decorator @override_settings(IS_PRODUCTION=True) and check the bcc_address as well as the cc_address The behaviour of that function changes when in production so it would catch any edge cases related to that

Comment on lines +67 to +78
with boto3_mocking.clients.handler_for("sesv2", self.mock_client_class):
send_templated_email(
"emails/update_to_approved_domain.txt",
"emails/update_to_approved_domain_subject.txt",
"doesnotexist@igorville.com",
context={"domain": "test", "user": "test", "date": 1, "changes": "test"},
bcc_address=None,
cc_addresses=["testy2@town.com", "mayor@igorville.gov"],
)

# check that an email was sent
self.assertTrue(self.mock_client.send_email.called)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should also include a test here that checks on the content of cc_addresses.
We have a few tests that test on the bcc_addresses - should be mostly the same logic for it

@boto3_mocking.patching
@less_console_noise_decorator
def test_submission_confirmation(self):
"""Submission confirmation email works."""
domain_request = completed_domain_request()
domain_request = completed_domain_request(user=User.objects.create(username="test", email="testy@town.com"))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Q) Why was this changed? Its not a bad thing though, just curious

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default the completed_domain_request function creates a user with no email. Technically what was happening previously was that emails were being "sent" (the send_email function was being called) but without any to_address because when the domain request was submitted, it would grab an empty string from the user's email. That was a valid case previously (not sure if that was intentional) but now I added a check to make sure that there is some email address in to, bcc, or cc. As a result, these tests broke and to fix it I had to add a user object with an email.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely a bug! Good catch

Comment on lines 90 to 94
self.security_contact, _ = PublicContact.objects.get_or_create(
domain=self.domain,
contact_type=PublicContact.ContactTypeChoices.SECURITY,
email="security@igorville.gov",
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you using this anywhere? If not can you delete it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, that was left over from a previous iteration of one of the tests! Good catch.

AllowedEmail(email="info@example.com"),
AllowedEmail(email="doesnotexist@igorville.com"),
]
AllowedEmail.objects.bulk_create(allowed_emails)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice use of bulk_create

Comment on lines +171 to +176
# forms of these types should not send notifications if they're part of a portfolio/Organization
check_for_portfolio = {
DomainOrgNameAddressForm,
SeniorOfficialContactForm,
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Q) Why?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(A) Because it was in the AC's :). Actually though, I think these cases will be handled separately in the org model work.

# 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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(nitpick/optional) Personally, I think the should_notify variable in this context is moreso better described as can_notify rather than should_notify

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually disagree, we technically can notify on changes with portfolios (as in, there's no technical barrier) but we have made a decision that we shouldn't. I like the attention to naming though! Good naming is important for whatever unfortunate soul has to maintain this code later on!

"changes": form_label_dict[form.__class__],
}
self.email_domain_managers(
self.object,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self.object is typically the model itself.
Later on its being used as domain_name. Is self.object a string in this context?

Will log a warning if the email fails to send for any reason, but will not raise an error.
"""
try:
domain = Domain.objects.get(name=domain_name)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per above, I think self.object should already be the object assuming its not just a string.
I'd suggest grabbing that directly rather than a filter. If that returns none then you can log as normal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree. This works technically because (I think) when you treat a domain model as a string it uses the name, but it's clunky at best.

src/registrar/views/domain.py Outdated Show resolved Hide resolved
@zandercymatics zandercymatics self-assigned this Oct 1, 2024
Co-authored-by: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Copy link

github-actions bot commented Oct 2, 2024

🥳 Successfully deployed to developer sandbox ms.

Copy link

github-actions bot commented Oct 2, 2024

🥳 Successfully deployed to developer sandbox ms.

Copy link
Contributor

@zandercymatics zandercymatics left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It works! One thing I noticed though is that I am receiving the email by being directly CC'd rather than it just being to my address, I assume that is not intentional?

Not blocking the review on it, but just be sure to resolve it given that design is in agreement (since they'll need to review this anyhow)
image

Co-authored-by: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
@Matt-Spence
Copy link
Contributor Author

It works! One thing I noticed though is that I am receiving the email by being directly CC'd rather than it just being to my address, I assume that is not intentional?

Not blocking the review on it, but just be sure to resolve it given that design is in agreement (since they'll need to review this anyhow) image

Actually it is intentional, as the AC's specifically asked for domain managers to be CC'ed on the same email. It is a little awkward for cases where there's only one domain manager, but I'm not sure it matters much either way. I'll defer to design.

@Matt-Spence Matt-Spence requested a review from a team October 2, 2024 20:23
@zandercymatics
Copy link
Contributor

@Matt-Spence Fair enough

Copy link

github-actions bot commented Oct 2, 2024

🥳 Successfully deployed to developer sandbox ms.

@Katherine-Osos Katherine-Osos requested review from Katherine-Osos and removed request for a team October 3, 2024 18:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
carryover Carryover from a previous sprint
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dev: Send email that announces when domain information has changed
3 participants