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 reset password email #2281

Merged
merged 58 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
6226ef9
fix: move verification emails to Dotdigital
evemartin Mar 28, 2024
d3b94b6
Merge branch 'master' into move-verification-emails-to-dotdigital
evemartin Mar 28, 2024
48cb482
fix: fix dotdigital email tests
evemartin Apr 2, 2024
dc6b581
fix: fix parent email test
evemartin Apr 2, 2024
84a5001
fix: add github secret binding
evemartin Apr 2, 2024
3eaaecb
fix: add chrome to dev container
evemartin Apr 2, 2024
55d6029
fix: attempt to fix under 13 test
evemartin Apr 2, 2024
33d57f4
fix: attempt to fix patching
evemartin Apr 2, 2024
f81868a
fix: continue work on updating tests
evemartin Apr 4, 2024
261cf33
fix: continue to update tests
evemartin Apr 4, 2024
0aa6d29
fix: fix package names
evemartin Apr 4, 2024
d4e95fe
fix: fix test assert
evemartin Apr 4, 2024
3ba97c2
fix: fix assert
evemartin Apr 4, 2024
9651a2a
fix: update tests
evemartin Apr 4, 2024
fcdf86d
fix: rearrange decorators
evemartin Apr 4, 2024
537f333
fix: continue work on tests
evemartin Apr 4, 2024
8add1ec
fix: fix typo
evemartin Apr 4, 2024
ea6239a
fix: testing something out
evemartin Apr 4, 2024
688013b
fix: testing something out
evemartin Apr 4, 2024
3ef54f4
fix: undo chrome changes
evemartin Apr 4, 2024
6dbe672
fix: adding additional mocks
evemartin Apr 4, 2024
f3a1cae
fix: debug tests
evemartin Apr 4, 2024
9ee8e3e
fix: debug tests
evemartin Apr 4, 2024
3305851
fix: debug tests
evemartin Apr 4, 2024
6502383
fix: debug tests
evemartin Apr 4, 2024
bd4942c
fix: debug tests
evemartin Apr 4, 2024
296d1cf
fix: debug tests
evemartin Apr 4, 2024
4327fee
fix: debug tests
evemartin Apr 4, 2024
dd8b086
fix: debug tests
evemartin Apr 4, 2024
a1f0674
fix: debug tests
evemartin Apr 4, 2024
1dc615a
fix: add forgotten import
evemartin Apr 4, 2024
643dfd2
fix: update dotdigital auth
evemartin Apr 9, 2024
5ab9fe3
fix: fix environmental variable
evemartin Apr 9, 2024
1425477
fix: address PR comments
evemartin Apr 9, 2024
566f528
fix: address PR comments
evemartin Apr 9, 2024
6abe884
fix: debug tests
evemartin Apr 9, 2024
e829610
fix: debug tests
evemartin Apr 9, 2024
1bc639f
fix: tidy code, replace verification reminder emails
evemartin Apr 9, 2024
4d3ac93
fix: fix verification reminder email tests
evemartin Apr 9, 2024
cc1e7c1
fix: debug tests
evemartin Apr 9, 2024
4e9cc43
fix: debug tests
evemartin Apr 9, 2024
dac0b40
fix: fix patch mock
evemartin Apr 10, 2024
3e472f3
fix: move reset password email
evemartin Apr 10, 2024
b8947e9
fix: tidy code
evemartin Apr 10, 2024
7d4f4fd
fix: remove old code
evemartin Apr 10, 2024
7d5a464
fix: debug tests
evemartin Apr 10, 2024
f9a1f52
fix: debug tests
evemartin Apr 10, 2024
4f4181c
fix: debug tests
evemartin Apr 10, 2024
23a53b8
Update ci.yml
evemartin Apr 10, 2024
68b4fa0
Update ci.yml
evemartin Apr 10, 2024
e68775d
Update ci.yml
evemartin Apr 10, 2024
1571ed1
Update ci.yml
evemartin Apr 10, 2024
3dc98b3
Merge branch 'master' into move-reset-password-email
evemartin Apr 10, 2024
7c7bfa1
fix: tidy code
evemartin Apr 11, 2024
c33ca26
fix: tidy code
evemartin Apr 11, 2024
6407c50
Merge branch 'master' into move-reset-password-email
faucomte97 Apr 11, 2024
b92837d
fix: address PR comments
evemartin Apr 11, 2024
8ab1243
Merge branch 'master' into move-reset-password-email
faucomte97 Apr 11, 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
15 changes: 1 addition & 14 deletions cfl_common/common/email_messages.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,4 @@
from django.urls import reverse, reverse_lazy


def resetEmailPasswordMessage(request, domain, uid, token, protocol):
password_reset_uri = reverse_lazy("password_reset_check_and_confirm", kwargs={"uidb64": uid, "token": token})
url = f"{protocol}://{domain}{password_reset_uri}"
return {
"subject": f"Password reset request",
"message": (
f"You are receiving this email because you requested "
f"a password reset for your Code For Life user account.\n\n"
f"Please go to the following page and choose a new password: {url}"
),
}
from django.urls import reverse


def userAlreadyRegisteredEmail(request, email, is_independent_student=False):
Expand Down
1 change: 1 addition & 0 deletions cfl_common/common/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
campaign_ids = {
"email_change_notification": 1551600,
"email_change_verification": 1551594,
"reset_password": 1557153,
"verify_new_user": 1551577,
"verify_new_user_first_reminder": 1557170,
"verify_new_user_second_reminder": 1557173,
Expand Down
5 changes: 1 addition & 4 deletions cfl_common/common/tests/utils/email.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import re
from builtins import str


Expand Down Expand Up @@ -35,9 +34,7 @@ def _follow_duplicate_account_email_link(page, email):
page.browser.get(message[i:j])


def follow_reset_email_link(browser, email):
message = str(email.body)
link = re.search("http.+/", message).group(0)[:-1]
def follow_reset_email_link(browser, link):
browser.get(link)

from portal.tests.pageObjects.portal.password_reset_form_page import (
Expand Down
37 changes: 16 additions & 21 deletions portal/forms/registration.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
from captcha.fields import ReCaptchaField
from captcha.widgets import ReCaptchaV2Invisible
from common.email_messages import resetEmailPasswordMessage
from common.helpers.emails import NOTIFICATION_EMAIL, send_email
from common.mail import campaign_ids, send_dotdigital_email
from common.models import Student, Teacher
from django import forms
from django.contrib.auth import forms as django_auth_forms
from django.contrib.auth import get_user_model
from django.contrib.auth.tokens import default_token_generator
from django.contrib.sites.shortcuts import get_current_site
from django.urls import reverse_lazy
from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_encode

from portal.helpers.password import PasswordStrength, form_clean_password


Expand Down Expand Up @@ -74,30 +75,24 @@ def save(
continue
if not domain_override:
current_site = get_current_site(request)
site_name = current_site.name
domain = current_site.domain
else:
site_name = domain = domain_override
context = {
"email": user.email,
"domain": domain,
"site_name": site_name,
"uid": urlsafe_base64_encode(force_bytes(user.pk)),
"user": user,
"token": token_generator.make_token(user),
"protocol": self._compute_protocol(use_https),
}

email_subject_content = resetEmailPasswordMessage(
request, domain, context["uid"], context["token"], context["protocol"]
domain = domain_override

reset_password_uri = reverse_lazy(
"password_reset_check_and_confirm",
kwargs={
"uidb64": urlsafe_base64_encode(force_bytes(user.pk)),
"token": token_generator.make_token(user),
},
)
protocol = self._compute_protocol(use_https)
reset_password_url = f"{protocol}://{domain}{reset_password_uri}"

send_email(
NOTIFICATION_EMAIL,
send_dotdigital_email(
campaign_ids["reset_password"],
[user.email],
email_subject_content["subject"],
email_subject_content["message"],
email_subject_content["subject"],
personalization_values={"RESET_PASSWORD_LINK": reset_password_url},
)

def _compute_protocol(self, use_https):
Expand Down
18 changes: 11 additions & 7 deletions portal/tests/test_independent_student.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,17 +284,22 @@ def test_login_not_verified(self, mock_send_dotdigital_email):

assert self.is_dashboard(page)

def test_reset_password(self):
@patch("portal.forms.registration.send_dotdigital_email")
def test_reset_password(self, mock_send_dotdigital_email: Mock):
page = self.go_to_homepage()

page, name, username, _, _ = create_independent_student(page)
page = self.get_to_forgotten_password_page()

page.reset_email_submit(username)

self.wait_for_email()
mock_send_dotdigital_email.assert_called_with(campaign_ids["reset_password"], ANY, personalization_values=ANY)

page = email_utils.follow_reset_email_link(self.selenium, mail.outbox[0])
reset_password_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"][
"RESET_PASSWORD_LINK"
]

page = email_utils.follow_reset_email_link(self.selenium, reset_password_url)

new_password = "AnotherPassword12"

Expand All @@ -312,14 +317,13 @@ def test_reset_password(self):
page = page.go_to_account_page()
assert page.check_account_details({"name": name})

def test_reset_password_fail(self):
@patch("portal.forms.registration.send_dotdigital_email")
def test_reset_password_fail(self, mock_send_dotdigital_email: Mock):
page = self.get_to_forgotten_password_page()
fake_email = "[email protected]"
page.reset_email_submit(fake_email)

time.sleep(5)

assert len(mail.outbox) == 0
mock_send_dotdigital_email.assert_not_called()

def test_update_name_success(self):
homepage = self.go_to_homepage()
Expand Down
15 changes: 9 additions & 6 deletions portal/tests/test_ratelimit.py
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,8 @@ def test_successful_request_resets_cache(self):

assert get_ratelimit_count_for_user(email) == 1

def test_teacher_reset_password_unblocks_user(self):
@patch("portal.forms.registration.send_dotdigital_email")
def test_teacher_reset_password_unblocks_user(self, mock_send_dotdigital_email: Mock):
"""
Given a blocked teacher,
When they reset they password,
Expand All @@ -344,15 +345,17 @@ def test_teacher_reset_password_unblocks_user(self):
# Ask for reset password link
self._reset_password_request(email)

assert len(mail.outbox) == 1
mock_send_dotdigital_email.assert_called_once_with(
campaign_ids["reset_password"], ANY, personalization_values=ANY
)

# Get reset link from email
message = str(mail.outbox[0].body)
url = re.search("http.+/", message).group(0)
reset_password_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"][
"RESET_PASSWORD_LINK"
]

new_password = "AnotherPassword12!"

self._reset_password(url, new_password)
self._reset_password(reset_password_url, new_password)

login_response = self._teacher_login(email, new_password)

Expand Down
29 changes: 19 additions & 10 deletions portal/tests/test_teacher.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,8 @@ def test_change_password(self):

assert self.is_dashboard_page(page)

def test_reset_password(self):
@patch("portal.forms.registration.send_dotdigital_email")
def test_reset_password(self, mock_send_dotdigital_email: Mock):
email, _ = signup_teacher_directly()
create_organisation_directly(email)
_, _, access_code = create_class_directly(email)
Expand All @@ -638,9 +639,13 @@ def test_reset_password(self):

page.reset_email_submit(email)

self.wait_for_email()
mock_send_dotdigital_email.assert_called_with(campaign_ids["reset_password"], ANY, personalization_values=ANY)

page = email_utils.follow_reset_email_link(self.selenium, mail.outbox[0])
reset_password_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"][
"RESET_PASSWORD_LINK"
]

page = email_utils.follow_reset_email_link(self.selenium, reset_password_url)

new_password = "AnotherPassword12!"

Expand All @@ -650,7 +655,8 @@ def test_reset_password(self):
page = HomePage(self.selenium).go_to_teacher_login_page().login(email, new_password)
assert self.is_dashboard_page(page)

def test_reset_with_same_password(self):
@patch("portal.forms.registration.send_dotdigital_email")
def test_reset_with_same_password(self, mock_send_dotdigital_email: Mock):
email, password = signup_teacher_directly()
create_organisation_directly(email)
_, _, access_code = create_class_directly(email)
Expand All @@ -660,23 +666,26 @@ def test_reset_with_same_password(self):

page.reset_email_submit(email)

self.wait_for_email()
mock_send_dotdigital_email.assert_called_with(campaign_ids["reset_password"], ANY, personalization_values=ANY)

reset_password_url = mock_send_dotdigital_email.call_args.kwargs["personalization_values"][
"RESET_PASSWORD_LINK"
]

page = email_utils.follow_reset_email_link(self.selenium, mail.outbox[0])
page = email_utils.follow_reset_email_link(self.selenium, reset_password_url)

page.reset_password_fail(password)

message = page.browser.find_element(By.CLASS_NAME, "errorlist")
assert "Please choose a password that you haven't used before" in message.text

def test_reset_password_fail(self):
@patch("portal.forms.registration.send_dotdigital_email")
def test_reset_password_fail(self, mock_send_dotdigital_email: Mock):
page = self.get_to_forgotten_password_page()
fake_email = "[email protected]"
page.reset_email_submit(fake_email)

time.sleep(5)

assert len(mail.outbox) == 0
mock_send_dotdigital_email.assert_not_called()

def test_admin_sees_all_school_classes(self):
email, password = signup_teacher_directly()
Expand Down
Loading