Skip to content

Commit de53f1c

Browse files
authored
Merge pull request #138 from adamspd/137-send-email-to-staff-admin-when-a-profile-is-created-for-him-to-set-password
Send email to staff member upon account creation
2 parents d331bef + 3bcf55e commit de53f1c

File tree

7 files changed

+114
-10
lines changed

7 files changed

+114
-10
lines changed

appointment/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@
55
__package_name__ = "django-appointment"
66
__url__ = "https://github.com/adamspd/django-appointment"
77
__package_website__ = "https://django-appt.adamspierredavid.com/"
8-
__version__ = "3.3.4"
8+
__version__ = "3.3.5"
99
__test_version__ = False

appointment/services.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
get_staff_member_from_user_id_or_logged_in, get_times_from_config, get_user_by_email,
3030
get_weekday_num_from_date, get_working_hours_for_staff_and_day, parse_name, update_appointment_reminder,
3131
working_hours_exist)
32+
from appointment.utils.email_ops import send_reset_link_to_staff_member
3233
from appointment.utils.error_codes import ErrorCode
3334
from appointment.utils.json_context import convert_appointment_to_json, get_generic_context, json_response
3435
from appointment.utils.permissions import check_entity_ownership
@@ -513,7 +514,7 @@ def email_change_verification_service(code, email, old_email):
513514
return False
514515

515516

516-
def create_staff_member_service(post_data):
517+
def create_staff_member_service(post_data, request):
517518
form = PersonalInformationForm(post_data)
518519
if form.is_valid():
519520
first_name = form.cleaned_data['first_name']
@@ -533,6 +534,7 @@ def create_staff_member_service(post_data):
533534
if not user.is_superuser:
534535
user.is_staff = True
535536
user.save()
537+
send_reset_link_to_staff_member(user, request, user.email)
536538
return user, True, None
537539
else:
538540
return None, False, get_error_message_in_form(form=form)

appointment/templates/appointment/thank_you.html

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
{% load static %}
44
{% block customCSS %}
55
<style>
6-
/* Add your custom CSS here */
76
body {
87
font-family: 'Nunito', sans-serif;
98
background-color: #f7f7f7;

appointment/tests/test_services.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import datetime
55
import json
66
from _decimal import Decimal
7+
from unittest.mock import patch
78

89
from django.core.cache import cache
910
from django.test import Client
@@ -589,6 +590,10 @@ class CreateStaffMemberServiceTest(BaseTest):
589590

590591
def setUp(self):
591592
super().setUp()
593+
self.factory = RequestFactory()
594+
595+
# Setup request object
596+
self.request = self.factory.post('/')
592597

593598
def test_valid_data(self):
594599
"""Test if a staff member can be created with valid data."""
@@ -597,7 +602,7 @@ def test_valid_data(self):
597602
'last_name': 'Doe',
598603
'email': '[email protected]'
599604
}
600-
user, success, error_message = create_staff_member_service(post_data)
605+
user, success, error_message = create_staff_member_service(post_data, self.request)
601606

602607
self.assertTrue(success)
603608
self.assertIsNotNone(user)
@@ -613,7 +618,7 @@ def test_invalid_data(self):
613618
'last_name': 'Doe',
614619
'email': '[email protected]'
615620
}
616-
user, success, error_message = create_staff_member_service(post_data)
621+
user, success, error_message = create_staff_member_service(post_data, self.request)
617622

618623
self.assertFalse(success)
619624
self.assertIsNone(user)
@@ -627,12 +632,27 @@ def test_email_already_exists(self):
627632
'last_name': 'Doe',
628633
'email': '[email protected]' # Using an email that already exists
629634
}
630-
user, success, error_message = create_staff_member_service(post_data)
635+
user, success, error_message = create_staff_member_service(post_data, self.request)
631636

632637
self.assertFalse(success)
633638
self.assertIsNone(user)
634639
self.assertEqual(error_message, "email: This email is already taken.")
635640

641+
@patch('appointment.services.send_reset_link_to_staff_member')
642+
def test_send_reset_link_to_new_staff_member(self, mock_send_reset_link):
643+
"""Test if a reset password link is sent to a new staff member."""
644+
post_data = {
645+
'first_name': 'Jane',
646+
'last_name': 'Smith',
647+
'email': '[email protected]'
648+
}
649+
user, success, _ = create_staff_member_service(post_data, self.request)
650+
self.assertTrue(success)
651+
self.assertIsNotNone(user)
652+
653+
# Check that the mock_send_reset_link function was called once
654+
mock_send_reset_link.assert_called_once_with(user, self.request, user.email)
655+
636656

637657
class HandleServiceManagementRequestTest(BaseTest):
638658

appointment/tests/utils/test_email_ops.py

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from unittest import mock
22
from unittest.mock import MagicMock, patch
33

4-
from django.test import TestCase
54
from django.test.client import RequestFactory
65
from django.utils import timezone
76
from django.utils.translation import gettext as _
@@ -10,12 +9,48 @@
109
from appointment.models import AppointmentRescheduleHistory
1110
from appointment.tests.base.base_test import BaseTest
1211
from appointment.utils.email_ops import (
13-
get_thank_you_message, notify_admin_about_appointment, send_reschedule_confirmation_email, send_thank_you_email,
12+
get_thank_you_message, notify_admin_about_appointment, send_reschedule_confirmation_email,
13+
send_reset_link_to_staff_member, send_thank_you_email,
1414
send_verification_email
1515
)
1616

1717

18-
class GetThankYouMessageTests(TestCase):
18+
class SendResetLinkToStaffMemberTests(BaseTest):
19+
20+
def setUp(self):
21+
super().setUp()
22+
self.user = self.user1
23+
self.user.is_staff = True
24+
self.user.save()
25+
self.factory = RequestFactory()
26+
self.request = self.factory.get('/')
27+
self.email = '[email protected]'
28+
29+
@mock.patch('appointment.utils.email_ops.send_email')
30+
@mock.patch('appointment.models.PasswordResetToken.create_token')
31+
def test_send_reset_link(self, mock_create_token, mock_send_email):
32+
# Setup the token
33+
mock_token = mock.Mock()
34+
mock_token.token = 'token123'
35+
mock_create_token.return_value = mock_token
36+
37+
# Assume get_absolute_url_ and get_website_name are utility functions you've defined somewhere
38+
with mock.patch('appointment.utils.email_ops.get_absolute_url_') as mock_get_absolute_url:
39+
with mock.patch('appointment.utils.email_ops.get_website_name') as mock_get_website_name:
40+
mock_get_absolute_url.return_value = 'http://testserver/reset_password'
41+
mock_get_website_name.return_value = 'TestCompany'
42+
43+
send_reset_link_to_staff_member(self.user, self.request, self.email)
44+
45+
# Check send_email was called with correct parameters
46+
mock_send_email.assert_called_once()
47+
args, kwargs = mock_send_email.call_args
48+
self.assertEqual(kwargs['recipient_list'], [self.email])
49+
self.assertIn('TestCompany', kwargs['message'])
50+
self.assertIn('http://testserver/reset_password', kwargs['message'])
51+
52+
53+
class GetThankYouMessageTests(BaseTest):
1954
def test_thank_you_no_payment(self):
2055
with patch('appointment.utils.email_ops.APPOINTMENT_PAYMENT_URL', None):
2156
ar = MagicMock()

appointment/utils/email_ops.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,54 @@ def send_thank_you_email(ar: AppointmentRequest, user, request, email: str, appo
8888
)
8989

9090

91+
def send_reset_link_to_staff_member(user, request, email: str, account_details=None):
92+
"""Email the staff member to set a password.
93+
94+
:param user: The user who booked the appointment.
95+
:param email: The email address of the client.
96+
:param account_details: Additional details about the account (default None).
97+
:param request: The request object.
98+
:return: None
99+
"""
100+
# Month and year like "J A N 2 0 2 1"
101+
token = PasswordResetToken.create_token(user=user, expiration_minutes=10080) # 7 days expiration
102+
ui_db64 = urlsafe_base64_encode(force_bytes(user.pk))
103+
relative_set_passwd_link = reverse('appointment:set_passwd', args=[ui_db64, token.token])
104+
set_passwd_link = get_absolute_url_(relative_set_passwd_link, request=request)
105+
106+
message = _("""
107+
Hello {first_name},
108+
109+
A request has been received to set a password for your staff account for the year {current_year} at {company}.
110+
111+
Please click the link below to set up your new password:
112+
{activation_link}
113+
114+
To login, if ask for a username, use '{username}', otherwise use your email address.
115+
116+
If you did not request this, please ignore this email.
117+
118+
{account_details}
119+
120+
Regards,
121+
{company}
122+
""").format(
123+
first_name=user.first_name,
124+
current_year=datetime.datetime.now().year,
125+
company=get_website_name(),
126+
activation_link=set_passwd_link,
127+
account_details=account_details if account_details else _("No additional details provided."),
128+
username=user.username
129+
)
130+
131+
# Assuming send_email is a method you have that sends an email
132+
send_email(
133+
recipient_list=[email],
134+
subject=_("Set Your Password for {company}").format(company=get_website_name()),
135+
message=message,
136+
)
137+
138+
91139
def notify_admin_about_appointment(appointment, client_name: str):
92140
"""Notify the admin and the staff member about a new appointment request."""
93141
email_context = {

appointment/views_admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ def email_change_verification_code(request):
379379
@require_superuser
380380
def create_new_staff_member(request):
381381
if request.method == 'POST':
382-
user, is_valid, error_message = create_staff_member_service(request.POST)
382+
user, is_valid, error_message = create_staff_member_service(request.POST, request)
383383
if is_valid:
384384
return redirect('appointment:user_profile', staff_user_id=user.pk)
385385
else:

0 commit comments

Comments
 (0)