Commits

Patrick Samson committed 6ed67f5

Adjustments for integration with version 1.2.x of django-ajax-selects, in addition to 1.1.x

Comments (0)

Files changed (9)

postman/fields.py

 arg_name = d.get('arg_name', 'channel')
 arg_default = d.get('arg_default') # the minimum to declare to enable the feature
 
+autocompleter_app = {}
 if app_name in settings.INSTALLED_APPS and arg_default:
+    autocompleter_app['is_active'] = True
+    autocompleter_app['name'] = app_name
+    autocompleter_app['version'] = getattr(__import__(app_name, globals(), locals(), ['__version__']), '__version__', None)
     # does something like "from ajax_select.fields import AutoCompleteField"
     auto_complete_field = getattr(__import__(app_name + '.fields', globals(), locals(), [field_name]), field_name)
-    is_autocompleted = True
 
     class CommaSeparatedUserField(BasicCommaSeparatedUserField, auto_complete_field):
         def __init__(self, *args, **kwargs):
                 setattr(self.widget, arg_name, value)
 
 else:
+    autocompleter_app['is_active'] = False
     CommaSeparatedUserField = BasicCommaSeparatedUserField
-    is_autocompleted = False

postman/templates/autocomplete_postman_multiple.html

-{% extends "autocomplete.html" %}
-{% block script %}
-	$('#{{ html_id }}').autocomplete('{{ lookup_url }}', {
-		width: 320,
-		formatItem: function(row) { return row[1]; },
-		formatResult: function(row) { return row[2]; },
-		multiple: true,
-		dataType: "text"
-	})
-	$('#{{ html_id }}').result(function(event, data, formatted) {
-		$('#{{ html_id }}').trigger("added");
-	})
-{% endblock %}

postman/templates/autocomplete_postman_multiple_as1-1.html

+{% extends "autocomplete.html" %}{% comment %}
+This is a custom template for django-ajax-selects version 1.1.4/5 (not for 1.2+).
+Channel:		postman_multiple_as1-1
+Form Field:		AutoCompleteField
+Usage:			Entering of multiple values.
+
+There is no such template provided in the django-ajax-selects application.
+Differences with the default template:
+- it uses the "multiple: true" option of the jquery-plugin-autocomplete
+- it fixes the issue http://code.google.com/p/django-ajax-selects/issues/detail?id=57
+Note: this template is also used in the test suite.
+
+{% endcomment %}
+{% block script %}
+	$('#{{ html_id }}').autocomplete('{{ lookup_url }}', {
+		width: 320,
+		formatItem: function(row) { return row[1]; },
+		formatResult: function(row) { return row[2]; },
+		multiple: true,
+		dataType: "text"
+	})
+	$('#{{ html_id }}').result(function(event, data, formatted) {
+		$('#{{ html_id }}').trigger("added");
+	})
+{% block extra_script %}{% endblock %}
+{% endblock %}

postman/templates/autocomplete_postman_single.html

-{% extends "autocomplete.html" %}
-{% block script %}
-	$('#{{ html_id }}').autocomplete('{{ lookup_url }}', {
-		width: 320,
-		formatItem: function(row) { return row[1]; },
-		formatResult: function(row) { return row[2]; },
-		dataType: "text"
-	})
-	$('#{{ html_id }}').result(function(event, data, formatted) {
-		$('#{{ html_id }}').trigger("added");
-	})
-{% endblock %}

postman/templates/autocomplete_postman_single_as1-1.html

+{% extends "autocomplete.html" %}{% comment %}
+This is a custom template for django-ajax-selects version 1.1.4/5 (not for 1.2+).
+Channel:		postman_single_as1-1
+Form Field:		AutoCompleteField
+Usage:			Basic entering of a single value.
+
+It is the same as the default template, except that it fixes the issue:
+http://code.google.com/p/django-ajax-selects/issues/detail?id=57
+Note: this template is also used in the test suite.
+
+{% endcomment %}
+{% block script %}
+	$('#{{ html_id }}').autocomplete('{{ lookup_url }}', {
+		width: 320,
+		formatItem: function(row) { return row[1]; },
+		formatResult: function(row) { return row[2]; },
+		dataType: "text"
+	})
+	$('#{{ html_id }}').result(function(event, data, formatted) {
+		$('#{{ html_id }}').trigger("added");
+	})
+{% block extra_script %}{% endblock %}
+{% endblock %}

postman/templates/postman/base_write.html

 {% extends "postman/base.html" %}
 {% load i18n %}
 {% block extrahead %}{{ block.super }}
-{% if is_autocompleted %}
-{# using the available admin jQuery is enough #}
-{# dj v1.4 #}{% load static %}<script type="text/javascript" src="{% static 'admin/js/jquery.min.js' %}"></script>
-{# dj v1.3 #}{# <script type="text/javascript" src="{% load adminmedia %}{% admin_media_prefix %}js/jquery.min.js"></script> #}
-{# <script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.min.js"></script> #}
-<script type="text/javascript" src="{{ MEDIA_URL }}js/jquery.autocomplete.min.js"></script>
-<link href="{{ MEDIA_URL }}css/jquery.autocomplete.css" type="text/css" media="all" rel="stylesheet" />
+{% if autocompleter_app.is_active %}
+{# dj v1.4 #}{# {% load static %} #}
+<script type="text/javascript"src="
+{# using the available admin jQuery is enough: #}
+ {# dj v1.4 #}{# {% static 'admin/js/jquery.min.js' %} #}
+ {# dj v1.2/3 #}{% load adminmedia %}{% admin_media_prefix %}js/jquery.min.js
+{# unless you really want your own: #}
+ {# dj v1.2 #}{# {{ MEDIA_URL }}js/jquery.min.js #}
+"></script>
+{% if autocompleter_app.name == "ajax_select" %}{% if autocompleter_app.version == "1.1.4" or autocompleter_app.version == "1.1.5" %}<script type="text/javascript" src="
+{# dj v1.4 #}{# {% static 'js/jquery.autocomplete.min.js' %} #}
+{# dj v1.3 #}{# {{ STATIC_URL }}js/jquery.autocomplete.min.js #}
+{# dj v1.2 #}{{ MEDIA_URL }}js/jquery.autocomplete.min.js
+"></script>
+<link type="text/css" media="all" rel="stylesheet" href="
+{# dj v1.4 #}{# {% static 'css/jquery.autocomplete.css' %} #}
+{# dj v1.3 #}{# {{ STATIC_URL }}css/jquery.autocomplete.css #}
+{# dj v1.2 #}{{ MEDIA_URL }}css/jquery.autocomplete.css
+" />{# else: for version 1.2.x use AJAX_SELECT_BOOTSTRAP + AJAX_SELECT_INLINES or arrange to include jqueryUI/js/css #}{% endif %}{% endif %}
 {% endif %}
 {% endblock %}
 {% block content %}

postman/test_urls.py

 try:
     from django.conf.urls import patterns, include, url # django 1.4
 except ImportError:
-    from django.conf.urls.defaults import patterns, include, url # django 1.3
+    from django.conf.urls.defaults import * # "patterns, include, url" is enough for django 1.3, "*" for django 1.2
 from django.forms import ValidationError
 from django.views.generic.simple import redirect_to
 
     url(r'^reply_formatters/(?P<message_id>[\d]+)/$', 'reply', {'formatters': (format_subject,format_body)}, name='postman_reply_formatters'),
     url(r'^view_formatters/(?P<message_id>[\d]+)/$', 'view', {'formatters': (format_subject,format_body)}, name='postman_view_formatters'),
     # auto-complete
-    url(r'^write_ac/(?:(?P<recipients>[\w.@+-:]+)/)?$', 'write', {'autocomplete_channels': ('postman_multiple', None)}, name='postman_write_auto_complete'),
-    url(r'^reply_ac/(?P<message_id>[\d]+)/$', 'reply', {'autocomplete_channel': 'postman_multiple'}, name='postman_reply_auto_complete'),
+    url(r'^write_ac/(?:(?P<recipients>[\w.@+-:]+)/)?$', 'write', {'autocomplete_channels': ('postman_multiple_as1-1', None)}, name='postman_write_auto_complete'),
+    url(r'^reply_ac/(?P<message_id>[\d]+)/$', 'reply', {'autocomplete_channel': 'postman_multiple_as1-1'}, name='postman_reply_auto_complete'),
     # 'template_name'
     url(r'^inbox_template/(?:(?P<option>'+OPTIONS+')/)?$', 'inbox', {'template_name': 'postman/fake.html'}, name='postman_inbox_template'),
     url(r'^sent_template/(?:(?P<option>'+OPTIONS+')/)?$', 'sent', {'template_name': 'postman/fake.html'}, name='postman_sent_template'),
                 delattr(settings, a)
         settings.POSTMAN_MAILER_APP = None
         settings.POSTMAN_AUTOCOMPLETER_APP = {
-            'arg_default': 'postman_single', # no default, mandatory to enable the feature
+            'arg_default': 'postman_single_as1-1', # no default, mandatory to enable the feature
         }
         self.reload_modules()
 
         response = self.client.get(url)
         f = response.context['form'].fields['recipients']
         if hasattr(f, 'channel'): # app may not be in INSTALLED_APPS
-            self.assertEqual(f.channel, 'postman_single')
+            self.assertEqual(f.channel, 'postman_single_as1-1')
         # authenticated
         self.assert_(self.client.login(username='foo', password='pass'))
         response = self.client.get(url)
         f = response.context['form'].fields['recipients']
         if hasattr(f, 'channel'):
-            self.assertEqual(f.channel, 'postman_multiple')
+            self.assertEqual(f.channel, 'postman_multiple_as1-1')
 
     def check_init_by_query_string(self, action, args=[]):
         template = "postman/{0}.html".format(action)
         response = self.client.get(url)
         f = response.context['form'].fields['recipients']
         if hasattr(f, 'channel'):
-            self.assertEqual(f.channel, 'postman_multiple')
+            self.assertEqual(f.channel, 'postman_multiple_as1-1')
 
     def check_404(self, view_name, pk):
         "Return is a 404 page."
         self.assertEqual(format_subject("foo bar"), "Re: foo bar")
         self.assertEqual(format_subject("Re: foo bar"), "Re: foo bar")
         self.assertEqual(format_subject("rE: foo bar"), "rE: foo bar")
+
+from postman.api import pm_broadcast, pm_write
+class ApiTest(BaseTest):
+    """
+    Test the API functions.
+    """
+    def check_message(self, m, subject='s', body='b', recipient_username='bar'):
+        "Check some message properties."
+        self.assertEqual(m.subject, subject)
+        self.assertEqual(m.body, body)
+        self.assertEqual(m.email, '')
+        self.assertEqual(m.sender, self.user1)
+        self.assertEqual(m.recipient.username, recipient_username)
+
+    def test_pm_broadcast(self):
+        "Test the case of a single recipient."
+        pm_broadcast(sender=self.user1, recipients=self.user2, subject='s', body='b')
+        m = Message.objects.get()
+        self.check_status(m, status=STATUS_ACCEPTED, moderation_date=True,
+            sender_archived=True, sender_deleted_at=True)
+        self.check_now(m.sender_deleted_at)
+        self.check_now(m.moderation_date)
+        self.check_message(m)
+        self.assertEqual(len(mail.outbox), 1)
+
+    def test_pm_broadcast_skip_notification(self):
+        "Test the notification skipping."
+        pm_broadcast(sender=self.user1, recipients=self.user2, subject='s', skip_notification=True)
+        self.assertEqual(len(mail.outbox), 0)
+
+    def test_pm_broadcast_multi(self):
+        "Test the case of more than a single recipient."
+        pm_broadcast(sender=self.user1, recipients=[self.user2, self.user3], subject='s', body='b')
+        msgs = list(Message.objects.all())
+        self.check_message(msgs[0], recipient_username='baz')
+        self.check_message(msgs[1])
+
+    def test_pm_write(self):
+        "Test the basic minimal use."
+        pm_write(sender=self.user1, recipient=self.user2, subject='s', body='b')
+        m = Message.objects.get()
+        self.check_status(m, status=STATUS_ACCEPTED, moderation_date=True)
+        self.check_now(m.moderation_date)
+        self.check_message(m)
+        self.assertEqual(len(mail.outbox), 1)
+
+    def test_pm_write_skip_notification(self):
+        "Test the notification skipping."
+        pm_write(sender=self.user1, recipient=self.user2, subject='s', skip_notification=True)
+        self.assertEqual(len(mail.outbox), 0)
+
+    def test_pm_write_auto_archive(self):
+        "Test the auto_archive parameter."
+        pm_write(sender=self.user1, recipient=self.user2, subject='s', auto_archive=True)
+        m = Message.objects.get()
+        self.check_status(m, status=STATUS_ACCEPTED, moderation_date=True, sender_archived=True)
+
+    def test_pm_write_auto_delete(self):
+        "Test the auto_delete parameter."
+        pm_write(sender=self.user1, recipient=self.user2, subject='s', auto_delete=True)
+        m = Message.objects.get()
+        self.check_status(m, status=STATUS_ACCEPTED, moderation_date=True, sender_deleted_at=True)
+        self.check_now(m.sender_deleted_at)
     from datetime import datetime
     now = datetime.now
 
-from postman.fields import is_autocompleted
+from postman.fields import autocompleter_app
 from postman.forms import WriteForm, AnonymousWriteForm, QuickReplyForm, FullReplyForm
 from postman.models import Message, get_order_by
 from postman.urls import OPTION_MESSAGES
         form = form_class(initial=initial, channel=channel)
     return render_to_response(template_name, {
         'form': form,
-        'is_autocompleted': is_autocompleted,
+        'autocompleter_app': autocompleter_app,
         'next_url': request.GET.get('next', next_url),
         }, context_instance=RequestContext(request))
 if getattr(settings, 'POSTMAN_DISALLOW_ANONYMOUS', False):
     return render_to_response(template_name, {
         'form': form,
         'recipient': parent.obfuscated_sender,
-        'is_autocompleted': is_autocompleted,
+        'autocompleter_app': autocompleter_app,
         'next_url': request.GET.get('next', next_url),
         }, context_instance=RequestContext(request))