diff --git a/physionet-django/notification/utility.py b/physionet-django/notification/utility.py index 4960b58e22..ceb641237b 100644 --- a/physionet-django/notification/utility.py +++ b/physionet-django/notification/utility.py @@ -1023,3 +1023,19 @@ def notify_event_participant_application(request, user, registered_user, event): body = loader.render_to_string('events/email/event_registration.html', context) # Not resend the email if there was an integrity error send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [user.email], fail_silently=False) + + +def notify_primary_email(associated_email): + """ + Inform a user of the primary email address linked to their account. + Must only be used when the email address is verified. + """ + if associated_email.is_verified: + subject = f"Primary email address on {settings.SITE_NAME}" + context = { + 'name': associated_email.user.get_full_name(), + 'primary_email': associated_email.user.email, + 'SITE_NAME': settings.SITE_NAME, + } + body = loader.render_to_string('user/email/notify_primary_email.html', context) + send_mail(subject, body, settings.DEFAULT_FROM_EMAIL, [associated_email.email], fail_silently=False) diff --git a/physionet-django/user/templates/user/email/notify_primary_email.html b/physionet-django/user/templates/user/email/notify_primary_email.html new file mode 100644 index 0000000000..d34907d84e --- /dev/null +++ b/physionet-django/user/templates/user/email/notify_primary_email.html @@ -0,0 +1,8 @@ +{% load i18n %}{% autoescape off %}{% filter wordwrap:70 %} +You are receiving this email because you requested a password reset for your account at {{ SITE_NAME }}. + +Only your primary email address can be used for resetting your password. Your primary email address is {{ primary_email }}. + +Regards +The {{ SITE_NAME }} Team +{% endfilter %}{% endautoescape %} diff --git a/physionet-django/user/views.py b/physionet-django/user/views.py index 05628b8699..509b18282b 100644 --- a/physionet-django/user/views.py +++ b/physionet-django/user/views.py @@ -9,6 +9,7 @@ from django.contrib import messages from django.contrib.auth import login from django.contrib.auth.decorators import login_required +from django.contrib.auth.forms import PasswordResetForm from django.contrib.auth.tokens import default_token_generator from django.contrib.sites.shortcuts import get_current_site from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, ValidationError @@ -29,6 +30,7 @@ credential_application_request, get_url_prefix, notify_account_registration, + notify_primary_email, process_credential_complete, training_application_request, ) @@ -95,13 +97,27 @@ class LogoutView(auth_views.LogoutView): pass +class CustomPasswordResetForm(PasswordResetForm): + def clean_email(self): + """ + Override the clean_email method to allow for secondary email checks. + """ + email = self.cleaned_data['email'] + secondary_email = AssociatedEmail.objects.filter(is_verified=True, is_primary_email=False, email=email).first() + + if secondary_email: + notify_primary_email(secondary_email) + + return email + + # Request password reset class PasswordResetView(auth_views.PasswordResetView): template_name = 'user/reset_password_request.html' success_url = reverse_lazy('reset_password_sent') email_template_name = 'user/email/reset_password_email.html' extra_email_context = {'SITE_NAME': settings.SITE_NAME} - + form_class = CustomPasswordResetForm # Page shown after reset email has been sent class PasswordResetDoneView(auth_views.PasswordResetDoneView):