Skip to content

Commit

Permalink
Factorise Dotmailer methods
Browse files Browse the repository at this point in the history
  • Loading branch information
faucomte97 committed Oct 10, 2024
1 parent 5e5e50b commit 0ba5dbb
Show file tree
Hide file tree
Showing 6 changed files with 358 additions and 140 deletions.
1 change: 0 additions & 1 deletion cfl_common/common/app_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

# Dotmailer URLs for adding users to the newsletter address book
DOTMAILER_CREATE_CONTACT_URL = getattr(settings, "DOTMAILER_CREATE_CONTACT_URL", "")
DOTMAILER_MAIN_ADDRESS_BOOK_URL = getattr(settings, "DOTMAILER_MAIN_ADDRESS_BOOK_URL", "")
DOTMAILER_TEACHER_ADDRESS_BOOK_URL = getattr(settings, "DOTMAILER_TEACHER_ADDRESS_BOOK_URL", "")
DOTMAILER_STUDENT_ADDRESS_BOOK_URL = getattr(settings, "DOTMAILER_STUDENT_ADDRESS_BOOK_URL", "")
DOTMAILER_NO_ACCOUNT_ADDRESS_BOOK_URL = getattr(settings, "DOTMAILER_NO_ACCOUNT_ADDRESS_BOOK_URL", "")
Expand Down
210 changes: 153 additions & 57 deletions cfl_common/common/helpers/emails.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@

import jwt
from common import app_settings
from common.mail import campaign_ids, django_send_email, send_dotdigital_email
from common.mail import (
address_book_ids,
campaign_ids,
django_send_email,
send_dotdigital_email,
)
from common.models import Student, Teacher
from django.conf import settings
from django.contrib.auth.models import User
Expand All @@ -15,9 +20,15 @@
from requests import delete, get, post, put
from requests.exceptions import RequestException

NOTIFICATION_EMAIL = "Code For Life Notification <" + app_settings.EMAIL_ADDRESS + ">"
VERIFICATION_EMAIL = "Code For Life Verification <" + app_settings.EMAIL_ADDRESS + ">"
PASSWORD_RESET_EMAIL = "Code For Life Password Reset <" + app_settings.EMAIL_ADDRESS + ">"
NOTIFICATION_EMAIL = (
"Code For Life Notification <" + app_settings.EMAIL_ADDRESS + ">"
)
VERIFICATION_EMAIL = (
"Code For Life Verification <" + app_settings.EMAIL_ADDRESS + ">"
)
PASSWORD_RESET_EMAIL = (
"Code For Life Password Reset <" + app_settings.EMAIL_ADDRESS + ">"
)
INVITE_FROM = "Code For Life Invitation <" + app_settings.EMAIL_ADDRESS + ">"


Expand All @@ -41,7 +52,9 @@ def generate_token_for_email(email: str, new_email: str = ""):
"email": email,
"new_email": new_email,
"email_verification_token": uuid4().hex[:30],
"expires": (timezone.now() + datetime.timedelta(hours=1)).timestamp(),
"expires": (
timezone.now() + datetime.timedelta(hours=1)
).timestamp(),
},
settings.SECRET_KEY,
algorithm="HS256",
Expand All @@ -62,10 +75,21 @@ def send_email(
plaintext_template="email.txt",
html_template="email.html",
):
django_send_email(sender, recipients, subject, text_content, title, replace_url, plaintext_template, html_template)
django_send_email(

Check warning on line 78 in cfl_common/common/helpers/emails.py

View check run for this annotation

Codecov / codecov/patch

cfl_common/common/helpers/emails.py#L78

Added line #L78 was not covered by tests
sender,
recipients,
subject,
text_content,
title,
replace_url,
plaintext_template,
html_template,
)


def send_verification_email(request, user, data, new_email=None, age=None, school=None):
def send_verification_email(
request, user, data, new_email=None, age=None, school=None
):
"""
Sends emails relating to email address verification.
Expand Down Expand Up @@ -98,69 +122,81 @@ def send_verification_email(request, user, data, new_email=None, age=None, schoo
url = f"{request.build_absolute_uri(reverse('verify_email', kwargs={'token': verification}))}"

send_dotdigital_email(
campaign_ids["verify_released_student"], [user.email],
personalization_values={"VERIFICATION_LINK": url, "SCHOOL_NAME": school.name}
campaign_ids["verify_released_student"],
[user.email],
personalization_values={
"VERIFICATION_LINK": url,
"SCHOOL_NAME": school.name,
},
)
else:
url = f"{request.build_absolute_uri(reverse('verify_email', kwargs={'token': verification}))}"

send_dotdigital_email(
campaign_ids["verify_new_user"], [user.email], personalization_values={"VERIFICATION_LINK": url}
campaign_ids["verify_new_user"],
[user.email],
personalization_values={"VERIFICATION_LINK": url},
)

if _newsletter_ticked(data):
add_to_dotmailer(user.first_name, user.last_name, user.email, DotmailerUserType.TEACHER)
add_to_dotmailer(
user.first_name,
user.last_name,
user.email,
address_book_ids["newsletter"],
DotmailerUserType.TEACHER,
)
# if the user is an independent student
else:
if age < 13:
url = f"{request.build_absolute_uri(reverse('verify_email', kwargs={'token': verification}))}"
send_dotdigital_email(
campaign_ids["verify_new_user_via_parent"],
[user.email],
personalization_values={"FIRST_NAME": user.first_name, "ACTIVATION_LINK": url},
personalization_values={
"FIRST_NAME": user.first_name,
"ACTIVATION_LINK": url,
},
)
else:
url = f"{request.build_absolute_uri(reverse('verify_email', kwargs={'token': verification}))}"
send_dotdigital_email(
campaign_ids["verify_new_user"], [user.email], personalization_values={"VERIFICATION_LINK": url}
campaign_ids["verify_new_user"],
[user.email],
personalization_values={"VERIFICATION_LINK": url},
)

if _newsletter_ticked(data):
add_to_dotmailer(user.first_name, user.last_name, user.email, DotmailerUserType.STUDENT)
add_to_dotmailer(

Check warning on line 170 in cfl_common/common/helpers/emails.py

View check run for this annotation

Codecov / codecov/patch

cfl_common/common/helpers/emails.py#L170

Added line #L170 was not covered by tests
user.first_name,
user.last_name,
user.email,
address_book_ids["newsletter"],
DotmailerUserType.STUDENT,
)
# verifying change of email address.
else:
verification = generate_token(user, new_email)
url = f"{request.build_absolute_uri(reverse('verify_email', kwargs={'token': verification}))}"
send_dotdigital_email(
campaign_ids["email_change_verification"], [new_email], personalization_values={"VERIFICATION_LINK": url}
campaign_ids["email_change_verification"],
[new_email],
personalization_values={"VERIFICATION_LINK": url},
)


def add_to_dotmailer(first_name: str, last_name: str, email: str, user_type: DotmailerUserType):
try:
create_contact(first_name, last_name, email)
add_contact_to_address_book(first_name, last_name, email, user_type)
except RequestException:
return HttpResponse(status=404)


def add_donor_to_dotmailer(first_name: str, last_name: str, email: str):
def add_to_dotmailer(
first_name: str,
last_name: str,
email: str,
address_book_id: int,
user_type: DotmailerUserType = None,
):
try:
create_contact(first_name, last_name, email)
main_address_book_url = "https://r1-api.dotmailer.com/v2/address-books/37649245/contacts"

body = {
"email": email,
"optInType": "VerifiedDouble",
"emailType": "Html",
"dataFields": [
{"key": "FIRSTNAME", "value": first_name},
{"key": "LASTNAME", "value": last_name},
{"key": "FULLNAME", "value": f"{first_name} {last_name}"},
],
}

post(main_address_book_url, json=body, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))
add_contact_to_address_book(
first_name, last_name, email, address_book_id, user_type
)
except RequestException:
return HttpResponse(status=404)

Expand All @@ -178,15 +214,34 @@ def create_contact(first_name, last_name, email):
{"key": "FULLNAME", "value": f"{first_name} {last_name}"},
],
},
"consentFields": [{"fields": [{"key": "DATETIMECONSENTED", "value": datetime.datetime.now().__str__()}]}],
"consentFields": [
{
"fields": [
{
"key": "DATETIMECONSENTED",
"value": datetime.datetime.now().__str__(),
}
]
}
],
"preferences": app_settings.DOTMAILER_DEFAULT_PREFERENCES,
}

post(url, json=body, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))
post(
url,
json=body,
auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD),
)


def add_contact_to_address_book(first_name: str, last_name: str, email: str, user_type: DotmailerUserType):
main_address_book_url = app_settings.DOTMAILER_MAIN_ADDRESS_BOOK_URL
def add_contact_to_address_book(
first_name: str,
last_name: str,
email: str,
address_book_id: int,
user_type: DotmailerUserType = None,
):
main_address_book_url = f"https://r1-api.dotmailer.com/v2/address-books/{address_book_id}/contacts"

body = {
"email": email,
Expand All @@ -199,60 +254,101 @@ def add_contact_to_address_book(first_name: str, last_name: str, email: str, use
],
}

post(main_address_book_url, json=body, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))

specific_address_book_url = app_settings.DOTMAILER_NO_ACCOUNT_ADDRESS_BOOK_URL
post(
main_address_book_url,
json=body,
auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD),
)

if user_type == DotmailerUserType.TEACHER:
specific_address_book_url = app_settings.DOTMAILER_TEACHER_ADDRESS_BOOK_URL
elif user_type == DotmailerUserType.STUDENT:
specific_address_book_url = app_settings.DOTMAILER_STUDENT_ADDRESS_BOOK_URL
if user_type is not None:
specific_address_book_url = (
app_settings.DOTMAILER_NO_ACCOUNT_ADDRESS_BOOK_URL
)

post(specific_address_book_url, json=body, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))
if user_type == DotmailerUserType.TEACHER:
specific_address_book_url = (
app_settings.DOTMAILER_TEACHER_ADDRESS_BOOK_URL
)
elif user_type == DotmailerUserType.STUDENT:
specific_address_book_url = (
app_settings.DOTMAILER_STUDENT_ADDRESS_BOOK_URL
)

post(
specific_address_book_url,
json=body,
auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD),
)


def delete_contact(email: str):
try:
user = get_dotmailer_user_by_email(email)
user_id = user.get("id")
if user_id:
url = app_settings.DOTMAILER_DELETE_USER_BY_ID_URL.replace("ID", str(user_id))
delete(url, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))
url = app_settings.DOTMAILER_DELETE_USER_BY_ID_URL.replace(
"ID", str(user_id)
)
delete(
url,
auth=(
app_settings.DOTMAILER_USER,
app_settings.DOTMAILER_PASSWORD,
),
)
except RequestException:
return HttpResponse(status=404)


def get_dotmailer_user_by_email(email):
url = app_settings.DOTMAILER_GET_USER_BY_EMAIL_URL.replace("EMAIL", email)

response = get(url, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))
response = get(
url, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD)
)

return json.loads(response.content)


def add_consent_record_to_dotmailer_user(user):
consent_date_time = datetime.datetime.now().__str__()

url = app_settings.DOTMAILER_PUT_CONSENT_DATA_URL.replace("USER_ID", str(user["id"]))
url = app_settings.DOTMAILER_PUT_CONSENT_DATA_URL.replace(
"USER_ID", str(user["id"])
)
body = {
"contact": {
"email": user["email"],
"optInType": user["optInType"],
"emailType": user["emailType"],
"dataFields": user["dataFields"],
},
"consentFields": [{"fields": [{"key": "DATETIMECONSENTED", "value": consent_date_time}]}],
"consentFields": [
{
"fields": [
{"key": "DATETIMECONSENTED", "value": consent_date_time}
]
}
],
}

put(url, json=body, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))
put(
url,
json=body,
auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD),
)


def send_dotmailer_consent_confirmation_email_to_user(user):
url = app_settings.DOTMAILER_SEND_CAMPAIGN_URL
campaign_id = app_settings.DOTMAILER_THANKS_FOR_STAYING_CAMPAIGN_ID
body = {"campaignID": campaign_id, "contactIds": [str(user["id"])]}

post(url, json=body, auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD))
post(
url,
json=body,
auth=(app_settings.DOTMAILER_USER, app_settings.DOTMAILER_PASSWORD),
)


def update_indy_email(user, request, data):
Expand Down
5 changes: 5 additions & 0 deletions cfl_common/common/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
"inactive_users_on_website_final_reminder": 1606215,
}

address_book_ids = {
"newsletter": 9705772,
"donors": 37649245,
}


def add_contact(email: str):
"""Add a new contact to Dotdigital."""
Expand Down
Loading

0 comments on commit 0ba5dbb

Please sign in to comment.