Commits

Patrick Samson  committed 95d5e1b

Allowed 0 for User key; Relaxed the allowed charset for naming the recipients

  • Participants
  • Parent commits b726df8

Comments (0)

Files changed (7)

File docs/features.rst

 
     urlpatterns = patterns('postman.views',
         # ...
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
             WriteView.as_view(max=3),
             name='postman_write'),
         # ...
 
     urlpatterns = patterns('postman.views',
         # ...
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
             WriteView.as_view(user_filter=my_user_filter),
             name='postman_write'),
         # ...
 
     urlpatterns = patterns('postman.views',
         # ...
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
             WriteView.as_view(exchange_filter=my_exchange_filter),
             name='postman_write'),
         # ...
 
     urlpatterns = patterns('postman.views',
         # ...
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
             WriteView.as_view(autocomplete_channels=(None,'anonymous_ac')),
             name='postman_write'),
         url(r'^reply/(?P<message_id>[\d]+)/$',
 
     urlpatterns = patterns('postman.views',
         # ...
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
             WriteView.as_view(autocomplete_channels='write_ac'), 
             name='postman_write'),
         # ...

File docs/moderation.rst

 
     urlpatterns = patterns('postman.views',
         # ...
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
             WriteView.as_view(auto_moderators=(mod1, mod2)),
             name='postman_write'),
         url(r'^reply/(?P<message_id>[\d]+)/$',

File docs/views.rst

 
     urlpatterns = patterns('postman.views',
         # ...
-        url(r'^write/(?:(?P<recipients>[\w.@+-:]+)/)?$',
+        url(r'^write/(?:(?P<recipients>[^/#]+)/)?$',
             WriteView.as_view(form_classes=(MyCustomWriteForm, MyCustomAnonymousWriteForm)),
             name='postman_write'),
         url(r'^reply/(?P<message_id>[\d]+)/$',

File postman/models.py

 
     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):
 
     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()
             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."""

File postman/tests.py

-"""
+"""
 Test suite.
 
 - Do not put 'mailer' in INSTALLED_APPS, it disturbs the emails counting.
         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')
               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
 
     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()
 
     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()

File postman/urls.py

     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'),

File postman/urls_for_tests.py

     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'),
 
     # 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'),