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 account deletion email to dotdigital #2289

Merged
merged 17 commits into from
May 2, 2024
13 changes: 0 additions & 13 deletions cfl_common/common/email_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,3 @@ def inviteTeacherEmail(request, schoolName, token, account_exists):
)

return {"subject": f"You've been invited to join Code for Life", "message": message}


def accountDeletionEmail(request):
return {
"subject": f"We are sorry to see you go",
"title": "Your account was successfully deleted",
"message": (
f"If you have a moment before you leave us completely, please "
f"let us know the reason through our super short survey below."
f"\n\nGive feedback: https://usabi.li/do/d8e0313a31d7/5bef"
f"\n\nThank you for being part of the Code for Life community!"
),
}
1 change: 1 addition & 0 deletions cfl_common/common/mail.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
campaign_ids = {
"admin_given": 1569057,
"admin_revoked": 1569071,
"delete_account": 1567477,
"email_change_notification": 1551600,
"email_change_verification": 1551594,
"reset_password": 1557153,
Expand Down
5 changes: 3 additions & 2 deletions portal/tests/test_independent_student.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,8 @@ def test_signup_under_13_sends_parent_email(self, mock_send_dotdigital_email: Mo

# Class for Selenium tests. We plan to replace these and turn them into Cypress tests
class TestIndependentStudentFrontend(BaseTest):
def test_delete_indy_account(self):
@patch("portal.views.registration.send_dotdigital_email")
def test_delete_indy_account(self, mock_send_dotdigital_email: Mock):
page = self.go_to_homepage()
page, _, _, email, password = create_independent_student(page)
page = page.independent_student_login(email, password)
Expand Down Expand Up @@ -214,7 +215,7 @@ def test_delete_indy_account(self):
assert not User.objects.get(id=user_id).is_active

# check if email has been sent
assert len(mail.outbox) == 1
mock_send_dotdigital_email.assert_called_once_with(campaign_ids["delete_account"], ANY)

def test_signup_without_newsletter(self):
page = self.go_to_homepage()
Expand Down
14 changes: 11 additions & 3 deletions portal/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,8 @@ def test_student_dashboard_view(self):
assert response.status_code == 200
assert response.context_data == EXPECTED_DATA_WITH_KURONO_GAME

def test_delete_account(self):
@patch("portal.views.registration.send_dotdigital_email")
def test_delete_account(self, mock_send_dotdigital_email: Mock):
email, password = signup_teacher_directly()
u = User.objects.get(email=email)
usrid = u.id
Expand All @@ -593,7 +594,7 @@ def test_delete_account(self):
response = c.post(url, {"password": "wrongPassword"})

assert response.status_code == 302
assert response.url == reverse("dashboard")
mock_send_dotdigital_email.assert_not_called()

# user has not been anonymised
u = User.objects.get(email=email)
Expand All @@ -604,14 +605,18 @@ def test_delete_account(self):
response = c.post(url, {"password": password, "unsubscribe_newsletter": "on"})

assert response.status_code == 302
mock_send_dotdigital_email.assert_called_once()
assert response.url == reverse("home")

# user has been anonymised
u = User.objects.get(id=usrid)
assert u.first_name == "Deleted"
assert not u.is_active

def test_delete_account_admin(self):
assert c.login(username=email, password=password) == False

@patch("portal.views.registration.send_dotdigital_email")
def test_delete_account_admin(self, mock_send_dotdigital_email: Mock):
"""test the passing of admin role after deletion of an admin account"""

email1, password1 = signup_teacher_directly()
Expand Down Expand Up @@ -666,6 +671,7 @@ def test_delete_account_admin(self):
# delete teacher1 account
url = reverse("delete_account")
c.post(url, {"password": password1})
mock_send_dotdigital_email.assert_called_once()

# user has been anonymised
u = User.objects.get(id=usrid1)
Expand Down Expand Up @@ -706,6 +712,7 @@ def test_delete_account_admin(self):
# now delete teacher3 account
url = reverse("delete_account")
c.post(url, {"password": password3})
self.assertEqual(mock_send_dotdigital_email.call_count, 2)

# 2 teachers left
teachers = Teacher.objects.filter(school=school).order_by("new_user__last_name", "new_user__first_name")
Expand Down Expand Up @@ -738,6 +745,7 @@ def test_delete_account_admin(self):

url = reverse("delete_account")
c.post(url, {"password": password2})
self.assertEqual(mock_send_dotdigital_email.call_count, 3)

# school should be anonymised
school = School._base_manager.get(id=school_id)
Expand Down
31 changes: 11 additions & 20 deletions portal/views/registration.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
import ast
import re

from common.email_messages import accountDeletionEmail
from portal.views.login import has_user_lockout_expired

from django.contrib.auth.models import User
from datetime import datetime

from common.helpers.emails import (
delete_contact,
NOTIFICATION_EMAIL,
PASSWORD_RESET_EMAIL,
delete_contact,
send_email,
)
from common.models import Teacher, Student, DailyActivity
from common.permissions import not_logged_in, not_fully_logged_in

from common.mail import campaign_ids, send_dotdigital_email
from common.models import DailyActivity, Student, Teacher
from common.permissions import not_fully_logged_in, not_logged_in
from django.contrib import messages as messages
from django.contrib.auth import get_user_model
from django.contrib.auth.decorators import user_passes_test, login_required
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.forms import PasswordResetForm, SetPasswordForm
from django.contrib.auth.models import User
from django.contrib.auth.tokens import default_token_generator
from django.http import HttpResponseRedirect
from django.shortcuts import render
Expand All @@ -35,14 +32,15 @@
from deploy import captcha
from portal import app_settings
from portal.forms.registration import (
TeacherPasswordResetForm,
TeacherPasswordResetSetPasswordForm,
StudentPasswordResetForm,
StudentPasswordResetSetPasswordForm,
TeacherPasswordResetForm,
TeacherPasswordResetSetPasswordForm,
)
from portal.helpers.captcha import remove_captcha_from_form
from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
from portal.views.api import anonymise
from portal.views.login import has_user_lockout_expired


@user_passes_test(not_logged_in, login_url=reverse_lazy("home"))
Expand Down Expand Up @@ -309,13 +307,6 @@ def delete_account(request):
delete_contact(email)

# send confirmation email
message = accountDeletionEmail(request)
send_email(
NOTIFICATION_EMAIL,
[email],
message["subject"],
message["message"],
message["title"],
)
send_dotdigital_email(campaign_ids["delete_account"], [email])

return HttpResponseRedirect(reverse_lazy("home"))
14 changes: 8 additions & 6 deletions portal/views/student/edit_account_details.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
from common.email_messages import accountDeletionEmail
from common.helpers.emails import NOTIFICATION_EMAIL, delete_contact, send_email, update_indy_email
from common.helpers.emails import (
NOTIFICATION_EMAIL,
delete_contact,
send_email,
update_indy_email,
)
from common.models import Student
from common.permissions import logged_in_as_student
from django.contrib import messages as messages
from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required, user_passes_test
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic.edit import FormView
from django.shortcuts import render

from portal.forms.play import StudentEditAccountForm, IndependentStudentEditAccountForm
from portal.forms.play import IndependentStudentEditAccountForm, StudentEditAccountForm
from portal.forms.registration import DeleteAccountForm

from portal.helpers.password import check_update_password
from portal.helpers.ratelimit import clear_ratelimit_cache_for_user
from portal.views.api import anonymise
from django.contrib import messages as messages


def _get_form(self, form_class):
Expand Down
Loading