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

fix: move remaining emails to dotdigital #2295

Merged
merged 39 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
cafbfd5
move remaining emails to dotdigital
evemartin May 2, 2024
d767de1
Merge branch 'master' into move-remaining-emails-to-dotdigital
evemartin May 2, 2024
f4840fc
fix typos
evemartin May 2, 2024
27ad020
update tests
evemartin May 2, 2024
a31fabb
fix tests
evemartin May 2, 2024
bec6adf
fix tests
evemartin May 2, 2024
cf7f2fc
get rid of unnecessary email messages
evemartin May 2, 2024
cee565f
address PR comments
evemartin May 2, 2024
e3961b3
fix patch
evemartin May 2, 2024
08f03a6
testing some changes to the tests
evemartin May 3, 2024
476d48f
add import
evemartin May 3, 2024
ab3e269
debug tests
evemartin May 3, 2024
7bea968
debug tests
evemartin May 3, 2024
87bf8fa
debug tests
evemartin May 3, 2024
380a7a2
debug tests
evemartin May 3, 2024
cd52a94
change arg order
evemartin May 3, 2024
4a7b4ea
debug tests
evemartin May 3, 2024
82c27ab
debug tests
evemartin May 3, 2024
062b4a6
debug tests
evemartin May 3, 2024
7c0e900
debug tests
evemartin May 3, 2024
57d67b4
debug tests
evemartin May 3, 2024
087f777
debug tests
evemartin May 3, 2024
737d5a9
debug tests
evemartin May 3, 2024
f1a9047
remove import
evemartin May 3, 2024
ffc3721
add import
evemartin May 3, 2024
01203f3
debug tests
evemartin May 3, 2024
0be3b3b
debug tests
evemartin May 3, 2024
2006758
debug tests
evemartin May 3, 2024
1866ea9
debug tests
evemartin May 3, 2024
147d19c
fix login_link url creation
evemartin May 3, 2024
8d39c6a
debug tests
evemartin May 3, 2024
6dd841a
finalize some tests
evemartin May 3, 2024
b16cc04
debug tests
evemartin May 3, 2024
2d6893e
debug tests
evemartin May 3, 2024
deb1455
debug tests
evemartin May 3, 2024
3513021
reset things I tried while debugging
evemartin May 3, 2024
e116bfb
fix invite email condition
evemartin May 3, 2024
6209cb3
add one more email ID
evemartin May 3, 2024
ba61ffe
address PR comment
evemartin May 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 0 additions & 50 deletions cfl_common/common/email_messages.py
Original file line number Diff line number Diff line change
@@ -1,50 +0,0 @@
from django.urls import reverse


def userAlreadyRegisteredEmail(request, email, is_independent_student=False):
if is_independent_student:
login_url = reverse("independent_student_login")
else:
login_url = reverse("teacher_login")

return {
"subject": f"Duplicate account",
"message": (
f"A user is already registered with this email address: {email}.\n"
f"If you've already registered, please login: "
f"{request.build_absolute_uri(login_url)}.\n"
f"Otherwise please register with a different email address."
),
}


def kickedEmail(request, schoolName):
return {
"subject": f"You were successfully released from your school or club",
"message": (
f"You have been released from the school or club '{schoolName}'. "
f"If you think this was an error, please contact the administrator of that "
f"school or club."
),
}


def inviteTeacherEmail(request, schoolName, token, account_exists):
url = f"{request.build_absolute_uri(reverse('invited_teacher', kwargs={'token': token}))} "

if account_exists:
message = (
f"A teacher at the school '{schoolName}' has invited you to join Code for Life. 🎉 Unfortunately, you "
f"already have an account with this email address, so you will need to either delete it first or change "
f"the email registered to your other account. After that, you can complete the registration process, by "
f"following the link below.\n\n"
f"{url}"
)
else:
message = (
f"A teacher at the school '{schoolName}' has invited you to join Code for Life. 🎉 To complete the "
f"registration process, please create a password by following the link below.\n\n"
f"{url}"
)

return {"subject": f"You've been invited to join Code for Life", "message": message}
4 changes: 4 additions & 0 deletions cfl_common/common/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,14 @@
"delete_account": 1567477,
"email_change_notification": 1551600,
"email_change_verification": 1551594,
"invite_teacher_with_account": 1569599,
"invite_teacher_without_account": 1569607,
"reset_password": 1557153,
"student_join_request_notification": 1569486,
"student_join_request_rejected": 1569470,
"student_join_request_sent": 1569477,
"teacher_released": 1569537,
"user_already_registered": 1569539,
"verify_new_user": 1551577,
"verify_new_user_first_reminder": 1557170,
"verify_new_user_second_reminder": 1557173,
Expand Down
13 changes: 2 additions & 11 deletions cfl_common/common/tests/utils/email.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,15 @@ def follow_verify_email_link_to_login(page, url, user_type):
return go_to_independent_student_login_page(page.browser)


def follow_duplicate_account_link_to_login(page, email, user_type):
_follow_duplicate_account_email_link(page, email)
def follow_duplicate_account_link_to_login(page, url, user_type):
page.browser.get(url)

if user_type == "teacher":
return go_to_teacher_login_page(page.browser)
elif user_type == "independent":
return go_to_independent_student_login_page(page.browser)


def _follow_duplicate_account_email_link(page, email):
message = str(email.message())
prefix = 'please login: <a href="'
i = str.find(message, prefix) + len(prefix)
suffix = '" rel="nofollow">'
j = str.find(message, suffix, i)
page.browser.get(message[i:j])


def follow_reset_email_link(browser, link):
browser.get(link)

Expand Down
4 changes: 2 additions & 2 deletions cfl_common/common/tests/utils/student.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def generate_independent_student_details():
generate_independent_student_details.next_id = 1


def signup_duplicate_independent_student_fail(page, duplicate_email=None):
def signup_duplicate_independent_student_fail(page, login_link, duplicate_email=None):
page = page.go_to_signup_page()

name, username, email_address, password = generate_independent_student_details()
Expand All @@ -114,7 +114,7 @@ def signup_duplicate_independent_student_fail(page, duplicate_email=None):

page = page.return_to_home_page()

page = email.follow_duplicate_account_link_to_login(page, mail.outbox[0], "independent")
page = email.follow_duplicate_account_link_to_login(page, login_link, "independent")

return page, name, username, email_address, password

Expand Down
8 changes: 5 additions & 3 deletions cfl_common/common/tests/utils/teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,18 @@ def signup_teacher_directly(preverified=True, **kwargs):
return email_address, password


def signup_duplicate_teacher_fail(page, duplicate_email):
@patch("common.helpers.emails.send_dotdigital_email")
def signup_duplicate_teacher_fail(page, mock_send_dotdigital_email, duplicate_email=None):
page = page.go_to_signup_page()

first_name, last_name, email_address, password = generate_details()
page = page.signup(first_name, last_name, duplicate_email, password, password)

page = page.return_to_home_page()

page = email.follow_duplicate_account_link_to_login(page, mail.outbox[0], "teacher")
mail.outbox = []
login_link = mock_send_dotdigital_email.call_args.kwargs["personalization_values"]["LOGIN_URL"]

page = email.follow_duplicate_account_link_to_login(page, login_link, "teacher")

return page, email_address, password

Expand Down
20 changes: 13 additions & 7 deletions portal/tests/test_independent_student.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,20 +222,25 @@ def test_signup_without_newsletter(self):
page, _, _, _, _ = create_independent_student(page)
assert is_email_verified_message_showing(self.selenium)

def test_signup_duplicate_email_failure(self):
@patch("common.helpers.emails.send_dotdigital_email")
def test_signup_duplicate_email_failure(self, mock_send_dotdigital_email: Mock):
page = self.go_to_homepage()
page, _, _, email, _ = create_independent_student(page)
assert is_email_verified_message_showing(self.selenium)

login_link = mock_send_dotdigital_email.call_args.kwargs["personalization_values"]["LOGIN_URL"]

page = self.go_to_homepage()
page, _, _, _, _ = signup_duplicate_independent_student_fail(page, duplicate_email=email)
page, _, _, _, _ = signup_duplicate_independent_student_fail(page, login_link, duplicate_email=email)

assert len(mail.outbox) == 1
assert mail.outbox[0].subject == "Duplicate account"
mock_send_dotdigital_email.assert_called_once_with(
campaign_ids["user_already_registered"], ANY, personalization_values=ANY
)

assert self.is_login_page(page)

def test_signup_duplicate_email_with_teacher(self):
@patch("common.helpers.emails.send_dotdigital_email")
def test_signup_duplicate_email_with_teacher(self, mock_send_dotdigital_email: Mock):
teacher_email, _ = signup_teacher_directly()

page = self.go_to_homepage()
Expand All @@ -248,8 +253,9 @@ def test_signup_duplicate_email_with_teacher(self):

page.return_to_home_page()

assert len(mail.outbox) == 1
assert mail.outbox[0].subject == "Duplicate account"
mock_send_dotdigital_email.assert_called_once_with(
campaign_ids["user_already_registered"], ANY, personalization_values=ANY
)

def test_login_failure(self):
page = self.go_to_homepage()
Expand Down
25 changes: 10 additions & 15 deletions portal/views/home.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
send_email,
send_verification_email,
)
from common.models import Student, Teacher, DynamicElement, TotalActivity
from common.mail import campaign_ids, send_dotdigital_email
from common.models import DynamicElement, Student, Teacher, TotalActivity
from common.permissions import logged_in_as_student, logged_in_as_teacher
from common.utils import _using_two_factor
from django.contrib import messages as messages
Expand All @@ -34,8 +35,7 @@
from portal.strings.coding_club import CODING_CLUB_BANNER
from portal.strings.home_learning import HOME_LEARNING_BANNER
from portal.templatetags.app_tags import cloud_storage
from portal.views.teacher.teach import DownloadType
from portal.views.teacher.teach import count_student_pack_downloads_click
from portal.views.teacher.teach import DownloadType, count_student_pack_downloads_click

LOGGER = logging.getLogger(__name__)

Expand Down Expand Up @@ -126,7 +126,7 @@ def process_signup_form(request, data):
email = data["teacher_email"]

if email and User.objects.filter(email=email).exists():
email_message = email_messages.userAlreadyRegisteredEmail(request, email)

is_email_ratelimited = is_ratelimited(
request=request,
group=RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP,
Expand All @@ -136,12 +136,10 @@ def process_signup_form(request, data):
)

if not is_email_ratelimited:
send_email(
NOTIFICATION_EMAIL,
send_dotdigital_email(
campaign_ids["user_already_registered"],
[email],
email_message["subject"],
email_message["message"],
email_message["subject"],
personalization_values={"EMAIL": email, "LOGIN_URL": reverse("teacher_login")},
)
else:
LOGGER.warn(f"Ratelimit teacher {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}")
Expand All @@ -164,7 +162,6 @@ def process_independent_student_signup_form(request, data):
email = data["email"]

if email and User.objects.filter(email=email).exists():
email_message = email_messages.userAlreadyRegisteredEmail(request, email, is_independent_student=True)
is_email_ratelimited = is_ratelimited(
request=request,
group=RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP,
Expand All @@ -174,12 +171,10 @@ def process_independent_student_signup_form(request, data):
)

if not is_email_ratelimited:
send_email(
NOTIFICATION_EMAIL,
send_dotdigital_email(
campaign_ids["user_already_registered"],
[email],
email_message["subject"],
email_message["message"],
email_message["subject"],
personalization_values={"EMAIL": email, "LOGIN_URL": reverse("independent_student_login")},
)
else:
LOGGER.warning(f"Ratelimit independent {RATELIMIT_USER_ALREADY_REGISTERED_EMAIL_GROUP}: {email}")
Expand Down
49 changes: 35 additions & 14 deletions portal/views/teacher/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,24 @@ def dashboard_teacher_view(request, is_admin):
)

account_exists = User.objects.filter(email=invited_teacher_email).exists()
message = email_messages.inviteTeacherEmail(request, school.name, token, account_exists)
send_email(
INVITE_FROM, [invited_teacher_email], message["subject"], message["message"], message["subject"]

registration_link = (
f"{request.build_absolute_uri(reverse('invited_teacher', kwargs={'token': token}))} "
)

if account_exists:
send_dotdigital_email(
campaign_ids["invite_teacher_with_account"],
[invited_teacher_email],
personalization_values={"SCHOOL_NAME": school.name, "REGISTRATION_LINK": registration_link},
)
else:
send_dotdigital_email(
campaign_ids["invite_teacher_without_account"],
[invited_teacher_email],
personalization_values={"SCHOOL_NAME": school.name, "REGISTRATION_LINK": registration_link},
)

messages.success(
request,
f"You have invited {invited_teacher_first_name} {invited_teacher_last_name} to your school.",
Expand Down Expand Up @@ -375,14 +388,10 @@ def organisation_kick(request, pk):

messages.success(request, success_message)

emailMessage = email_messages.kickedEmail(request, user.school.name)

send_email(
NOTIFICATION_EMAIL,
send_dotdigital_email(
campaign_ids["teacher_released"],
[teacher.new_user.email],
emailMessage["subject"],
emailMessage["message"],
emailMessage["subject"],
personalization_values={"SCHOOL_CLUB_NAME": user.school.name},
)

return HttpResponseRedirect(reverse_lazy("dashboard"))
Expand Down Expand Up @@ -589,10 +598,22 @@ def resend_invite_teacher(request, token):
teacher = Teacher.objects.filter(id=invite.from_teacher.id)[0]

messages.success(request, "Teacher re-invited!")
message = email_messages.inviteTeacherEmail(request, invite.school, token, not (invite.is_expired))
send_email(
INVITE_FROM, [invite.invited_teacher_email], message["subject"], message["message"], message["subject"]
)

registration_link = f"{request.build_absolute_uri(reverse('invited_teacher', kwargs={'token': token}))} "

if invite.is_expired:
send_dotdigital_email(
campaign_ids["invite_teacher_without_account"],
[invite.invited_teacher_email],
personalization_values={"SCHOOL_NAME": invite.school, "REGISTRATION_LINK": registration_link},
)
else:
send_dotdigital_email(
campaign_ids["invite_teacher_with_account"],
[invite.invited_teacher_email],
personalization_values={"SCHOOL_NAME": invite.school, "REGISTRATION_LINK": registration_link},
)

return HttpResponseRedirect(reverse_lazy("dashboard"))


Expand Down
Loading