From 764c55e60e22721ea446567c687ffbfd840f6ae8 Mon Sep 17 00:00:00 2001 From: Andrii Iudin Date: Mon, 26 Mar 2018 13:46:07 +0100 Subject: [PATCH 01/15] Removed unused dash_tickets variable and its calculation, modified the case where it is used to rely on model query APIs rather than on raw queries that use the default database and are not forwarded by routers. --- helpdesk/views/staff.py | 50 +++++++++-------------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py index 5cb871fc..6578e24f 100644 --- a/helpdesk/views/staff.py +++ b/helpdesk/views/staff.py @@ -151,21 +151,6 @@ def dashboard(request): else: where_clause = """WHERE q.id = t.queue_id""" - cursor = connection.cursor() - cursor.execute(""" - SELECT q.id as queue, - q.title AS name, - COUNT(CASE t.status WHEN '1' THEN t.id WHEN '2' THEN t.id END) AS open, - COUNT(CASE t.status WHEN '3' THEN t.id END) AS resolved, - COUNT(CASE t.status WHEN '4' THEN t.id END) AS closed - %s - %s - GROUP BY queue, name - ORDER BY q.id; - """ % (from_clause, where_clause)) - - dash_tickets = query_to_dict(cursor.fetchall(), cursor.description) - return render(request, 'helpdesk/dashboard.html', { 'user_tickets': tickets, 'user_tickets_closed_resolved': tickets_closed_resolved, @@ -1103,31 +1088,18 @@ def report_index(request): # Open Resolved # Queue 1 10 4 # Queue 2 4 12 + Queues = user_queues if user_queues else Queue.objects.all() - queues = _get_user_queues(request.user).values_list('id', flat=True) - - from_clause = """FROM helpdesk_ticket t, - helpdesk_queue q""" - if queues: - where_clause = """WHERE q.id = t.queue_id AND - q.id IN (%s)""" % (",".join(("%d" % pk for pk in queues))) - else: - where_clause = """WHERE q.id = t.queue_id""" - - cursor = connection.cursor() - cursor.execute(""" - SELECT q.id as queue, - q.title AS name, - COUNT(CASE t.status WHEN '1' THEN t.id WHEN '2' THEN t.id END) AS open, - COUNT(CASE t.status WHEN '3' THEN t.id END) AS resolved, - COUNT(CASE t.status WHEN '4' THEN t.id END) AS closed - %s - %s - GROUP BY queue, name - ORDER BY q.id; - """ % (from_clause, where_clause)) - - dash_tickets = query_to_dict(cursor.fetchall(), cursor.description) + dash_tickets = [] + for queue in Queues: + dash_ticket = { + 'queue': queue.id, + 'name': queue.title, + 'open': queue.ticket_set.filter(status__in=[1, 2]).count(), + 'resolved': queue.ticket_set.filter(status=3).count(), + 'closed': queue.ticket_set.filter(status=4).count(), + } + dash_tickets.append(dash_ticket) return render(request, 'helpdesk/report_index.html', { 'number_tickets': number_tickets, From d372e337c6edd826b36ade7c2c43440688df5619 Mon Sep 17 00:00:00 2001 From: Patrick Mithamo Date: Thu, 29 Mar 2018 01:51:24 +0300 Subject: [PATCH 02/15] Fix imaplib 'IMAP' module reference to 'IMAP4' On IMAP login error: 'imaplib' has no 'IMAP' member; maybe 'IMAP4' --- helpdesk/management/commands/get_email.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpdesk/management/commands/get_email.py b/helpdesk/management/commands/get_email.py index 65eea45b..f9fb7392 100755 --- a/helpdesk/management/commands/get_email.py +++ b/helpdesk/management/commands/get_email.py @@ -216,7 +216,7 @@ def process_queue(q, logger): q.email_box_pass or settings.QUEUE_EMAIL_BOX_PASSWORD) server.select(q.email_box_imap_folder) - except imaplib.IMAP.abort: + except imaplib.IMAP4.abort: logger.error("IMAP login failed. Check that the server is accessible and that the username and password are correct.") server.logout() sys.exit() From a361e769999172b0d7ef37f581c16884c6d7ee29 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Fri, 20 Apr 2018 03:27:26 -0400 Subject: [PATCH 03/15] Update akismet code for python 3, to address #607 --- helpdesk/akismet.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/helpdesk/akismet.py b/helpdesk/akismet.py index 9a99c881..31564b92 100644 --- a/helpdesk/akismet.py +++ b/helpdesk/akismet.py @@ -12,6 +12,9 @@ # Released subject to the BSD License # See http://www.voidspace.org.uk/python/license.shtml +# Updated by django-helpdesk developers, 2018 +# to be compatible with python 3 + """ A python interface to the `Akismet `_ API. @@ -56,7 +59,10 @@ Usage example:: import os -from urllib import urlencode +try: + from urllib import urlencode # python2 +except ImportError: + from urllib.parse import urlencode # python3 import socket if hasattr(socket, 'setdefaulttimeout'): From 2cf1a32a10712b985ec5d1edd3204d9e48566f5f Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Thu, 10 May 2018 01:42:09 -0400 Subject: [PATCH 04/15] Fix deprecated escape sequence warning for Py3.7, ignore W503,504 --- .travis.yml | 2 +- helpdesk/management/commands/get_email.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8827ddbb..06a155b6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ install: - pip install -q -r requirements-testing.txt before_script: - - "pycodestyle --exclude=migrations --ignore=E501 helpdesk" + - "pycodestyle --exclude=migrations --ignore=E501,W503,W504 helpdesk" script: - coverage run --source='.' quicktest.py helpdesk diff --git a/helpdesk/management/commands/get_email.py b/helpdesk/management/commands/get_email.py index f9fb7392..5ae13079 100755 --- a/helpdesk/management/commands/get_email.py +++ b/helpdesk/management/commands/get_email.py @@ -332,7 +332,7 @@ def ticket_from_message(message, queue, logger): return False return True - matchobj = re.match(r".*\[" + queue.slug + "-(?P\d+)\]", subject) + matchobj = re.match(r".*\[" + queue.slug + r"-(?P\d+)\]", subject) if matchobj: # This is a reply or forward. ticket = matchobj.group('id') From c3bf39a3b938f79fbeb82f94ed38f5820fec7c5f Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Thu, 10 May 2018 02:14:59 -0400 Subject: [PATCH 05/15] Fix bad URL when canceling query deletion, to address #615 --- .../templates/helpdesk/confirm_delete_saved_query.html | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/helpdesk/templates/helpdesk/confirm_delete_saved_query.html b/helpdesk/templates/helpdesk/confirm_delete_saved_query.html index 61cfa871..c5dc7099 100644 --- a/helpdesk/templates/helpdesk/confirm_delete_saved_query.html +++ b/helpdesk/templates/helpdesk/confirm_delete_saved_query.html @@ -11,12 +11,11 @@

{% blocktrans %}You have shared this query, so other users may be using it. If you delete it, they will have to manually create their own query.{% endblocktrans %}

{% endif %} +

-

- -
+{% csrf_token %} -{% csrf_token %}
+ {% endblock %} From 08fc9b5aac949711804117b5f858df9f5c12cdca Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Wed, 27 Jun 2018 02:10:20 -0400 Subject: [PATCH 06/15] Check format of DEFAULT_FROM_EMAIL before creating messages, to address #608 --- helpdesk/models.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/helpdesk/models.py b/helpdesk/models.py index fe413572..177574ce 100644 --- a/helpdesk/models.py +++ b/helpdesk/models.py @@ -17,6 +17,7 @@ from django.utils import timezone from django.utils import six from django.utils.translation import ugettext_lazy as _, ugettext from django.utils.encoding import python_2_unicode_compatible +import re @python_2_unicode_compatible @@ -278,7 +279,13 @@ class Queue(models.Model): in the sender name field, so hopefully the admin can see and fix it. """ if not self.email_address: - return u'NO QUEUE EMAIL ADDRESS DEFINED <%s>' % settings.DEFAULT_FROM_EMAIL + # must check if given in format "Foo " + default_email = re.match(".*<(?P.*@*.)>", settings.DEFAULT_FROM_EMAIL) + if default_email is not None: + # already in the right format, so just include it here + return u'NO QUEUE EMAIL ADDRESS DEFINED %s' % settings.DEFAULT_FROM_EMAIL + else: + return u'NO QUEUE EMAIL ADDRESS DEFINED <%s>' % settings.DEFAULT_FROM_EMAIL else: return u'%s <%s>' % (self.title, self.email_address) from_address = property(_from_address) From 15985e286fe857d249a9f0e5f724179937389fae Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Wed, 27 Jun 2018 02:27:24 -0400 Subject: [PATCH 07/15] Fix saved queries when running in Django 2.0+, for #613 --- helpdesk/views/staff.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py index 6578e24f..ac9a9af6 100644 --- a/helpdesk/views/staff.py +++ b/helpdesk/views/staff.py @@ -9,6 +9,7 @@ views/staff.py - The bulk of the application - provides most business logic and from __future__ import unicode_literals from datetime import datetime, timedelta +import django.VERSION as DJANGO_VERSION from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.decorators import user_passes_test @@ -831,7 +832,11 @@ def ticket_list(request): from helpdesk.lib import b64decode try: if six.PY3: - query_params = json.loads(b64decode(str(saved_query.query)).decode()) + if DJANGO_VERSION[0] > 1: + # if Django >= 2.0 + query_params = json.loads(b64decode(str(saved_query.query).lstrip("b\\'")).decode()) + else: + query_params = json.loads(b64decode(str(saved_query.query)).decode()) else: query_params = json.loads(b64decode(str(saved_query.query))) except ValueError: @@ -1138,7 +1143,11 @@ def run_report(request, report): from helpdesk.lib import b64decode try: if six.PY3: - query_params = json.loads(b64decode(str(saved_query.query)).decode()) + if DJANGO_VERSION[0] > 1: + # if Django >= 2.0 + query_params = json.loads(b64decode(str(saved_query.query).lstrip("b\\'")).decode()) + else: + query_params = json.loads(b64decode(str(saved_query.query)).decode()) else: query_params = json.loads(b64decode(str(saved_query.query))) except json.JSONDecodeError: From b40e9dd5ea6777df42f50ce7c79565456402fbe9 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Wed, 27 Jun 2018 02:37:35 -0400 Subject: [PATCH 08/15] Fix bug while importing django version for #613 --- helpdesk/views/staff.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py index ac9a9af6..df65955a 100644 --- a/helpdesk/views/staff.py +++ b/helpdesk/views/staff.py @@ -9,7 +9,7 @@ views/staff.py - The bulk of the application - provides most business logic and from __future__ import unicode_literals from datetime import datetime, timedelta -import django.VERSION as DJANGO_VERSION +from django import VERSION as DJANGO_VERSION from django.conf import settings from django.contrib.auth import get_user_model from django.contrib.auth.decorators import user_passes_test From fb196773835575cbbf13e7c8e8fb9a52f7842fe3 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Wed, 27 Jun 2018 02:44:13 -0400 Subject: [PATCH 09/15] Test against latest bugfix of django 1.11 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 06a155b6..caeaab63 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: - "3.6" env: - - DJANGO=1.11.9 + - DJANGO=1.11.13 install: - pip install -q Django==$DJANGO From fbe725a22faed0fa334af4d4cb9a701c73358059 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Wed, 27 Jun 2018 02:49:55 -0400 Subject: [PATCH 10/15] Correct old documentation for HELPDESK_ENABLE_PER_QUEUE_PERMISSION to HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION, for #611 --- docs/settings.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/settings.rst b/docs/settings.rst index 29c41aee..a337e9aa 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -211,4 +211,4 @@ The following settings were defined in previous versions and are no longer suppo - **HELPDESK_FOOTER_SHOW_CHANGE_LANGUAGE_LINK** Is never shown. Use your own template if required. -- **HELPDESK_ENABLE_PER_QUEUE_MEMBERSHIP** Discontinued in favor of HELPDESK_ENABLE_PER_QUEUE_PERMISSION. +- **HELPDESK_ENABLE_PER_QUEUE_MEMBERSHIP** Discontinued in favor of HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION. From d0cf8426d0c64b734309525716870a7c699a903d Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Mon, 2 Jul 2018 22:07:59 -0400 Subject: [PATCH 11/15] Add Due Date column to ticket list and in description table for individual ticket page --- helpdesk/templates/helpdesk/ticket_desc_table.html | 5 +++++ helpdesk/templates/helpdesk/ticket_list.html | 2 ++ 2 files changed, 7 insertions(+) diff --git a/helpdesk/templates/helpdesk/ticket_desc_table.html b/helpdesk/templates/helpdesk/ticket_desc_table.html index bf9281dc..fb46e4ce 100644 --- a/helpdesk/templates/helpdesk/ticket_desc_table.html +++ b/helpdesk/templates/helpdesk/ticket_desc_table.html @@ -38,6 +38,11 @@ {{ ticket.resolution|force_escape|urlizetrunc:50|linebreaksbr }} {% endif %} + + + {% trans "Due Date" %} + {{ ticket.due_date|date:"r" }} ({{ ticket.due_date|naturaltime }}) + {% trans "Submitted On" %} {{ ticket.created|date:"r" }} ({{ ticket.created|naturaltime }}) diff --git a/helpdesk/templates/helpdesk/ticket_list.html b/helpdesk/templates/helpdesk/ticket_list.html index 3a49b64f..82797318 100644 --- a/helpdesk/templates/helpdesk/ticket_list.html +++ b/helpdesk/templates/helpdesk/ticket_list.html @@ -223,6 +223,7 @@ $(document).ready(function() { {% trans "Queue" %} {% trans "Status" %} {% trans "Created" %} + {% trans "Due Date" %} {% trans "Owner" %} @@ -236,6 +237,7 @@ $(document).ready(function() { {{ ticket.queue }} {{ ticket.get_status }} {{ ticket.created|naturaltime }} + {{ ticket.due_date|naturaltime }} {{ ticket.get_assigned_to }} {% endfor %} From 4d78bc85cabbe657b752c7700103ce98171613ca Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Tue, 3 Jul 2018 00:20:51 -0400 Subject: [PATCH 12/15] Update due date correct when adding followup to ticket, for #616 --- helpdesk/templates/helpdesk/ticket.html | 1 + helpdesk/views/staff.py | 31 ++++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/helpdesk/templates/helpdesk/ticket.html b/helpdesk/templates/helpdesk/ticket.html index eb6de0bb..013fb362 100644 --- a/helpdesk/templates/helpdesk/ticket.html +++ b/helpdesk/templates/helpdesk/ticket.html @@ -214,6 +214,7 @@ $(document).on('change', ':file', function() {
+
{{ form.due_date }}
diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py index df65955a..a4454a89 100644 --- a/helpdesk/views/staff.py +++ b/helpdesk/views/staff.py @@ -7,7 +7,8 @@ views/staff.py - The bulk of the application - provides most business logic and renders all staff-facing views. """ from __future__ import unicode_literals -from datetime import datetime, timedelta +from datetime import date, datetime, timedelta +import re from django import VERSION as DJANGO_VERSION from django.conf import settings @@ -381,6 +382,10 @@ def update_ticket(request, ticket_id, public=False): (reverse('helpdesk:login'), request.path)) ticket = get_object_or_404(Ticket, id=ticket_id) + + date_re = re.compile( + r'(?P\d{1,2})/(?P\d{1,2})/(?P\d{4})$' + ) comment = request.POST.get('comment', '') new_status = int(request.POST.get('new_status', ticket.status)) @@ -391,15 +396,29 @@ def update_ticket(request, ticket_id, public=False): due_date_year = int(request.POST.get('due_date_year', 0)) due_date_month = int(request.POST.get('due_date_month', 0)) due_date_day = int(request.POST.get('due_date_day', 0)) + #NOTE: jQuery's default for dates is mm/dd/yy + # very US-centric but for now that's the only format supported + # until we clean up code to internationalize a little more + due_date = request.POST.get('due_date', None) - if not (due_date_year and due_date_month and due_date_day): - due_date = ticket.due_date + if due_date is not None: + # based on Django code to parse dates: + # https://docs.djangoproject.com/en/2.0/_modules/django/utils/dateparse/ + match = date_re.match(due_date) + if match: + kw = {k: int(v) for k, v in match.groupdict().items()} + due_date = date(**kw) else: - if ticket.due_date: + # old way, probably deprecated? + if not (due_date_year and due_date_month and due_date_day): due_date = ticket.due_date else: - due_date = timezone.now() - due_date = due_date.replace(due_date_year, due_date_month, due_date_day) + # NOTE: must be an easier way to create a new date than doing it this way? + if ticket.due_date: + due_date = ticket.due_date + else: + due_date = timezone.now() + due_date = due_date.replace(due_date_year, due_date_month, due_date_day) no_changes = all([ not request.FILES, From d1e57d70b0209934cf6b315cd5c5d8d68a01bcc8 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Tue, 3 Jul 2018 00:24:20 -0400 Subject: [PATCH 13/15] Use jQuery datepicker widget when editing a ticket, for comment part of #616 --- helpdesk/templates/helpdesk/edit_ticket.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/helpdesk/templates/helpdesk/edit_ticket.html b/helpdesk/templates/helpdesk/edit_ticket.html index a3087c99..cd2845ef 100644 --- a/helpdesk/templates/helpdesk/edit_ticket.html +++ b/helpdesk/templates/helpdesk/edit_ticket.html @@ -37,4 +37,11 @@ + + + {% endblock %} From fabac887efefcc41f1fedc076046c463dc73e5e2 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Tue, 3 Jul 2018 00:29:46 -0400 Subject: [PATCH 14/15] Bump version to 0.2.8 --- demo/setup.py | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/setup.py b/demo/setup.py index 88e9f0af..1e4fe3b9 100644 --- a/demo/setup.py +++ b/demo/setup.py @@ -13,7 +13,7 @@ project_root = os.path.dirname(here) NAME = 'django-helpdesk-demodesk' DESCRIPTION = 'A demo Django project using django-helpdesk' README = open(os.path.join(here, 'README.rst')).read() -VERSION = '0.2.7' +VERSION = '0.2.8' #VERSION = open(os.path.join(project_root, 'VERSION')).read().strip() AUTHOR = 'django-helpdesk team' URL = 'https://github.com/django-helpdesk/django-helpdesk' diff --git a/setup.py b/setup.py index ce8bf8c0..3f2ea321 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ from distutils.util import convert_path from fnmatch import fnmatchcase from setuptools import setup, find_packages -version = '0.2.7' +version = '0.2.8' # Provided as an attribute, so you can append to these instead # of replicating them: From 9cb32f83ca87ea43fbab94c3c39bbb9119f07c98 Mon Sep 17 00:00:00 2001 From: Garret Wassermann Date: Tue, 3 Jul 2018 00:32:23 -0400 Subject: [PATCH 15/15] Minor PEP8 changes --- helpdesk/views/staff.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py index a4454a89..b6bd433a 100644 --- a/helpdesk/views/staff.py +++ b/helpdesk/views/staff.py @@ -382,7 +382,7 @@ def update_ticket(request, ticket_id, public=False): (reverse('helpdesk:login'), request.path)) ticket = get_object_or_404(Ticket, id=ticket_id) - + date_re = re.compile( r'(?P\d{1,2})/(?P\d{1,2})/(?P\d{4})$' ) @@ -396,13 +396,13 @@ def update_ticket(request, ticket_id, public=False): due_date_year = int(request.POST.get('due_date_year', 0)) due_date_month = int(request.POST.get('due_date_month', 0)) due_date_day = int(request.POST.get('due_date_day', 0)) - #NOTE: jQuery's default for dates is mm/dd/yy + # NOTE: jQuery's default for dates is mm/dd/yy # very US-centric but for now that's the only format supported # until we clean up code to internationalize a little more due_date = request.POST.get('due_date', None) if due_date is not None: - # based on Django code to parse dates: + # based on Django code to parse dates: # https://docs.djangoproject.com/en/2.0/_modules/django/utils/dateparse/ match = date_re.match(due_date) if match: