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
+++ /dev/null
-{% 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 %}
\ No newline at end of file
--- /dev/null
+{% 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 %}
\ No newline at end of file
+++ /dev/null
-{% 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 %}
\ No newline at end of file
--- /dev/null
+{% 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 %}
\ No newline at end of file
{% 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 %}
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))