]> git.parisson.com Git - django-postman.git/commitdiff
Fixed issue #35, the app can work without the sites framework
authorPatrick Samson <pk.samson@gmail.com>
Sat, 14 Sep 2013 12:12:18 +0000 (14:12 +0200)
committerPatrick Samson <pk.samson@gmail.com>
Sat, 14 Sep 2013 12:12:18 +0000 (14:12 +0200)
docs/notification.rst
postman/admin.py
postman/api.py
postman/forms.py
postman/models.py
postman/tests.py
postman/utils.py
postman/views.py

index 76f68d3c01f85406f358bb43cfb13699c65c364c..84e752cf1cf8b63c12b1a755d273a5cdcdfdd77d 100644 (file)
@@ -17,7 +17,8 @@ An email is sent, using these templates:
 \r
 The available context variables are:\r
 \r
-* ``site``: the Site instance\r
+* ``site``: the *Site* instance if the "sites" framework is installed, otherwise a *RequestSite* instance\r
+  with a fallback to *None* in the case of the API\r
 * ``object``: the Message instance\r
 * ``action``: 'rejection' or 'acceptance'\r
 \r
index aaf2f381a299408969c15733c17c73422cb19874..3e1c954573bb388ce73b01aad183f3605d28ac5e 100644 (file)
@@ -2,6 +2,7 @@ from __future__ import unicode_literals
 
 from django import forms
 from django.contrib import admin
+from django.contrib.sites.models import get_current_site
 from django.db import transaction
 from django.utils.translation import ugettext, ugettext_lazy as _
 
@@ -134,7 +135,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, is_auto_moderated=False)
+        obj.notify_users(form.initial_status, get_current_site(request), is_auto_moderated=False)
 
 
 class PendingMessageAdminForm(forms.ModelForm):
index f9f53f591c7559f5646c6dd401124216140e85e3..ad337b112edbe1dc38baf5e584ad24e62a81951b 100644 (file)
@@ -18,6 +18,7 @@ for e in events:
 """
 from __future__ import unicode_literals
 
+from django.contrib.sites.models import Site
 try:
     from django.utils.timezone import now  # Django 1.4 aware datetimes
 except ImportError:
@@ -26,6 +27,12 @@ except ImportError:
 
 from postman.models import Message, STATUS_PENDING, STATUS_ACCEPTED
 
+
+def _get_site():
+    # do not require the sites framework to be installed ; and no request object is available here
+    return Site.objects.get_current() if Site._meta.installed else None
+
+
 def pm_broadcast(sender, recipients, subject, body='', skip_notification=False):
     """
     Broadcast a message to multiple Users.
@@ -47,7 +54,8 @@ def pm_broadcast(sender, recipients, subject, body='', skip_notification=False):
         message.pk = None
         message.save()
         if not skip_notification:
-            message.notify_users(STATUS_PENDING)
+            message.notify_users(STATUS_PENDING, _get_site())
+
 
 def pm_write(sender, recipient, subject, body='', skip_notification=False,
         auto_archive=False, auto_delete=False, auto_moderators=None):
@@ -77,4 +85,4 @@ def pm_write(sender, recipient, subject, body='', skip_notification=False,
         message.sender_deleted_at = now()
     message.save()
     if not skip_notification:
-        message.notify_users(initial_status)
+        message.notify_users(initial_status, _get_site())
index b0ca4d1f22ccc831b6350eaf781c3af874c19d2e..126b26a8b9d0870af25e2162124657a7fb5a3554 100644 (file)
@@ -48,6 +48,7 @@ class BaseWriteForm(forms.ModelForm):
         user_filter = kwargs.pop('user_filter', None)
         max = kwargs.pop('max', None)
         channel = kwargs.pop('channel', None)
+        self.site = kwargs.pop('site', None)
         super(BaseWriteForm, self).__init__(*args, **kwargs)
 
         self.instance.sender = sender if (sender and sender.is_authenticated()) else None
@@ -141,7 +142,7 @@ class BaseWriteForm(forms.ModelForm):
             if self.instance.is_rejected():
                 is_successful = False
             self.instance.update_parent(initial_status)
-            self.instance.notify_users(initial_status)
+            self.instance.notify_users(initial_status, self.site)
             # some resets for next reuse
             if not isinstance(r, get_user_model()):
                 self.instance.email = ''
index 51627670689f5dfe5f3f533832854e5b8f97b027..1cb34c072c55479851e5d54eea643f5832765b9c 100644 (file)
@@ -419,16 +419,16 @@ class Message(models.Model):
                         parent.replied_at = None
                     parent.save()
 
-    def notify_users(self, initial_status, is_auto_moderated=True):
+    def notify_users(self, initial_status, site, 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():
                 # 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')
+                    (notify_user if self.sender_id else email_visitor)(self, 'rejection', site)
             elif self.is_accepted():
-                (notify_user if self.recipient_id else email_visitor)(self, 'acceptance')
+                (notify_user if self.recipient_id else email_visitor)(self, 'acceptance', site)
 
     def get_dates(self):
         """Get some dates to restore later."""
index 6adb666217a7a6f01b531d2f43d6abc3c253ed12..fad8cc989a3072dcbeda3210777a929744463de2 100644 (file)
@@ -7,7 +7,7 @@ Test suite.
     base.html
     404.html
 
-To have a fast test session, you can set a minimal configuration as:
+To have a fast test session, set a minimal configuration as:
 DATABASES = {
     'default': {
         'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
@@ -22,11 +22,11 @@ INSTALLED_APPS = (
     'django.contrib.auth',
     'django.contrib.contenttypes',
     'django.contrib.sessions',
-    'django.contrib.sites',
+    # 'django.contrib.sites',  # is optional
     'django.contrib.admin',
-    # 'pagination', # or use the mock
-    # 'ajax_select', # is an option
-    # 'notification', # is an option
+    # 'pagination',  # or use the mock
+    # 'ajax_select',  # is an option
+    # 'notification',  # is an option
     'postman',
 )
 
@@ -44,6 +44,7 @@ try:
 except ImportError:
     from postman.future_1_5 import get_user_model
 from django.contrib.auth.models import AnonymousUser
+from django.contrib.sites.models import Site
 from django.core import mail
 from django.core.exceptions import ValidationError
 from django.core.urlresolvers import reverse, clear_url_caches, get_resolver, get_urlconf
@@ -429,6 +430,23 @@ class ViewTest(BaseTest):
         self.check_status(Message.objects.get(), status=STATUS_REJECTED, recipient_deleted_at=True,
             moderation_date=True, moderation_reason="some reason")
 
+    def test_write_notification(self):
+        "Test the fallback for the site name in the generation of a notification, when the django.contrib.sites app is not installed."
+        settings.POSTMAN_AUTO_MODERATE_AS = True  # will generate an acceptance notification
+        url = reverse('postman_write')
+        data = {'subject': 's', 'body': 'b', 'recipients': self.user2.get_username()}
+        self.assertTrue(self.client.login(username='foo', password='pass'))
+        response = self.client.post(url, data, HTTP_REFERER=url)
+        self.assertRedirects(response, url)
+        self.check_status(Message.objects.get(), status=STATUS_ACCEPTED, moderation_date=True)
+        self.assertEqual(len(mail.outbox), 1)
+        # can't use get_current_site(response.request) because response.request is not an HttpRequest and doesn't have a get_host attribute
+        if Site._meta.installed:
+            sitename = Site.objects.get_current().name
+        else:
+            sitename = "testserver"  # the SERVER_NAME environment variable is not accessible here
+        self.assertTrue(sitename in mail.outbox[0].subject)
+
     def test_reply_authentication(self):
         "Test permission and what template & form are used."
         template = "postman/reply.html"
@@ -1303,7 +1321,7 @@ class MessageTest(BaseTest):
 
     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, is_auto_moderated)
+        m.notify_users(STATUS_PENDING, Site.objects.get_current() if Site._meta.installed else None, is_auto_moderated)
         self.assertEqual(len(mail.outbox), mail_number)
         if mail_number:
             self.assertEqual(mail.outbox[0].to, [email])
index f7d5d7c052b63cc65b4a1fa1d36902ee2bc4174d..64dbacf825112621d214c553acd78f09c8d3c947 100644 (file)
@@ -4,7 +4,6 @@ import sys
 from textwrap import TextWrapper
 
 from django.conf import settings
-from django.contrib.sites.models import Site
 from django.template.loader import render_to_string
 from django.utils.encoding import force_unicode
 from django.utils.translation import ugettext, ugettext_lazy as _
@@ -65,9 +64,8 @@ def format_subject(subject):
     return subject if re.match(pattern, subject, re.IGNORECASE) else str.format(subject=subject)
 
 
-def email(subject_template, message_template, recipient_list, object, action=None):
+def email(subject_template, message_template, recipient_list, object, action, site):
     """Compose and send an email."""
-    site = Site.objects.get_current()
     ctx_dict = {'site': site, 'object': object, 'action': action}
     subject = render_to_string(subject_template, ctx_dict)
     # Email subject *must not* contain newlines
@@ -77,12 +75,12 @@ def email(subject_template, message_template, recipient_list, object, action=Non
     send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list, fail_silently=True)
 
 
-def email_visitor(object, action):
+def email_visitor(object, action, site):
     """Email a visitor."""
-    email('postman/email_visitor_subject.txt', 'postman/email_visitor.txt', [object.email], object, action)
+    email('postman/email_visitor_subject.txt', 'postman/email_visitor.txt', [object.email], object, action, site)
 
 
-def notify_user(object, action):
+def notify_user(object, action, site):
     """Notify a user."""
     if action == 'rejection':
         user = object.sender
@@ -98,4 +96,4 @@ def notify_user(object, action):
         notification.send(users=[user], label=label, extra_context={'pm_message': object, 'pm_action': action})
     else:
         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)
+            email('postman/email_user_subject.txt', 'postman/email_user.txt', [user.email], object, action, site)
index 2dceef555febbdc9f8195b7daadf7f36929d3bbf..614f17219d653d9a264dc64d89edee289ffb69ef 100644 (file)
@@ -8,6 +8,7 @@ try:
     from django.contrib.auth import get_user_model  # Django 1.5
 except ImportError:
     from postman.future_1_5 import get_user_model
+from django.contrib.sites.models import get_current_site
 from django.core.urlresolvers import reverse
 from django.db.models import Q
 from django.http import Http404
@@ -163,6 +164,7 @@ class ComposeMixin(object):
                 'user_filter': self.user_filter,
                 'exchange_filter': self.exchange_filter,
                 'max': self.max,
+                'site': get_current_site(self.request),
             })        
         return kwargs