]> git.parisson.com Git - django-postman.git/commitdiff
Allowed 0 for User key; Relaxed the allowed charset for naming the recipients
authorPatrick Samson <pk.samson@gmail.com>
Fri, 17 Jan 2014 20:23:54 +0000 (21:23 +0100)
committerPatrick Samson <pk.samson@gmail.com>
Fri, 17 Jan 2014 20:23:54 +0000 (21:23 +0100)
docs/features.rst
docs/moderation.rst
docs/views.rst
postman/models.py
postman/tests.py
postman/urls.py
postman/urls_for_tests.py

index 0167ab81caada508948d5dd7c9769919c5f62ccf..416622ae0a42c8e766bb08ffd13d9fa82d572527 100644 (file)
@@ -45,7 +45,7 @@ Example::
 \r
     urlpatterns = patterns('postman.views',\r
         # ...\r
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',\r
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',\r
             WriteView.as_view(max=3),\r
             name='postman_write'),\r
         # ...\r
@@ -93,7 +93,7 @@ Example::
 \r
     urlpatterns = patterns('postman.views',\r
         # ...\r
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',\r
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',\r
             WriteView.as_view(user_filter=my_user_filter),\r
             name='postman_write'),\r
         # ...\r
@@ -152,7 +152,7 @@ An example, with the django-relationships application::
 \r
     urlpatterns = patterns('postman.views',\r
         # ...\r
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',\r
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',\r
             WriteView.as_view(exchange_filter=my_exchange_filter),\r
             name='postman_write'),\r
         # ...\r
@@ -261,7 +261,7 @@ Example::
 \r
     urlpatterns = patterns('postman.views',\r
         # ...\r
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',\r
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',\r
             WriteView.as_view(autocomplete_channels=(None,'anonymous_ac')),\r
             name='postman_write'),\r
         url(r'^reply/(?P<message_id>[\d]+)/$',\r
@@ -274,7 +274,7 @@ Example::
 \r
     urlpatterns = patterns('postman.views',\r
         # ...\r
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',\r
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',\r
             WriteView.as_view(autocomplete_channels='write_ac'), \r
             name='postman_write'),\r
         # ...\r
index e13332473d207575e74c62f32cc55420107695e3..fd040780326e5a9744276498b7863391692e8783 100644 (file)
@@ -36,7 +36,7 @@ Example::
 \r
     urlpatterns = patterns('postman.views',\r
         # ...\r
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',\r
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',\r
             WriteView.as_view(auto_moderators=(mod1, mod2)),\r
             name='postman_write'),\r
         url(r'^reply/(?P<message_id>[\d]+)/$',\r
index 05772f59494994a4694a10dc16127dc70febcc7e..17656fdcb4335cb5afa33b04ef6351010cbd1407 100644 (file)
@@ -25,7 +25,7 @@ Examples::
 \r
     urlpatterns = patterns('postman.views',\r
         # ...\r
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',\r
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',\r
             WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),\r
             name='postman_write'),\r
         url(r'^reply/(?P<message_id>[\d]+)/$',\r
index eb58dcb8df3e4d4cb8113cc931b0f55d2786d766..a819f71d386196767dd94855aaed931ba9598081 100644 (file)
@@ -368,7 +368,7 @@ class Message(models.Model):
 
     def clean(self):
         """Check some validity constraints."""
-        if not (self.sender_id or self.email):
+        if not (self.sender_id is not None or self.email):
             raise ValidationError(ugettext("Undefined sender."))
 
     def clean_moderation(self, initial_status, user=None):
@@ -385,11 +385,11 @@ class Message(models.Model):
 
     def clean_for_visitor(self):
         """Do some auto-read and auto-delete, because there is no one to do it (no account)."""
-        if not self.sender_id:
+        if self.sender_id is None:
             # no need to wait for a final moderation status to mark as deleted
             if not self.sender_deleted_at:
                 self.sender_deleted_at = now()
-        elif not self.recipient_id:
+        elif self.recipient_id is None:
             if self.is_accepted():
                 if not self.read_at:
                     self.read_at = now()
@@ -431,10 +431,10 @@ class Message(models.Model):
             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', site)
+                if not (self.sender_id is not None and is_auto_moderated):
+                    (notify_user if self.sender_id is not None else email_visitor)(self, 'rejection', site)
             elif self.is_accepted():
-                (notify_user if self.recipient_id else email_visitor)(self, 'acceptance', site)
+                (notify_user if self.recipient_id is not None else email_visitor)(self, 'acceptance', site)
 
     def get_dates(self):
         """Get some dates to restore later."""
index 75f36665aed0a38230fc4386df9b2cc8b898a3f1..a26c09ff49ce904c3e0ba453c21f955948110c8c 100644 (file)
@@ -1,4 +1,4 @@
-"""
+"""
 Test suite.
 
 - Do not put 'mailer' in INSTALLED_APPS, it disturbs the emails counting.
@@ -287,6 +287,12 @@ class ViewTest(BaseTest):
         response = self.client.get(url)
         self.assertContains(response, 'value="bar, foo"')
 
+        # because of Custom User Model, do allow almost any character, not only '^[\w.@+-]+$' of the legacy django.contrib.auth.User model
+        get_user_model().objects.create_user("Le Créac'h", 'foobar@domain.com', 'pass')  # even: space, accentued, qootes
+        url = reverse('postman_write', args=["Le Créac'h"])
+        response = self.client.get(url)
+        self.assertContains(response, 'value="Le Créac&#39;h"')
+
     def test_write_auto_complete(self):
         "Test the 'autocomplete_channels' parameter."
         url = reverse('postman_write_auto_complete')
@@ -1001,7 +1007,7 @@ class MessageManagerTest(BaseTest):
               x       X---
         """
 
-        m1 = self.c12(moderation_status=STATUS_PENDING);
+        m1 = self.c12(moderation_status=STATUS_PENDING)
         m2 = self.c12(moderation_status=STATUS_REJECTED, recipient_deleted_at=now())
         m3 = self.c12()
         m3.read_at, m3.thread = now(), m3
@@ -1377,23 +1383,23 @@ class MessageTest(BaseTest):
 
     def test_notification_rejection_user(self):
         "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)
+        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)
+        m = Message.objects.create(subject='s', moderation_status=STATUS_REJECTED, sender=self.user1, recipient=self.user2)
         self.check_notification(m, 0, is_auto_moderated=True)
 
     def test_notification_rejection_user_inactive(self):
         "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)
+        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, 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)
+        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()
@@ -1406,18 +1412,18 @@ class MessageTest(BaseTest):
 
     def test_notification_acceptance_user(self):
         "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)
+        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, recipient is a User, but must be active."
-        m = Message.objects.create(subject='s', moderation_status=STATUS_ACCEPTED, sender=self.user1, recipient = self.user2)
+        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)
+        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()
index 1fcc091f9cbf3ab07de4db8acf3c9ca4ea398368..71c29fdc3c2e0781639684fc62d49ce33535be62 100644 (file)
@@ -105,7 +105,7 @@ urlpatterns = patterns('',
     url(r'^sent/(?:(?P<option>'+OPTIONS+')/)?$', SentView.as_view(), name='postman_sent'),
     url(r'^archives/(?:(?P<option>'+OPTIONS+')/)?$', ArchivesView.as_view(), name='postman_archives'),
     url(r'^trash/(?:(?P<option>'+OPTIONS+')/)?$', TrashView.as_view(), name='postman_trash'),
-    url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(), name='postman_write'),
+    url(r'^write/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(), name='postman_write'),
     url(r'^reply/(?P<message_id>[\d]+)/$', ReplyView.as_view(), name='postman_reply'),
     url(r'^view/(?P<message_id>[\d]+)/$', MessageView.as_view(), name='postman_view'),
     url(r'^view/t/(?P<thread_id>[\d]+)/$', ConversationView.as_view(), name='postman_view_conversation'),
index e5bc6eee71306000cee045b50851565cce93233b..9970468a96d28901f6650b714d246df4caef920d 100644 (file)
@@ -65,7 +65,7 @@ postman_patterns = patterns('',
     url(r'^sent/(?:(?P<option>'+OPTIONS+')/)?$', SentView.as_view(), name='postman_sent'),
     url(r'^archives/(?:(?P<option>'+OPTIONS+')/)?$', ArchivesView.as_view(), name='postman_archives'),
     url(r'^trash/(?:(?P<option>'+OPTIONS+')/)?$', TrashView.as_view(), name='postman_trash'),
-    url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(), name='postman_write'),
+    url(r'^write/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(), name='postman_write'),
     url(r'^reply/(?P<message_id>[\d]+)/$', ReplyView.as_view(), name='postman_reply'),
     url(r'^view/(?P<message_id>[\d]+)/$', MessageView.as_view(), name='postman_view'),
     url(r'^view/t/(?P<thread_id>[\d]+)/$', ConversationView.as_view(), name='postman_view_conversation'),
@@ -76,49 +76,49 @@ postman_patterns = patterns('',
 
     # Customized set
     # 'success_url'
-    url(r'^write_sent/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(success_url='postman_sent'), name='postman_write_with_success_url_to_sent'),
+    url(r'^write_sent/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(success_url='postman_sent'), name='postman_write_with_success_url_to_sent'),
     url(r'^reply_sent/(?P<message_id>[\d]+)/$', ReplyView.as_view(success_url='postman_sent'), name='postman_reply_with_success_url_to_sent'),
     url(r'^archive_arch/$', ArchiveView.as_view(success_url='postman_archives'), name='postman_archive_with_success_url_to_archives'),
     url(r'^delete_arch/$', DeleteView.as_view(success_url='postman_archives'), name='postman_delete_with_success_url_to_archives'),
     url(r'^undelete_arch/$', UndeleteView.as_view(success_url='postman_archives'), name='postman_undelete_with_success_url_to_archives'),
     # 'max'
-    url(r'^write_max/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(max=1), name='postman_write_with_max'),
+    url(r'^write_max/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(max=1), name='postman_write_with_max'),
     url(r'^reply_max/(?P<message_id>[\d]+)/$', ReplyView.as_view(max=1), name='postman_reply_with_max'),
     # 'user_filter' on write
-    url(r'^write_user_filter_reason/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(user_filter=user_filter_reason), name='postman_write_with_user_filter_reason'),
-    url(r'^write_user_filter_no_reason/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(user_filter=user_filter_no_reason), name='postman_write_with_user_filter_no_reason'),
-    url(r'^write_user_filter_false/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(user_filter=user_filter_false), name='postman_write_with_user_filter_false'),
-    url(r'^write_user_filter_exception/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(user_filter=user_filter_exception), name='postman_write_with_user_filter_exception'),
+    url(r'^write_user_filter_reason/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(user_filter=user_filter_reason), name='postman_write_with_user_filter_reason'),
+    url(r'^write_user_filter_no_reason/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(user_filter=user_filter_no_reason), name='postman_write_with_user_filter_no_reason'),
+    url(r'^write_user_filter_false/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(user_filter=user_filter_false), name='postman_write_with_user_filter_false'),
+    url(r'^write_user_filter_exception/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(user_filter=user_filter_exception), name='postman_write_with_user_filter_exception'),
     # 'user_filter' on reply
     url(r'^reply_user_filter_reason/(?P<message_id>[\d]+)/$', ReplyView.as_view(user_filter=user_filter_reason), name='postman_reply_with_user_filter_reason'),
     url(r'^reply_user_filter_no_reason/(?P<message_id>[\d]+)/$', ReplyView.as_view(user_filter=user_filter_no_reason), name='postman_reply_with_user_filter_no_reason'),
     url(r'^reply_user_filter_false/(?P<message_id>[\d]+)/$', ReplyView.as_view(user_filter=user_filter_false), name='postman_reply_with_user_filter_false'),
     url(r'^reply_user_filter_exception/(?P<message_id>[\d]+)/$', ReplyView.as_view(user_filter=user_filter_exception), name='postman_reply_with_user_filter_exception'),
     # 'exchange_filter' on write
-    url(r'^write_exch_filter_reason/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_reason), name='postman_write_with_exch_filter_reason'),
-    url(r'^write_exch_filter_no_reason/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_no_reason), name='postman_write_with_exch_filter_no_reason'),
-    url(r'^write_exch_filter_false/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_false), name='postman_write_with_exch_filter_false'),
-    url(r'^write_exch_filter_exception/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_exception), name='postman_write_with_exch_filter_exception'),
+    url(r'^write_exch_filter_reason/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_reason), name='postman_write_with_exch_filter_reason'),
+    url(r'^write_exch_filter_no_reason/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_no_reason), name='postman_write_with_exch_filter_no_reason'),
+    url(r'^write_exch_filter_false/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_false), name='postman_write_with_exch_filter_false'),
+    url(r'^write_exch_filter_exception/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(exchange_filter=exch_filter_exception), name='postman_write_with_exch_filter_exception'),
     # 'exchange_filter' on reply
     url(r'^reply_exch_filter_reason/(?P<message_id>[\d]+)/$', ReplyView.as_view(exchange_filter=exch_filter_reason), name='postman_reply_with_exch_filter_reason'),
     url(r'^reply_exch_filter_no_reason/(?P<message_id>[\d]+)/$', ReplyView.as_view(exchange_filter=exch_filter_no_reason), name='postman_reply_with_exch_filter_no_reason'),
     url(r'^reply_exch_filter_false/(?P<message_id>[\d]+)/$', ReplyView.as_view(exchange_filter=exch_filter_false), name='postman_reply_with_exch_filter_false'),
     url(r'^reply_exch_filter_exception/(?P<message_id>[\d]+)/$', ReplyView.as_view(exchange_filter=exch_filter_exception), name='postman_reply_with_exch_filter_exception'),
     # 'auto_moderators'
-    url(r'^write_moderate/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(auto_moderators=(moderate_as_51,moderate_as_48)), name='postman_write_moderate'),
+    url(r'^write_moderate/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(auto_moderators=(moderate_as_51,moderate_as_48)), name='postman_write_moderate'),
     url(r'^reply_moderate/(?P<message_id>[\d]+)/$', ReplyView.as_view(auto_moderators=(moderate_as_51,moderate_as_48)), name='postman_reply_moderate'),
     # 'formatters'
     url(r'^reply_formatters/(?P<message_id>[\d]+)/$', ReplyView.as_view(formatters=(format_subject, format_body)), name='postman_reply_formatters'),
     url(r'^view_formatters/(?P<message_id>[\d]+)/$', MessageView.as_view(formatters=(format_subject, format_body)), name='postman_view_formatters'),
     # auto-complete
-    url(r'^write_ac/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(autocomplete_channels=('postman_multiple_as1-1', None)), name='postman_write_auto_complete'),
+    url(r'^write_ac/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(autocomplete_channels=('postman_multiple_as1-1', None)), name='postman_write_auto_complete'),
     url(r'^reply_ac/(?P<message_id>[\d]+)/$', ReplyView.as_view(autocomplete_channel='postman_multiple_as1-1'), name='postman_reply_auto_complete'),
     # 'template_name'
     url(r'^inbox_template/(?:(?P<option>'+OPTIONS+')/)?$', InboxView.as_view(template_name='postman/fake.html'), name='postman_inbox_template'),
     url(r'^sent_template/(?:(?P<option>'+OPTIONS+')/)?$', SentView.as_view(template_name='postman/fake.html'), name='postman_sent_template'),
     url(r'^archives_template/(?:(?P<option>'+OPTIONS+')/)?$', ArchivesView.as_view(template_name='postman/fake.html'), name='postman_archives_template'),
     url(r'^trash_template/(?:(?P<option>'+OPTIONS+')/)?$', TrashView.as_view(template_name='postman/fake.html'), name='postman_trash_template'),
-    url(r'^write_template/(?:(?P<recipients>[\w.@+-:]+)/)?$', WriteView.as_view(template_name='postman/fake.html'), name='postman_write_template'),
+    url(r'^write_template/(?:(?P<recipients>[^/#]+)/)?$', WriteView.as_view(template_name='postman/fake.html'), name='postman_write_template'),
     url(r'^reply_template/(?P<message_id>[\d]+)/$', ReplyView.as_view(template_name='postman/fake.html'), name='postman_reply_template'),
     url(r'^view_template/(?P<message_id>[\d]+)/$', MessageView.as_view(template_name='postman/fake.html'), name='postman_view_template'),
     url(r'^view_template/t/(?P<thread_id>[\d]+)/$', ConversationView.as_view(template_name='postman/fake.html'), name='postman_view_conversation_template'),