From 12be1aa7b111e0af186646869c4086e6c41cac8e Mon Sep 17 00:00:00 2001 From: Patrick Samson Date: Sun, 15 Jan 2012 19:16:50 +0100 Subject: [PATCH] Added the setting POSTMAN_DISABLE_USER_EMAILING ; No need for an immediate rejection notification for a User --- docs/conf.py | 4 ++-- docs/notification.rst | 3 +++ docs/quickstart.rst | 8 +++++++ postman/__init__.py | 2 +- postman/admin.py | 2 +- postman/models.py | 7 ++++-- postman/tests.py | 53 +++++++++++++++++++++++++++++++------------ postman/utils.py | 12 +++++----- 8 files changed, 64 insertions(+), 27 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 4a9c0eb..11ce129 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,9 +45,9 @@ copyright = u'2010, Patrick Samson' # built documents. # # The short X.Y version. -version = '1.0' +version = '1.1' # The full version, including alpha/beta/rc tags. -release = '1.0' +release = '1.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/notification.rst b/docs/notification.rst index ec0de66..5be2980 100644 --- a/docs/notification.rst +++ b/docs/notification.rst @@ -26,6 +26,9 @@ and design yours. For users --------- +Special case: In case of a rejection by the auto moderation feature, the user is immediately aware of it, +so there is no need for a notification in addition. + If a notifier application is configured (see :ref:`optional_settings`), the following labels are used: * ``postman_rejection`` to notify the sender of the rejection diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 9653a93..2d9ba34 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -71,6 +71,13 @@ You may specify some additional configuration options in your :file:`settings.py Set it to True if you do not allow additional recipients when replying. *Defaults to*: False. + +``POSTMAN_DISABLE_USER_EMAILING`` + Set it to True if you do not want basic email notification to users. + This setting does not apply to visitors (refer to ``POSTMAN_DISALLOW_ANONYMOUS``), + nor to a notifier application (refer to ``POSTMAN_NOTIFIER_APP``) + + *Defaults to*: False. ``POSTMAN_AUTO_MODERATE_AS`` The default moderation status when no auto-moderation functions, if any, were decisive. @@ -190,6 +197,7 @@ Examples # POSTMAN_DISALLOW_ANONYMOUS = True # default is False # POSTMAN_DISALLOW_MULTIRECIPIENTS = True # default is False # POSTMAN_DISALLOW_COPIES_ON_REPLY = True # default is False + # POSTMAN_DISABLE_USER_EMAILING = True # default is False # POSTMAN_AUTO_MODERATE_AS = True # default is None # POSTMAN_NOTIFIER_APP = None # default is 'notification' # POSTMAN_MAILER_APP = None # default is 'mailer' diff --git a/postman/__init__.py b/postman/__init__.py index 1b706de..06d9f56 100644 --- a/postman/__init__.py +++ b/postman/__init__.py @@ -1,7 +1,7 @@ """A messaging application for Django""" # following PEP 386: N.N[.N]+[{a|b|c|rc}N[.N]+][.postN][.devN] -VERSION = (1, 0, 1) +VERSION = (1, 1, 0) PREREL = () POST = 0 DEV = 0 diff --git a/postman/admin.py b/postman/admin.py index d1286be..a904769 100644 --- a/postman/admin.py +++ b/postman/admin.py @@ -130,7 +130,7 @@ class MessageAdmin(admin.ModelAdmin): obj.clean_for_visitor() super(MessageAdmin, self).save_model(request, obj, form, change) obj.update_parent(form.initial_status) - obj.notify_users(form.initial_status) + obj.notify_users(form.initial_status, is_auto_moderated=False) class PendingMessageAdminForm(forms.ModelForm): class Meta: diff --git a/postman/models.py b/postman/models.py index d3d5af6..7170178 100644 --- a/postman/models.py +++ b/postman/models.py @@ -389,11 +389,14 @@ class Message(models.Model): parent.replied_at = None parent.save() - def notify_users(self, initial_status): + def notify_users(self, initial_status, is_auto_moderated=True): """Notify the rejection (to sender) or the acceptance (to recipient) of the message.""" if initial_status == STATUS_PENDING: if self.is_rejected(): - (notify_user if self.sender_id else email_visitor)(self, 'rejection') + # Bypass: for an online user, no need to notify when rejection is immediate. + # Only useful for a visitor as an archive copy of the message, otherwise lost. + if not (self.sender_id and is_auto_moderated): + (notify_user if self.sender_id else email_visitor)(self, 'rejection') elif self.is_accepted(): (notify_user if self.recipient_id else email_visitor)(self, 'acceptance') diff --git a/postman/tests.py b/postman/tests.py index 683af08..40c4d4d 100644 --- a/postman/tests.py +++ b/postman/tests.py @@ -52,7 +52,8 @@ from postman.fields import CommaSeparatedUserField from postman.models import ORDER_BY_KEY, ORDER_BY_MAPPER, Message, PendingMessage,\ STATUS_PENDING, STATUS_ACCEPTED, STATUS_REJECTED from postman.urls import OPTION_MESSAGES -from postman.utils import format_body, format_subject, notification +# because of reload()'s, do "from postman.utils import notification" just before needs +from postman.utils import format_body, format_subject if not 'pagination' in settings.INSTALLED_APPS: try: @@ -69,7 +70,7 @@ class GenericTest(TestCase): Usual generic tests. """ def test_version(self): - self.assertEqual(sys.modules['postman'].__version__, "1.0.1") + self.assertEqual(sys.modules['postman'].__version__, "1.1.0") class BaseTest(TestCase): """ @@ -83,11 +84,11 @@ class BaseTest(TestCase): 'POSTMAN_DISALLOW_ANONYMOUS', 'POSTMAN_DISALLOW_MULTIRECIPIENTS', 'POSTMAN_DISALLOW_COPIES_ON_REPLY', + 'POSTMAN_DISABLE_USER_EMAILING', 'POSTMAN_AUTO_MODERATE_AS', ): if hasattr(settings, a): delattr(settings, a) - settings.POSTMAN_NOTIFIER_APP = None settings.POSTMAN_MAILER_APP = None settings.POSTMAN_AUTOCOMPLETER_APP = { 'arg_default': 'postman_single', # no default, mandatory to enable the feature @@ -171,6 +172,7 @@ class BaseTest(TestCase): "Reload some modules after a change in settings." clear_url_caches() try: + reload(sys.modules['postman.utils']) reload(sys.modules['postman.forms']) reload(sys.modules['postman.views']) reload(sys.modules['postman.urls']) @@ -449,7 +451,6 @@ class ViewTest(BaseTest): url = reverse('postman_reply_auto_complete', args=[pk]) self.assert_(self.client.login(username='foo', password='pass')) response = self.client.get(url) - # print response.context f = response.context['form'].fields['recipients'] if hasattr(f, 'channel'): self.assertEqual(f.channel, 'postman_multiple') @@ -1269,50 +1270,72 @@ class MessageTest(BaseTest): # note: accepted -> pending, with no other suitable reply # is covered in the accepted -> rejected case - def check_notification(self, m, mail_number, email=None, notice_label=None): + def check_notification(self, m, mail_number, email=None, is_auto_moderated=True, notice_label=None): "Check number of mails, recipient, and notice creation." - m.notify_users(STATUS_PENDING) + m.notify_users(STATUS_PENDING, is_auto_moderated) self.assertEqual(len(mail.outbox), mail_number) if mail_number: self.assertEqual(mail.outbox[0].to, [email]) + from utils import notification if notification and notice_label: notice = notification.Notice.objects.get() self.assertEqual(notice.notice_type.label, notice_label) def test_notification_rejection_visitor(self): - "Test notify_users() for rejection, from a visitor." + "Test notify_users() for rejection, sender is a visitor." m = Message.objects.create(subject='s', moderation_status=STATUS_REJECTED, email=self.email, recipient=self.user2) self.check_notification(m, 1, self.email) def test_notification_rejection_user(self): - "Test notify_users() for rejection, from a User." + "Test notify_users() for rejection, sender is a User." + m = Message.objects.create(subject='s', moderation_status=STATUS_REJECTED, sender = self.user1, recipient=self.user2) + self.check_notification(m, 1, self.user1.email, is_auto_moderated=False, notice_label='postman_rejection') + + def test_notification_rejection_user_auto_moderated(self): + "Test notify_users() for rejection, sender is a User, and is alerted online." m = Message.objects.create(subject='s', moderation_status=STATUS_REJECTED, sender = self.user1, recipient=self.user2) - self.check_notification(m, 1, self.user1.email, notice_label='postman_rejection') + self.check_notification(m, 0, is_auto_moderated=True) def test_notification_rejection_user_inactive(self): - "Test notify_users() for rejection, from a User, but must be active." + "Test notify_users() for rejection, sender is a User, but must be active." m = Message.objects.create(subject='s', moderation_status=STATUS_REJECTED, sender = self.user1, recipient=self.user2) self.user1.is_active = False - self.check_notification(m, 0, notice_label='postman_rejection') + self.check_notification(m, 0, is_auto_moderated=False, notice_label='postman_rejection') + + def test_notification_rejection_user_disable(self): + "Test notify_users() for rejection, sender is a User, but emailing is disabled." + m = Message.objects.create(subject='s', moderation_status=STATUS_REJECTED, sender = self.user1, recipient=self.user2) + settings.POSTMAN_DISABLE_USER_EMAILING = True + settings.POSTMAN_NOTIFIER_APP = None + self.reload_modules() + self.check_notification(m, 0, is_auto_moderated=False) def test_notification_acceptance_visitor(self): - "Test notify_users() for acceptance, to a visitor." + "Test notify_users() for acceptance, recipient is a visitor." m = Message.objects.create(subject='s', moderation_status=STATUS_ACCEPTED, sender=self.user1, email=self.email) self.check_notification(m, 1, self.email) def test_notification_acceptance_user(self): - "Test notify_users() for acceptance, to a User." + "Test notify_users() for acceptance, recipient is a User." m = Message.objects.create(subject='s', moderation_status=STATUS_ACCEPTED, sender=self.user1, recipient = self.user2) self.check_notification(m, 1, self.user2.email, notice_label='postman_message') def test_notification_acceptance_user_inactive(self): - "Test notify_users() for acceptance, to a User, but must be active." + "Test notify_users() for acceptance, recipient is a User, but must be active." m = Message.objects.create(subject='s', moderation_status=STATUS_ACCEPTED, sender=self.user1, recipient = self.user2) self.user2.is_active = False self.check_notification(m, 0, notice_label='postman_message') + def test_notification_acceptance_user_disable(self): + "Test notify_users() for acceptance, recipient is a User, but emailing is disabled." + m = Message.objects.create(subject='s', moderation_status=STATUS_ACCEPTED, sender=self.user1, recipient = self.user2) + settings.POSTMAN_DISABLE_USER_EMAILING = True + settings.POSTMAN_NOTIFIER_APP = None + self.reload_modules() + self.check_notification(m, 0, notice_label='postman_message') + def test_notification_acceptance_reply(self): - "Test notify_users() for acceptance, for a reply, to a User." + "Test notify_users() for acceptance, for a reply, recipient is a User." p = Message.objects.create(subject='s', moderation_status=STATUS_ACCEPTED, sender=self.user2, recipient=self.user1) m = Message.objects.create(subject='s', moderation_status=STATUS_ACCEPTED, sender=self.user1, recipient=self.user2, parent=p, thread=p) diff --git a/postman/utils.py b/postman/utils.py index d148e61..b12cbe5 100644 --- a/postman/utils.py +++ b/postman/utils.py @@ -26,6 +26,9 @@ if name and name in settings.INSTALLED_APPS: else: from django.core.mail import send_mail +# to disable email notification to users +DISABLE_USER_EMAILING = getattr(settings, 'POSTMAN_DISABLE_USER_EMAILING', False) + # default wrap width; referenced in forms.py WRAP_WIDTH = 55 @@ -66,11 +69,8 @@ def email(subject_template, message_template, recipient_list, object, action=Non # Email subject *must not* contain newlines subject = ''.join(subject.splitlines()) message = render_to_string(message_template, ctx_dict) - if settings.DEBUG and getattr(settings, 'DEV_DEBUG', False): - print "email from:", settings.DEFAULT_FROM_EMAIL, " - to:", recipient_list, " - subject:", subject - print message - else: - send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True) + # during the development phase, consider using the setting: EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' + send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True) def email_visitor(object, action): """Email a visitor.""" @@ -90,5 +90,5 @@ def notify_user(object, action): if notification: notification.send(users=[user], label=label, extra_context={'message': object, 'action': action}) else: - if user.email and user.is_active: + if not DISABLE_USER_EMAILING and user.email and user.is_active: email('postman/email_user_subject.txt', 'postman/email_user.txt', [user.email], object, action) -- 2.39.5