Skip to content

Commit

Permalink
[change] Improved password expiration warning email #367
Browse files Browse the repository at this point in the history
Closes #367
  • Loading branch information
pandafy committed Feb 13, 2024
1 parent 7e93b75 commit cb225e0
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% load i18n %}

<p>{% blocktrans with expiry_date=expiry_date|date:"Y-m-d" %}We inform you that the password for your account {{ username }} will expire in 7 days, precisely on {{ expiry_date }}.{% endblocktrans %}<p>

<p>{% trans "Kindly proceed with updating your password by clicking on the button below." %}<p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% load i18n %}

{% blocktrans with expiry_date=expiry_date|date:"Y-m-d" %}We inform you that the password for your account {{ username }} will expire in 7 days, precisely on {{ expiry_date }}.{% endblocktrans %}

{% trans "Kindly proceed with updating your password by clicking on the button below." %}
23 changes: 20 additions & 3 deletions openwisp_users/tasks.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
from time import sleep

from celery import shared_task
from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import UNUSABLE_PASSWORD_PREFIX
from django.contrib.sites.models import Site
from django.db.models import Q
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.timezone import now, timedelta
from django.utils.translation import gettext_lazy as _
Expand Down Expand Up @@ -49,11 +52,18 @@ def password_expiration_email():
)
.filter(query)
)
email_counts = 0
for user in qs.iterator():
send_email(
subject=_('Your password is about to expire'),
body_text=_('Your password is about to expire in 7 days'),
body_html=_('You password is about to expire in 7 days.'),
subject=_('Action Required: Password Expiry Notice'),
body_text=render_to_string(
'account/email/password_expiration_message.txt',
context={'username': user.username, 'expiry_date': expiry_date},
).strip(),
body_html=render_to_string(
'account/email/password_expiration_message.html',
context={'username': user.username, 'expiry_date': expiry_date},
).strip(),
recipients=[user.email],
extra_context={
'call_to_action_url': 'https://{0}{1}'.format(
Expand All @@ -63,3 +73,10 @@ def password_expiration_email():
'call_to_action_text': _('Change password'),
},
)
# Avoid overloading the SMTP server by sending multiple
# emails continuously.
if email_counts > 10:
email_counts = 0
sleep(10)
else:
email_counts += 1
33 changes: 32 additions & 1 deletion openwisp_users/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,12 +428,43 @@ def test_password_expiration_mail(self):
password_updated=user_expiry_date
)
password_expiration_email.delay()
formatted_expiry_date = (now() + timedelta(days=7)).strftime('%Y-%m-%d')
self.assertEqual(len(mail.outbox), 1)
email = mail.outbox.pop()
self.assertEqual(email.to, [verified_email_user.email])
self.assertEqual(email.subject, 'Your password is about to expire')
self.assertEqual(email.subject, 'Action Required: Password Expiry Notice')
self.assertEqual(
email.body,
'We inform you that the password for your account tester will expire'
f' in 7 days, precisely on {formatted_expiry_date}.\n\n'
'Kindly proceed with updating your password by clicking on the'
' button below.',
)
self.assertIn(
'<p>We inform you that the password for your account tester will expire'
f' in 7 days, precisely on {formatted_expiry_date}.<p>\n\n<p>',
email.alternatives[0][0],
)
self.assertIn(
'Kindly proceed with updating your password by clicking on the button'
' below.<p>',
email.alternatives[0][0],
)
self.assertNotEqual(email.to, [unverified_email_user.email])

@patch.object(app_settings, 'USER_PASSWORD_EXPIRATION', 30)
@patch('openwisp_users.tasks.sleep')
def test_password_expiration_mail_sleep(self, mocked_sleep):
user_expiry_date = now().today() - timedelta(
days=(app_settings.USER_PASSWORD_EXPIRATION - 7)
)
for i in range(12):
self._create_user(username=f'user{i}', email=f'user{i}@example.com')
EmailAddress.objects.update(verified=True)
User.objects.update(password_updated=user_expiry_date)
password_expiration_email.delay()
mocked_sleep.assert_called_with(10)

@patch.object(app_settings, 'USER_PASSWORD_EXPIRATION', 0)
@patch.object(app_settings, 'STAFF_USER_PASSWORD_EXPIRATION', 0)
def test_password_expiration_mail_settings_disabled(self):
Expand Down

0 comments on commit cb225e0

Please sign in to comment.