Skip to content

Commit 424345b

Browse files
committed
Merge pull request #1051 from jfunez/1050_emails_editorialmanager
aprimorar envío de emails do editorialmanager #1050
2 parents 6c121c5 + edd0f37 commit 424345b

File tree

17 files changed

+833
-46
lines changed

17 files changed

+833
-46
lines changed

scielomanager/articletrack/notifications.py

+7-3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44

55
from scielomanager import notifications
6+
from scielomanager.tools import user_receive_emails
67

78

89
logger = logging.getLogger(__name__)
@@ -48,7 +49,7 @@ def set_recipients(self, checkin):
4849
and the submitter (checkin.submitted_by).
4950
"""
5051
if checkin.team_members:
51-
send_to = set([member.email for member in checkin.team_members])
52+
send_to = set([member.email for member in checkin.team_members if user_receive_emails(member)])
5253
# the submitter already belong to a related team
5354
self.recipients = list(send_to)
5455
else:
@@ -88,11 +89,14 @@ def set_recipients(self, ticket):
8889
and the submitter (checkin.submitted_by, already belong to a team) of each checkin,
8990
and the author to the ticket related.
9091
"""
91-
send_to = set([ticket.author.email, ])
92+
send_to = set()
93+
if user_receive_emails(ticket.author):
94+
send_to.update([unicode(ticket.author.email), ])
95+
9296
for checkin in ticket.article.checkins.all():
9397
# the submitter already belong to a related team
9498
if checkin.team_members:
95-
send_to.update([member.email for member in checkin.team_members])
99+
send_to.update([member.email for member in checkin.team_members if user_receive_emails(member)])
96100
else:
97101
logger.info("[TicketMessage.set_recipients] Can't prepare a message, checkin.team_members is empty. Checkin pk == %s" % checkin.pk)
98102
self.recipients = list(send_to)

scielomanager/articletrack/tests/tests_notifications.py

+60
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,36 @@ def test_each_action(self):
129129
for recipient in self.expected_recipients:
130130
self.assertIn(recipient, new_email.to)
131131

132+
@override_settings(CELERY_EAGER_PROPAGATES_EXCEPTIONS=True, CELERY_ALWAYS_EAGER=True, BROKER_BACKEND='memory')
133+
def test_each_action_with_disable_notifications_for_one_team_member(self):
134+
"""
135+
for each action, test notifications are sent, but for one team member will have disable notifications
136+
"""
137+
# disable email notifications for one team member (excludes submitter)
138+
non_exclusion_users_pk = [self.ticket.author.pk , self.submitter.pk, ]
139+
target_team_member_profile = self.team.member.all().exclude(pk__in=non_exclusion_users_pk)[0].get_profile()
140+
target_team_member_profile.email_notifications = False
141+
target_team_member_profile.save()
142+
143+
# update self.expected_recipients
144+
self.expected_recipients.remove(target_team_member_profile.user.email)
145+
146+
email_count = 0
147+
for action in self.ACTIONS:
148+
email_count += 1
149+
# when
150+
result = notifications.ticket_send_mail_by_action(ticket=self.ticket, action=action)
151+
# then
152+
expected_subject = self._make_subject(action)
153+
154+
self.assertTrue(result)
155+
self.assertEqual(len(mail.outbox), email_count)
156+
new_email = mail.outbox[-1]
157+
self.assertEqual(new_email.subject, expected_subject)
158+
self.assertEqual(len(self.expected_recipients), len(new_email.to))
159+
for recipient in self.expected_recipients:
160+
self.assertIn(recipient, new_email.to)
161+
132162

133163
class CommentMessageTests(TestCase):
134164
ACTIONS = [
@@ -184,3 +214,33 @@ def test_each_action(self):
184214
self.assertEqual(len(self.expected_recipients), len(new_email.to))
185215
for recipient in self.expected_recipients:
186216
self.assertIn(recipient, new_email.to)
217+
218+
@override_settings(CELERY_EAGER_PROPAGATES_EXCEPTIONS=True, CELERY_ALWAYS_EAGER=True, BROKER_BACKEND='memory')
219+
def test_each_action_with_disable_notifications_for_one_team_member(self):
220+
"""
221+
for each action, test notifications are sent, but for one team member will have disable notifications
222+
"""
223+
# disable email notifications for one team member (excludes submitter and author for no particular reason)
224+
non_exclusion_users_pk = [self.ticket.author.pk , self.submitter.pk, ]
225+
target_team_member_profile = self.team.member.all().exclude(pk__in=non_exclusion_users_pk)[0].get_profile()
226+
target_team_member_profile.email_notifications = False
227+
target_team_member_profile.save()
228+
229+
# update self.expected_recipients
230+
self.expected_recipients.remove(target_team_member_profile.user.email)
231+
232+
email_count = 0
233+
for action in self.ACTIONS:
234+
email_count += 1
235+
# when
236+
result = notifications.comment_send_mail_by_action(comment=self.comment, action=action)
237+
# then
238+
expected_subject = self._make_subject(action)
239+
240+
self.assertTrue(result)
241+
self.assertEqual(len(mail.outbox), email_count)
242+
new_email = mail.outbox[-1]
243+
self.assertEqual(new_email.subject, expected_subject)
244+
self.assertEqual(len(self.expected_recipients), len(new_email.to))
245+
for recipient in self.expected_recipients:
246+
self.assertIn(recipient, new_email.to)

scielomanager/editorialmanager/notifications.py

+30-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# coding: utf-8
22

33
import logging
4-
4+
from django.core.exceptions import ObjectDoesNotExist
5+
from scielomanager.tools import get_users_by_group_by_collections, user_receive_emails
56
from scielomanager import notifications
67

78

@@ -24,9 +25,12 @@ class IssueBoardMessage(notifications.Message):
2425
def set_recipients(self, issue):
2526
editor = getattr(issue.journal, 'editor', None)
2627
if editor:
27-
self.recipients = [editor.email, ]
28+
if user_receive_emails(editor):
29+
self.recipients = [editor.email, ]
30+
else:
31+
logger.info("[IssueBoardMessage.set_recipients] editor (user.pk: %s) does not have a profile or decides to not receive emails." % editor.pk)
2832
else:
29-
logger.info("[IssueBoardMessage.set_recipients] Can't prepare a message, issue.journal.editor is None or empty. Issue pk == %s" % issue.pk)
33+
logger.error("[IssueBoardMessage.set_recipients] Can't prepare a message, issue.journal.editor is None or empty. Issue pk == %s" % issue.pk)
3034

3135

3236
class BoardMembersMessage(notifications.Message):
@@ -46,14 +50,25 @@ class BoardMembersMessage(notifications.Message):
4650
}
4751
}
4852

49-
def set_recipients(self, member):
50-
from scielomanager.tools import get_users_by_group
51-
from django.core.exceptions import ObjectDoesNotExist
52-
try:
53-
librarians = get_users_by_group('Librarian')
54-
self.recipients = [user.email for user in librarians if user.email]
55-
except ObjectDoesNotExist:
56-
logger.info("[BoardMembersMessage.set_recipients] Can't prepare a message, Can't retrieve a list of Librarian Users.")
53+
def set_recipients(self):
54+
""" emails must be sent as BCC """
55+
self.recipients = []
56+
57+
def set_bcc_recipients(self, member):
58+
""" recipients must belong to the same collection as member """
59+
collections_of_board_member = member.board.issue.journal.collections.all()
60+
61+
if collections_of_board_member:
62+
librarians = get_users_by_group_by_collections('Librarian', collections_of_board_member)
63+
else:
64+
logger.error("[BoardMembersMessage.set_bcc_recipients] Can't define the collection of member (pk: %s), to filter bcc_recipients" % member.pk)
65+
return
66+
67+
if librarians:
68+
filtered_librarians = [librarian for librarian in librarians if user_receive_emails(librarian)]
69+
self.bcc_recipients = map(lambda u: u.email, filtered_librarians)
70+
else:
71+
logger.error("[BoardMembersMessage.set_bcc_recipients] Can't prepare a message, Can't retrieve a list of Librarian Users.")
5772

5873

5974
def issue_board_replica(issue, action):
@@ -64,14 +79,15 @@ def issue_board_replica(issue, action):
6479
return message.send_mail()
6580

6681

67-
def board_members_send_email_by_action(member, user, message, action):
82+
def board_members_send_email_by_action(member, user, audit_log_msg, action):
6883
message = BoardMembersMessage(action=action)
69-
message.set_recipients(member)
84+
message.set_recipients()
85+
message.set_bcc_recipients(member)
7086
extra_context = {
7187
'user': user,
7288
'member': member,
7389
'issue': member.board.issue,
74-
'message': message,
90+
'message': audit_log_msg,
7591
}
7692
message.render_body(extra_context)
7793
return message.send_mail()

scielomanager/editorialmanager/tests/tests_notifications.py

+70-6
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from django.test import TestCase
66
from django.test.utils import override_settings
77
from django_factory_boy import auth
8-
8+
from journalmanager import models as jmodels
99
from journalmanager.tests import modelfactories
1010
from editorialmanager import notifications
1111
from . import modelfactories as editorial_modelfactories
@@ -21,7 +21,7 @@ def setUp(self):
2121
self.editor = auth.UserF(is_active=True)
2222
self.journal = modelfactories.JournalFactory.create(editor=self.editor)
2323
self.issue = modelfactories.IssueFactory(journal=self.journal)
24-
self.expected_recipients = [self.editor, ]
24+
self.expected_recipients = [self.editor.email, ]
2525
self.expected_subject_sufix_by_action = {
2626
'issue_add_no_replicated_board': "Issue Board can't be replicated",
2727
'issue_add_replicated_board': "Issue has a new replicated board",
@@ -53,7 +53,27 @@ def test_each_action(self):
5353
self.assertEqual(new_email.subject, expected_subject)
5454
self.assertEqual(len(self.expected_recipients), len(new_email.to))
5555
for recipient in self.expected_recipients:
56-
self.assertIn(recipient.email, new_email.to)
56+
self.assertIn(recipient, new_email.to)
57+
58+
@override_settings(CELERY_EAGER_PROPAGATES_EXCEPTIONS=True, CELERY_ALWAYS_EAGER=True, BROKER_BACKEND='memory')
59+
def test_each_action_with_disable_notifications_for_editor(self):
60+
"""
61+
for each action, test notifications are sent, but editor will have disable notifications
62+
"""
63+
editor_profile = self.editor.get_profile()
64+
editor_profile.email_notifications = False
65+
editor_profile.save()
66+
# update self.expected_recipients
67+
self.expected_recipients.remove(editor_profile.user.email)
68+
69+
for action in self.ACTIONS:
70+
# with
71+
expected_subject = self._make_subject(action)
72+
# when
73+
result = notifications.issue_board_replica(issue=self.issue, action=action)
74+
# then
75+
# no mail sent, since the only recipient: editor, "choose" to not receive emails
76+
self.assertIsNone(result)
5777

5878

5979
class BoardMembersMessageTests(TestCase):
@@ -75,13 +95,22 @@ def setUp(self):
7595
self.librarian2.groups.add(self.librarian_group)
7696
self.librarian2.save()
7797

98+
self.collection = modelfactories.CollectionFactory.create()
7899
self.editor = auth.UserF(is_active=True)
79100
self.journal = modelfactories.JournalFactory.create(editor=self.editor)
80101
self.issue = modelfactories.IssueFactory(journal=self.journal)
81102
self.board = editorial_modelfactories.EditorialBoardFactory.create(issue=self.issue)
82103
self.member = editorial_modelfactories.EditorialMemberFactory.create(board=self.board)
83104

84-
self.expected_recipients = [self.librarian1, self.librarian2, ]
105+
# link journal to collection
106+
jmodels.Membership.objects.create(journal=self.journal, collection=self.collection, created_by=auth.UserF(is_active=True))
107+
108+
# link librarians and collection
109+
self.collection.add_user(self.librarian1)
110+
self.collection.add_user(self.librarian2)
111+
112+
self.expected_recipients = []
113+
self.expected_bcc_recipients = [self.librarian1.email, self.librarian2.email, ]
85114
self.expected_subject_sufix_by_action = {
86115
'board_add_member': "Member of the journal board, was added",
87116
'board_edit_member': "Member of the journal board, was edited",
@@ -99,7 +128,39 @@ def test_each_action(self):
99128
for action in self.ACTIONS:
100129
# with
101130
expected_subject = self._make_subject(action)
102-
message = ''
131+
message = 'Audit Log change message goes here!'
132+
email_count += 1
133+
# when
134+
result = notifications.board_members_send_email_by_action(self.member, self.editor, message, action)
135+
# then
136+
self.assertTrue(result)
137+
self.assertEqual(len(mail.outbox), email_count)
138+
new_email = mail.outbox[-1]
139+
self.assertEqual(new_email.subject, expected_subject)
140+
self.assertEqual(len(self.expected_recipients), len(new_email.to))
141+
self.assertEqual(len(self.expected_bcc_recipients), len(new_email.bcc))
142+
for recipient in self.expected_recipients:
143+
self.assertIn(recipient, new_email.to)
144+
for recipient in self.expected_bcc_recipients:
145+
self.assertIn(recipient, new_email.bcc)
146+
147+
148+
@override_settings(CELERY_EAGER_PROPAGATES_EXCEPTIONS=True, CELERY_ALWAYS_EAGER=True, BROKER_BACKEND='memory')
149+
def test_each_action_with_disable_notifications_for_one_librarian(self):
150+
"""
151+
for each action, test notifications are sent, but librarian2 will have disable notifications
152+
"""
153+
librarian2_profile = self.librarian2.get_profile()
154+
librarian2_profile.email_notifications = False
155+
librarian2_profile.save()
156+
# remove it from expected_bcc_recipients
157+
self.expected_bcc_recipients.remove(librarian2_profile.user.email)
158+
159+
email_count = 0
160+
for action in self.ACTIONS:
161+
# with
162+
expected_subject = self._make_subject(action)
163+
message = 'Audit Log change message goes here!'
103164
email_count += 1
104165
# when
105166
result = notifications.board_members_send_email_by_action(self.member, self.editor, message, action)
@@ -109,5 +170,8 @@ def test_each_action(self):
109170
new_email = mail.outbox[-1]
110171
self.assertEqual(new_email.subject, expected_subject)
111172
self.assertEqual(len(self.expected_recipients), len(new_email.to))
173+
self.assertEqual(len(self.expected_bcc_recipients), len(new_email.bcc))
112174
for recipient in self.expected_recipients:
113-
self.assertIn(recipient.email, new_email.to)
175+
self.assertIn(recipient, new_email.to)
176+
for recipient in self.expected_bcc_recipients:
177+
self.assertIn(recipient, new_email.bcc)

scielomanager/journalmanager/admin.py

+17
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from django.contrib import admin
33
from django.contrib.auth.models import User
44
from django.contrib.auth.admin import UserAdmin
5+
from django.contrib.admin.templatetags.admin_static import static
56
from tastypie.models import ApiAccess
67

78
from .models import *
@@ -91,6 +92,22 @@ def queryset(self, request):
9192

9293

9394
class UserAdmin(UserAdmin):
95+
def profile_email_notifications(self, user):
96+
"""
97+
display a green/red icon if user accepts or not email notifications.
98+
if for some reason, the user don't have a UserProfile, it returns a (?) icon.
99+
"""
100+
if user.get_profile():
101+
email_notifications = user.get_profile().email_notifications
102+
icon_url = static('admin/img/icon-%s.gif' % {True: 'yes', False: 'no', None: 'unknown'}[email_notifications])
103+
return '<img src="{0}" alt="{1}" />'.format(icon_url, email_notifications)
104+
else:
105+
icon_url = static('admin/img/icon-icon-unknown.gif')
106+
return '<img src="{0}" alt="NO PROFILE" />no profile!' % icon_url
107+
profile_email_notifications.short_description = 'Email Notifications'
108+
profile_email_notifications.allow_tags = True
109+
110+
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff', 'profile_email_notifications', )
94111
inlines = (UserProfileInline, UserCollectionsInline)
95112
form = UserChangeForm
96113
add_form = UserCreationForm

scielomanager/journalmanager/forms.py

+5
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,11 @@ def get_all_ahead_pressrelease_forms(post_dict, journal, pressrelease):
755755
return d
756756

757757

758+
class UserProfileForm(ModelForm):
759+
class Meta:
760+
model = models.UserProfile
761+
fields = ('email_notifications',)
762+
758763
class UserCollectionsForm(ModelForm):
759764
def __init__(self, *args, **kwargs):
760765
"""

0 commit comments

Comments
 (0)