mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-06-30 08:13:27 +02:00
add scripts, templates and settings for sending one-time domain invitations during data migration
This commit is contained in:
parent
4daec217d7
commit
82b097d2f6
5 changed files with 223 additions and 0 deletions
|
@ -523,6 +523,9 @@ STATIC_URL = "public/"
|
|||
# {% public_site_url subdir/path %} template tag
|
||||
GETGOV_PUBLIC_SITE_URL = env_getgov_public_site_url
|
||||
|
||||
# Base URL of application
|
||||
BASE_URL = env_base_url
|
||||
|
||||
# endregion
|
||||
# region: Registry----------------------------------------------------------###
|
||||
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
"""Data migration: Generate fake transition domains, replacing existing ones."""
|
||||
|
||||
import logging
|
||||
|
||||
from django.core.management import BaseCommand
|
||||
from registrar.models import TransitionDomain, Domain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Generate test transition domains from existing domains"
|
||||
|
||||
# Generates test transition domains for testing send_domain_invitations script.
|
||||
# Running this script removes all existing transition domains, so use with caution.
|
||||
# Transition domains are created with email addresses provided as command line
|
||||
# argument. Email addresses for testing are passed as comma delimited list of
|
||||
# email addresses, and are required to be provided. Email addresses from the list
|
||||
# are assigned to transition domains at time of creation.
|
||||
|
||||
def add_arguments(self, parser):
|
||||
"""Add command line arguments."""
|
||||
parser.add_argument(
|
||||
"-e",
|
||||
"--emails",
|
||||
required=True,
|
||||
dest="emails",
|
||||
help="Comma-delimited list of email addresses to be used for testing",
|
||||
)
|
||||
|
||||
def handle(self, **options):
|
||||
"""Delete existing TransitionDomains. Generate test ones."""
|
||||
|
||||
# split options[emails] into an array of test emails
|
||||
test_emails = options["emails"].split(",")
|
||||
|
||||
# setting up test data
|
||||
self.delete_test_transition_domains()
|
||||
self.load_test_transition_domains(test_emails)
|
||||
|
||||
def load_test_transition_domains(self, test_emails):
|
||||
"""Load test transition domains"""
|
||||
|
||||
# counter for test_emails index
|
||||
test_emails_counter = 0
|
||||
# Need to get actual domain names from the database for this test
|
||||
real_domains = Domain.objects.all()
|
||||
for real_domain in real_domains:
|
||||
TransitionDomain.objects.create(
|
||||
username=test_emails[test_emails_counter % len(test_emails)],
|
||||
domain_name=real_domain.name,
|
||||
status="created",
|
||||
email_sent=False,
|
||||
)
|
||||
test_emails_counter += 1
|
||||
|
||||
def delete_test_transition_domains(self):
|
||||
self.transition_domains = TransitionDomain.objects.all()
|
||||
for transition_domain in self.transition_domains:
|
||||
transition_domain.delete()
|
148
src/registrar/management/commands/send_domain_invitations.py
Normal file
148
src/registrar/management/commands/send_domain_invitations.py
Normal file
|
@ -0,0 +1,148 @@
|
|||
"""Data migration: Send domain invitations once to existing customers."""
|
||||
|
||||
import logging
|
||||
import copy
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.management import BaseCommand
|
||||
from django.urls import reverse
|
||||
from registrar.models import TransitionDomain, Domain
|
||||
from ...utility.email import send_templated_email, EmailSendingError
|
||||
from typing import List
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Send domain invitations once to existing customers."
|
||||
|
||||
# this array is used to store and process the transition_domains
|
||||
transition_domains: List[str] = []
|
||||
# this array is used to store domains with errors, which are not
|
||||
# sent emails; this array is used to update the succesful
|
||||
# transition_domains to email_sent=True, and also to report
|
||||
# out errors
|
||||
domains_with_errors: List[str] = []
|
||||
# this array is used to store email_context; each item in the array
|
||||
# contains the context for a single email; single emails may be 1
|
||||
# or more transition_domains, as they are grouped by username
|
||||
emails_to_send: List[str] = []
|
||||
|
||||
def add_arguments(self, parser):
|
||||
"""Add command line arguments."""
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--send_emails",
|
||||
action="store_true",
|
||||
default=False,
|
||||
dest="send_emails",
|
||||
help="Send emails ",
|
||||
)
|
||||
|
||||
def handle(self, **options):
|
||||
"""Process the objects in TransitionDomain."""
|
||||
|
||||
logger.debug("checking domains and preparing emails")
|
||||
# Get all TransitionDomain objects
|
||||
self.transition_domains = TransitionDomain.objects.filter(
|
||||
email_sent=False,
|
||||
).order_by("username")
|
||||
|
||||
self.build_emails_to_send_array()
|
||||
|
||||
if options["send_emails"]:
|
||||
logger.debug("about to send emails")
|
||||
self.send_emails()
|
||||
logger.debug("done sending emails")
|
||||
|
||||
self.update_domains_as_sent()
|
||||
|
||||
logger.debug("done sending emails and updating transition_domains")
|
||||
else:
|
||||
logger.debug("not sending emails")
|
||||
|
||||
def build_emails_to_send_array(self):
|
||||
"""this method sends emails to distinct usernames"""
|
||||
|
||||
# data structure to hold email context for a single email;
|
||||
# transition_domains ordered by username, a single email_context
|
||||
# may include information from more than one transition_domain
|
||||
email_context = {"email": ""}
|
||||
|
||||
# loop through all transition_domains; group them by username
|
||||
# into emails_to_send_array
|
||||
for transition_domain in self.transition_domains:
|
||||
# attempt to get the domain from domain objects; if there is
|
||||
# an error getting the domain, skip this domain and add it to
|
||||
# domains_with_errors
|
||||
try:
|
||||
domain = Domain.objects.get(name=transition_domain.domain_name)
|
||||
# if prior username does not match current username
|
||||
if (
|
||||
not email_context["email"]
|
||||
or email_context["email"] != transition_domain.username
|
||||
):
|
||||
# if not first in list of transition_domains
|
||||
if email_context["email"]:
|
||||
# append the email context to the emails_to_send array
|
||||
self.emails_to_send.append(copy.deepcopy(email_context))
|
||||
email_context["domains"] = []
|
||||
email_context["email"] = transition_domain.username
|
||||
email_context["domains"].append(
|
||||
{
|
||||
"name": transition_domain.domain_name,
|
||||
"url": settings.BASE_URL
|
||||
+ reverse("domain", kwargs={"pk": domain.id}),
|
||||
}
|
||||
)
|
||||
except Exception as err:
|
||||
# error condition if domain not in database
|
||||
self.domains_with_errors.append(
|
||||
copy.deepcopy(transition_domain.domain_name)
|
||||
)
|
||||
logger.error(
|
||||
f"error retrieving domain {transition_domain.domain_name}: {err}"
|
||||
)
|
||||
# if there are at least one more transition domains than errors,
|
||||
# then send one more
|
||||
if len(self.transition_domains) > len(self.domains_with_errors):
|
||||
self.emails_to_send.append(email_context)
|
||||
|
||||
def send_emails(self):
|
||||
for email_data in self.emails_to_send:
|
||||
self.send_email(email_data)
|
||||
|
||||
def send_email(self, email_data):
|
||||
try:
|
||||
send_templated_email(
|
||||
"emails/transition_domain_invitation.txt",
|
||||
"emails/transition_domain_invitation_subject.txt",
|
||||
to_address=email_data["email"],
|
||||
context={
|
||||
"domains": email_data["domains"],
|
||||
},
|
||||
)
|
||||
# if log level set to debug, success message is logged
|
||||
logger.debug(
|
||||
f"email sent successfully to {email_data['email']} for "
|
||||
f"{[domain['name'] for domain in email_data['domains']]}"
|
||||
)
|
||||
except EmailSendingError as err:
|
||||
logger.error(
|
||||
f"email did not send successfully to {email_data['email']} "
|
||||
f"for {[domain['name'] for domain in email_data['domains']]}"
|
||||
f": {err}"
|
||||
)
|
||||
# if email failed to send, set error in domains_with_errors for each
|
||||
# domain in the email so that transition domain email_sent is not set
|
||||
# to True
|
||||
for domain in email_data["domains"]:
|
||||
self.domains_with_errors.append(domain)
|
||||
|
||||
def update_domains_as_sent(self):
|
||||
"""set email_sent to True in all transition_domains which have
|
||||
been processed successfully"""
|
||||
for transition_domain in self.transition_domains:
|
||||
if transition_domain.domain_name not in self.domains_with_errors:
|
||||
transition_domain.email_sent = True
|
||||
transition_domain.save()
|
|
@ -0,0 +1,11 @@
|
|||
You have been invited to manage {% if domains|length > 1 %}multiple domains{% else %}the domain {{ domains.0.name }}{% endif %} on get.gov,
|
||||
the registrar for .gov domain names.
|
||||
{%if domains|length > 1 %}
|
||||
To accept your invitation, go to each of the following urls:
|
||||
{% for domain in domains %}
|
||||
{{ domain.url }} (to manage {{ domain.name }})
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
To accept your invitation, go to <{{ domains.0.url }}>.
|
||||
{% endif %}
|
||||
You will need to log in with a Login.gov account using this email address.
|
|
@ -0,0 +1 @@
|
|||
You are invited to manage {% if domains|length > 1 %}multiple domains{% else %}{{ domains.0 }}{% endif %} on get.gov
|
Loading…
Add table
Add a link
Reference in a new issue