Merge pull request #358 from flinz/django-1.9-fixes

Django 1.9 compatibility
This commit is contained in:
Ross Poulton 2015-12-16 10:24:16 +11:00
commit 6187b0568c
8 changed files with 102 additions and 71 deletions

View File

@ -49,6 +49,7 @@ def send_templated_mail(template_name, email_context, recipients, sender=None, b
along with the File objects to be read. files can be blank. along with the File objects to be read. files can be blank.
""" """
from django import VERSION
from django.conf import settings from django.conf import settings
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from django.template import loader, Context from django.template import loader, Context
@ -57,7 +58,11 @@ def send_templated_mail(template_name, email_context, recipients, sender=None, b
from helpdesk.settings import HELPDESK_EMAIL_SUBJECT_TEMPLATE from helpdesk.settings import HELPDESK_EMAIL_SUBJECT_TEMPLATE
import os import os
context = Context(email_context) # RemovedInDjango110Warning: render() must be called with a dict, not a Context.
if VERSION >= (1, 8):
context = email_context
else:
context = Context(email_context)
if hasattr(context['queue'], 'locale'): if hasattr(context['queue'], 'locale'):
locale = getattr(context['queue'], 'locale', '') locale = getattr(context['queue'], 'locale', '')

View File

@ -1230,7 +1230,7 @@ class CustomField(models.Model):
label = models.CharField( label = models.CharField(
_('Label'), _('Label'),
max_length='30', max_length=30,
help_text=_('The display label for this field'), help_text=_('The display label for this field'),
) )

View File

@ -1,5 +1,4 @@
{% load i18n %} {% load i18n %}
{% load url from future %}
{% load load_helpdesk_settings %} {% load load_helpdesk_settings %}
{% load static from staticfiles %} {% load static from staticfiles %}
{% with request|load_helpdesk_settings as helpdesk_settings %} {% with request|load_helpdesk_settings as helpdesk_settings %}

View File

@ -1,6 +1,5 @@
{% extends "helpdesk/public_base.html" %} {% extends "helpdesk/public_base.html" %}
{% load i18n bootstrap %} {% load i18n bootstrap %}
{% load url from future %}
{% block helpdesk_body %} {% block helpdesk_body %}

View File

@ -4,6 +4,12 @@ from django.core import mail
from django.test.client import Client from django.test.client import Client
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
try: # python 3
from urllib.parse import urlparse
except ImportError: # python 2
from urlparse import urlparse
class TicketBasicsTestCase(TestCase): class TicketBasicsTestCase(TestCase):
fixtures = ['emailtemplate.json'] fixtures = ['emailtemplate.json']
@ -44,11 +50,16 @@ class TicketBasicsTestCase(TestCase):
last_redirect = response.redirect_chain[-1] last_redirect = response.redirect_chain[-1]
last_redirect_url = last_redirect[0] last_redirect_url = last_redirect[0]
last_redirect_status = last_redirect[1] last_redirect_status = last_redirect[1]
# Ensure we landed on the "View" page. # Ensure we landed on the "View" page.
self.assertEqual(last_redirect_url.split('?')[0], 'http://testserver%s' % reverse('helpdesk_public_view')) # Django 1.9 compatible way of testing this
# https://docs.djangoproject.com/en/1.9/releases/1.9/#http-redirects-no-longer-forced-to-absolute-uris
urlparts = urlparse(last_redirect_url)
self.assertEqual(urlparts.path, reverse('helpdesk_public_view'))
# Ensure submitter, new-queue + update-queue were all emailed. # Ensure submitter, new-queue + update-queue were all emailed.
self.assertEqual(email_count+3, len(mail.outbox)) self.assertEqual(email_count+3, len(mail.outbox))
def test_create_ticket_private(self): def test_create_ticket_private(self):
email_count = len(mail.outbox) email_count = len(mail.outbox)
post_data = { post_data = {
@ -83,7 +94,12 @@ class TicketBasicsTestCase(TestCase):
last_redirect = response.redirect_chain[-1] last_redirect = response.redirect_chain[-1]
last_redirect_url = last_redirect[0] last_redirect_url = last_redirect[0]
last_redirect_status = last_redirect[1] last_redirect_status = last_redirect[1]
# Ensure we landed on the "View" page. # Ensure we landed on the "View" page.
self.assertEqual(last_redirect_url.split('?')[0], 'http://testserver%s' % reverse('helpdesk_public_view')) # Django 1.9 compatible way of testing this
# https://docs.djangoproject.com/en/1.9/releases/1.9/#http-redirects-no-longer-forced-to-absolute-uris
urlparts = urlparse(last_redirect_url)
self.assertEqual(urlparts.path, reverse('helpdesk_public_view'))
# Ensure only two e-mails were sent - submitter & updated. # Ensure only two e-mails were sent - submitter & updated.
self.assertEqual(email_count+2, len(mail.outbox)) self.assertEqual(email_count+2, len(mail.outbox))

View File

@ -16,7 +16,8 @@ else:
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from helpdesk import settings as helpdesk_settings from helpdesk import settings as helpdesk_settings
from helpdesk.views import feeds from helpdesk.views import feeds, staff, public, api, kb
from django.contrib.auth import views as auth_views
from django.views.generic import TemplateView from django.views.generic import TemplateView
class DirectTemplateView(TemplateView): class DirectTemplateView(TemplateView):
@ -31,135 +32,135 @@ class DirectTemplateView(TemplateView):
context[key] = value context[key] = value
return context return context
urlpatterns = patterns('helpdesk.views.staff', urlpatterns = [
url(r'^dashboard/$', url(r'^dashboard/$',
'dashboard', staff.dashboard,
name='helpdesk_dashboard'), name='helpdesk_dashboard'),
url(r'^tickets/$', url(r'^tickets/$',
'ticket_list', staff.ticket_list,
name='helpdesk_list'), name='helpdesk_list'),
url(r'^tickets/update/$', url(r'^tickets/update/$',
'mass_update', staff.mass_update,
name='helpdesk_mass_update'), name='helpdesk_mass_update'),
url(r'^tickets/submit/$', url(r'^tickets/submit/$',
'create_ticket', staff.create_ticket,
name='helpdesk_submit'), name='helpdesk_submit'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/$',
'view_ticket', staff.view_ticket,
name='helpdesk_view'), name='helpdesk_view'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/followup_edit/(?P<followup_id>[0-9]+)/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/followup_edit/(?P<followup_id>[0-9]+)/$',
'followup_edit', staff.followup_edit,
name='helpdesk_followup_edit'), name='helpdesk_followup_edit'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/followup_delete/(?P<followup_id>[0-9]+)/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/followup_delete/(?P<followup_id>[0-9]+)/$',
'followup_delete', staff.followup_delete,
name='helpdesk_followup_delete'), name='helpdesk_followup_delete'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/edit/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/edit/$',
'edit_ticket', staff.edit_ticket,
name='helpdesk_edit'), name='helpdesk_edit'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/update/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/update/$',
'update_ticket', staff.update_ticket,
name='helpdesk_update'), name='helpdesk_update'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/delete/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/delete/$',
'delete_ticket', staff.delete_ticket,
name='helpdesk_delete'), name='helpdesk_delete'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/hold/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/hold/$',
'hold_ticket', staff.hold_ticket,
name='helpdesk_hold'), name='helpdesk_hold'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/unhold/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/unhold/$',
'unhold_ticket', staff.unhold_ticket,
name='helpdesk_unhold'), name='helpdesk_unhold'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/$',
'ticket_cc', staff.ticket_cc,
name='helpdesk_ticket_cc'), name='helpdesk_ticket_cc'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/add/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/add/$',
'ticket_cc_add', staff.ticket_cc_add,
name='helpdesk_ticket_cc_add'), name='helpdesk_ticket_cc_add'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/delete/(?P<cc_id>[0-9]+)/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/cc/delete/(?P<cc_id>[0-9]+)/$',
'ticket_cc_del', staff.ticket_cc_del,
name='helpdesk_ticket_cc_del'), name='helpdesk_ticket_cc_del'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/dependency/add/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/dependency/add/$',
'ticket_dependency_add', staff.ticket_dependency_add,
name='helpdesk_ticket_dependency_add'), name='helpdesk_ticket_dependency_add'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/dependency/delete/(?P<dependency_id>[0-9]+)/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/dependency/delete/(?P<dependency_id>[0-9]+)/$',
'ticket_dependency_del', staff.ticket_dependency_del,
name='helpdesk_ticket_dependency_del'), name='helpdesk_ticket_dependency_del'),
url(r'^tickets/(?P<ticket_id>[0-9]+)/attachment_delete/(?P<attachment_id>[0-9]+)/$', url(r'^tickets/(?P<ticket_id>[0-9]+)/attachment_delete/(?P<attachment_id>[0-9]+)/$',
'attachment_del', staff.attachment_del,
name='helpdesk_attachment_del'), name='helpdesk_attachment_del'),
url(r'^raw/(?P<type>\w+)/$', url(r'^raw/(?P<type>\w+)/$',
'raw_details', staff.raw_details,
name='helpdesk_raw'), name='helpdesk_raw'),
url(r'^rss/$', url(r'^rss/$',
'rss_list', staff.rss_list,
name='helpdesk_rss_index'), name='helpdesk_rss_index'),
url(r'^reports/$', url(r'^reports/$',
'report_index', staff.report_index,
name='helpdesk_report_index'), name='helpdesk_report_index'),
url(r'^reports/(?P<report>\w+)/$', url(r'^reports/(?P<report>\w+)/$',
'run_report', staff.run_report,
name='helpdesk_run_report'), name='helpdesk_run_report'),
url(r'^save_query/$', url(r'^save_query/$',
'save_query', staff.save_query,
name='helpdesk_savequery'), name='helpdesk_savequery'),
url(r'^delete_query/(?P<id>[0-9]+)/$', url(r'^delete_query/(?P<id>[0-9]+)/$',
'delete_saved_query', staff.delete_saved_query,
name='helpdesk_delete_query'), name='helpdesk_delete_query'),
url(r'^settings/$', url(r'^settings/$',
'user_settings', staff.user_settings,
name='helpdesk_user_settings'), name='helpdesk_user_settings'),
url(r'^ignore/$', url(r'^ignore/$',
'email_ignore', staff.email_ignore,
name='helpdesk_email_ignore'), name='helpdesk_email_ignore'),
url(r'^ignore/add/$', url(r'^ignore/add/$',
'email_ignore_add', staff.email_ignore_add,
name='helpdesk_email_ignore_add'), name='helpdesk_email_ignore_add'),
url(r'^ignore/delete/(?P<id>[0-9]+)/$', url(r'^ignore/delete/(?P<id>[0-9]+)/$',
'email_ignore_del', staff.email_ignore_del,
name='helpdesk_email_ignore_del'), name='helpdesk_email_ignore_del'),
) ]
urlpatterns += patterns('helpdesk.views.public', urlpatterns += [
url(r'^$', url(r'^$',
'homepage', public.homepage,
name='helpdesk_home'), name='helpdesk_home'),
url(r'^view/$', url(r'^view/$',
'view_ticket', public.view_ticket,
name='helpdesk_public_view'), name='helpdesk_public_view'),
url(r'^change_language/$', url(r'^change_language/$',
'change_language', public.change_language,
name='helpdesk_public_change_language'), name='helpdesk_public_change_language'),
) ]
urlpatterns += patterns('', urlpatterns += [
url(r'^rss/user/(?P<user_name>[^/]+)/$', url(r'^rss/user/(?P<user_name>[^/]+)/$',
login_required(feeds.OpenTicketsByUser()), login_required(feeds.OpenTicketsByUser()),
name='helpdesk_rss_user'), name='helpdesk_rss_user'),
@ -167,60 +168,66 @@ urlpatterns += patterns('',
url(r'^rss/user/(?P<user_name>[^/]+)/(?P<queue_slug>[A-Za-z0-9_-]+)/$', url(r'^rss/user/(?P<user_name>[^/]+)/(?P<queue_slug>[A-Za-z0-9_-]+)/$',
login_required(feeds.OpenTicketsByUser()), login_required(feeds.OpenTicketsByUser()),
name='helpdesk_rss_user_queue'), name='helpdesk_rss_user_queue'),
url(r'^rss/queue/(?P<queue_slug>[A-Za-z0-9_-]+)/$', url(r'^rss/queue/(?P<queue_slug>[A-Za-z0-9_-]+)/$',
login_required(feeds.OpenTicketsByQueue()), login_required(feeds.OpenTicketsByQueue()),
name='helpdesk_rss_queue'), name='helpdesk_rss_queue'),
url(r'^rss/unassigned/$', url(r'^rss/unassigned/$',
login_required(feeds.UnassignedTickets()), login_required(feeds.UnassignedTickets()),
name='helpdesk_rss_unassigned'), name='helpdesk_rss_unassigned'),
url(r'^rss/recent_activity/$', url(r'^rss/recent_activity/$',
login_required(feeds.RecentFollowUps()), login_required(feeds.RecentFollowUps()),
name='helpdesk_rss_activity'), name='helpdesk_rss_activity'),
]
)
urlpatterns += patterns('', urlpatterns += [
url(r'^api/(?P<method>[a-z_-]+)/$', url(r'^api/(?P<method>[a-z_-]+)/$',
'helpdesk.views.api.api', api.api,
name='helpdesk_api'), name='helpdesk_api'),
url(r'^login/$', url(r'^login/$',
'django.contrib.auth.views.login', auth_views.login,
{'template_name': 'helpdesk/registration/login.html'}, {'template_name': 'helpdesk/registration/login.html'},
name='login'), name='login'),
url(r'^logout/$', url(r'^logout/$',
'django.contrib.auth.views.logout', auth_views.logout,
{'template_name': 'helpdesk/registration/login.html', 'next_page': '../'}, {'template_name': 'helpdesk/registration/login.html', 'next_page': '../'},
name='logout'), name='logout'),
) ]
if helpdesk_settings.HELPDESK_KB_ENABLED: if helpdesk_settings.HELPDESK_KB_ENABLED:
urlpatterns += patterns('helpdesk.views.kb', urlpatterns += [
url(r'^kb/$', url(r'^kb/$',
'index', name='helpdesk_kb_index'), kb.index,
name='helpdesk_kb_index'),
url(r'^kb/(?P<item>[0-9]+)/$', url(r'^kb/(?P<item>[0-9]+)/$',
'item', name='helpdesk_kb_item'), kb.item,
name='helpdesk_kb_item'),
url(r'^kb/(?P<item>[0-9]+)/vote/$', url(r'^kb/(?P<item>[0-9]+)/vote/$',
'vote', name='helpdesk_kb_vote'), kb.vote,
name='helpdesk_kb_vote'),
url(r'^kb/(?P<slug>[A-Za-z0-9_-]+)/$', url(r'^kb/(?P<slug>[A-Za-z0-9_-]+)/$',
'category', name='helpdesk_kb_category'), kb.category,
) name='helpdesk_kb_category'),
]
urlpatterns += patterns('', urlpatterns += [
url(r'^api/$', TemplateView.as_view(template_name='helpdesk/help_api.html'), url(r'^api/$',
TemplateView.as_view(template_name='helpdesk/help_api.html'),
name='helpdesk_api_help'), name='helpdesk_api_help'),
url(r'^help/context/$', TemplateView.as_view(template_name='helpdesk/help_context.html'), url(r'^help/context/$',
TemplateView.as_view(template_name='helpdesk/help_context.html'),
name='helpdesk_help_context'), name='helpdesk_help_context'),
url(r'^system_settings/$', DirectTemplateView.as_view(template_name='helpdesk/system_settings.html'), url(r'^system_settings/$',
DirectTemplateView.as_view(template_name='helpdesk/system_settings.html'),
name='helpdesk_system_settings'), name='helpdesk_system_settings'),
) ]

View File

@ -11,6 +11,7 @@ from django.utils.encoding import python_2_unicode_compatible
from datetime import datetime, timedelta from datetime import datetime, timedelta
import sys import sys
from django import VERSION
from django.conf import settings from django.conf import settings
try: try:
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
@ -374,7 +375,6 @@ def update_ticket(request, ticket_id, public=False):
# then the following line will give us a crash, since django expects {% if %} # then the following line will give us a crash, since django expects {% if %}
# to be closed with an {% endif %} tag. # to be closed with an {% endif %} tag.
# get_template_from_string was removed in Django 1.8 http://django.readthedocs.org/en/1.8.x/ref/templates/upgrading.html # get_template_from_string was removed in Django 1.8 http://django.readthedocs.org/en/1.8.x/ref/templates/upgrading.html
try: try:
from django.template import engines from django.template import engines
@ -382,7 +382,11 @@ def update_ticket(request, ticket_id, public=False):
except ImportError: # occurs in django < 1.8 except ImportError: # occurs in django < 1.8
template_func = loader.get_template_from_string template_func = loader.get_template_from_string
comment = template_func(comment).render(Context(context)) # RemovedInDjango110Warning: render() must be called with a dict, not a Context.
if VERSION < (1, 8):
context = Context(context)
comment = template_func(comment).render(context)
if owner is -1 and ticket.assigned_to: if owner is -1 and ticket.assigned_to:
owner = ticket.assigned_to.id owner = ticket.assigned_to.id

View File

@ -19,13 +19,14 @@ class QuickDjangoTest(object):
""" """
DIRNAME = os.path.dirname(__file__) DIRNAME = os.path.dirname(__file__)
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.admin',
'django.contrib.staticfiles',
'django.contrib.messages',
'django.contrib.humanize', 'django.contrib.humanize',
'django.contrib.messages',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.staticfiles',
'bootstrapform', 'bootstrapform',
) )
MIDDLEWARE_CLASSES = [ MIDDLEWARE_CLASSES = [