mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-22 16:03:19 +01:00
Merge 0.2.8 bugfixes
This commit is contained in:
commit
dff14d40d3
@ -7,7 +7,7 @@ python:
|
|||||||
- "3.6"
|
- "3.6"
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- DJANGO=1.11.9
|
- DJANGO=1.11.13
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- pip install -q Django==$DJANGO
|
- pip install -q Django==$DJANGO
|
||||||
@ -15,7 +15,7 @@ install:
|
|||||||
- pip install -q -r requirements-testing.txt
|
- pip install -q -r requirements-testing.txt
|
||||||
|
|
||||||
before_script:
|
before_script:
|
||||||
- "pycodestyle --exclude=migrations --ignore=E501 helpdesk"
|
- "pycodestyle --exclude=migrations --ignore=E501,W503,W504 helpdesk"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- coverage run --source='.' quicktest.py helpdesk
|
- coverage run --source='.' quicktest.py helpdesk
|
||||||
|
@ -19,11 +19,9 @@ AUTHOR = 'django-helpdesk team'
|
|||||||
URL = 'https://github.com/django-helpdesk/django-helpdesk'
|
URL = 'https://github.com/django-helpdesk/django-helpdesk'
|
||||||
CLASSIFIERS = ['Development Status :: 4 - Beta',
|
CLASSIFIERS = ['Development Status :: 4 - Beta',
|
||||||
'License :: OSI Approved :: BSD License',
|
'License :: OSI Approved :: BSD License',
|
||||||
'Programming Language :: Python :: 2.7',
|
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.5',
|
||||||
'Programming Language :: Python :: 3.6',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Framework :: Django :: 1.11',
|
|
||||||
'Framework :: Django :: 2.0']
|
'Framework :: Django :: 2.0']
|
||||||
KEYWORDS = []
|
KEYWORDS = []
|
||||||
PACKAGES = ['demodesk']
|
PACKAGES = ['demodesk']
|
||||||
|
@ -215,4 +215,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_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.
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
# Released subject to the BSD License
|
# Released subject to the BSD License
|
||||||
# See http://www.voidspace.org.uk/python/license.shtml
|
# 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 <http://akismet.com>`_ API.
|
A python interface to the `Akismet <http://akismet.com>`_ API.
|
||||||
@ -56,7 +59,10 @@ Usage example::
|
|||||||
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from urllib import urlencode
|
try:
|
||||||
|
from urllib import urlencode # python2
|
||||||
|
except ImportError:
|
||||||
|
from urllib.parse import urlencode # python3
|
||||||
|
|
||||||
import socket
|
import socket
|
||||||
if hasattr(socket, 'setdefaulttimeout'):
|
if hasattr(socket, 'setdefaulttimeout'):
|
||||||
|
@ -216,7 +216,7 @@ def process_queue(q, logger):
|
|||||||
q.email_box_pass or
|
q.email_box_pass or
|
||||||
settings.QUEUE_EMAIL_BOX_PASSWORD)
|
settings.QUEUE_EMAIL_BOX_PASSWORD)
|
||||||
server.select(q.email_box_imap_folder)
|
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.")
|
logger.error("IMAP login failed. Check that the server is accessible and that the username and password are correct.")
|
||||||
server.logout()
|
server.logout()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
@ -332,7 +332,7 @@ def ticket_from_message(message, queue, logger):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
matchobj = re.match(r".*\[" + queue.slug + "-(?P<id>\d+)\]", subject)
|
matchobj = re.match(r".*\[" + queue.slug + r"-(?P<id>\d+)\]", subject)
|
||||||
if matchobj:
|
if matchobj:
|
||||||
# This is a reply or forward.
|
# This is a reply or forward.
|
||||||
ticket = matchobj.group('id')
|
ticket = matchobj.group('id')
|
||||||
|
@ -17,6 +17,7 @@ from django.utils import timezone
|
|||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils.translation import ugettext_lazy as _, ugettext
|
from django.utils.translation import ugettext_lazy as _, ugettext
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
import re
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
@ -279,6 +280,12 @@ class Queue(models.Model):
|
|||||||
in the sender name field, so hopefully the admin can see and fix it.
|
in the sender name field, so hopefully the admin can see and fix it.
|
||||||
"""
|
"""
|
||||||
if not self.email_address:
|
if not self.email_address:
|
||||||
|
# must check if given in format "Foo <foo@example.com>"
|
||||||
|
default_email = re.match(".*<(?P<email>.*@*.)>", 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
|
return u'NO QUEUE EMAIL ADDRESS DEFINED <%s>' % settings.DEFAULT_FROM_EMAIL
|
||||||
else:
|
else:
|
||||||
return u'%s <%s>' % (self.title, self.email_address)
|
return u'%s <%s>' % (self.title, self.email_address)
|
||||||
|
@ -11,12 +11,11 @@
|
|||||||
<p>{% 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 %}</p>
|
<p>{% 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 %}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<p><a href='{% url 'helpdesk:list' %}?saved_query={{ query.id }}'><button class="btn btn-primary btn-lg">{% trans "No, Don't Delete It" %}</button></a></p>
|
||||||
|
|
||||||
<p><a href='../'><button class="btn btn-primary btn-lg">{% trans "No, Don't Delete It" %}</button></a></p>
|
<form method='post' action='./'>{% csrf_token %}
|
||||||
|
|
||||||
<form method='post' action='./'>
|
|
||||||
<button class="btn btn-danger" type='submit'>{% trans "Yes I Understand - Delete It Anyway" %}</button>
|
<button class="btn btn-danger" type='submit'>{% trans "Yes I Understand - Delete It Anyway" %}</button>
|
||||||
{% csrf_token %}</form>
|
</form>
|
||||||
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -37,4 +37,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
$( function() {
|
||||||
|
$( "#id_due_date" ).datepicker();
|
||||||
|
} );
|
||||||
|
</script>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -214,6 +214,7 @@ $(document).on('change', ':file', function() {
|
|||||||
|
|
||||||
<dt><label for='id_priority'>{% trans "Priority" %}</label></dt>
|
<dt><label for='id_priority'>{% trans "Priority" %}</label></dt>
|
||||||
<dd><select id='id_priority' name='priority'>{% for p in priorities %}<option value='{{ p.0 }}'{% ifequal p.0 ticket.priority %} selected='selected'{% endifequal %}>{{ p.1 }}</option>{% endfor %}</select></dd>
|
<dd><select id='id_priority' name='priority'>{% for p in priorities %}<option value='{{ p.0 }}'{% ifequal p.0 ticket.priority %} selected='selected'{% endifequal %}>{{ p.1 }}</option>{% endfor %}</select></dd>
|
||||||
|
|
||||||
<dt><label for='id_due_date'>{% trans "Due on" %}</label></dt>
|
<dt><label for='id_due_date'>{% trans "Due on" %}</label></dt>
|
||||||
<dd>{{ form.due_date }}</dd>
|
<dd>{{ form.due_date }}</dd>
|
||||||
|
|
||||||
|
@ -38,6 +38,11 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td colspan='2'>{{ ticket.resolution|force_escape|urlizetrunc:50|linebreaksbr }}</td>
|
<td colspan='2'>{{ ticket.resolution|force_escape|urlizetrunc:50|linebreaksbr }}</td>
|
||||||
</tr>{% endif %}
|
</tr>{% endif %}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Due Date" %}</th>
|
||||||
|
<td>{{ ticket.due_date|date:"r" }} ({{ ticket.due_date|naturaltime }})</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{% trans "Submitted On" %}</th>
|
<th>{% trans "Submitted On" %}</th>
|
||||||
<td>{{ ticket.created|date:"r" }} ({{ ticket.created|naturaltime }})</td>
|
<td>{{ ticket.created|date:"r" }} ({{ ticket.created|naturaltime }})</td>
|
||||||
|
@ -223,6 +223,7 @@ $(document).ready(function() {
|
|||||||
<th>{% trans "Queue" %}</th>
|
<th>{% trans "Queue" %}</th>
|
||||||
<th>{% trans "Status" %}</th>
|
<th>{% trans "Status" %}</th>
|
||||||
<th>{% trans "Created" %}</th>
|
<th>{% trans "Created" %}</th>
|
||||||
|
<th>{% trans "Due Date" %}</th>
|
||||||
<th>{% trans "Owner" %}</th>
|
<th>{% trans "Owner" %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -236,6 +237,7 @@ $(document).ready(function() {
|
|||||||
<td>{{ ticket.queue }}</td>
|
<td>{{ ticket.queue }}</td>
|
||||||
<td>{{ ticket.get_status }}</td>
|
<td>{{ ticket.get_status }}</td>
|
||||||
<td data-order='{{ ticket.created|date:"U" }}'><span title='{{ ticket.created|date:"r" }}'>{{ ticket.created|naturaltime }}</span></td>
|
<td data-order='{{ ticket.created|date:"U" }}'><span title='{{ ticket.created|date:"r" }}'>{{ ticket.created|naturaltime }}</span></td>
|
||||||
|
<td data-order='{{ ticket.due_date|date:"U" }}'><span title='{{ ticket.due_date|date:"r" }}'>{{ ticket.due_date|naturaltime }}</span></td>
|
||||||
<td>{{ ticket.get_assigned_to }}</td>
|
<td>{{ ticket.get_assigned_to }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -7,8 +7,10 @@ views/staff.py - The bulk of the application - provides most business logic and
|
|||||||
renders all staff-facing views.
|
renders all staff-facing views.
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
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
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
@ -155,21 +157,6 @@ def dashboard(request):
|
|||||||
else:
|
else:
|
||||||
where_clause = """WHERE q.id = t.queue_id"""
|
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', {
|
return render(request, 'helpdesk/dashboard.html', {
|
||||||
'user_tickets': tickets,
|
'user_tickets': tickets,
|
||||||
'user_tickets_closed_resolved': tickets_closed_resolved,
|
'user_tickets_closed_resolved': tickets_closed_resolved,
|
||||||
@ -404,6 +391,10 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
|
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
|
|
||||||
|
date_re = re.compile(
|
||||||
|
r'(?P<month>\d{1,2})/(?P<day>\d{1,2})/(?P<year>\d{4})$'
|
||||||
|
)
|
||||||
|
|
||||||
comment = request.POST.get('comment', '')
|
comment = request.POST.get('comment', '')
|
||||||
new_status = int(request.POST.get('new_status', ticket.status))
|
new_status = int(request.POST.get('new_status', ticket.status))
|
||||||
title = request.POST.get('title', '')
|
title = request.POST.get('title', '')
|
||||||
@ -413,10 +404,24 @@ def update_ticket(request, ticket_id, public=False):
|
|||||||
due_date_year = int(request.POST.get('due_date_year', 0))
|
due_date_year = int(request.POST.get('due_date_year', 0))
|
||||||
due_date_month = int(request.POST.get('due_date_month', 0))
|
due_date_month = int(request.POST.get('due_date_month', 0))
|
||||||
due_date_day = int(request.POST.get('due_date_day', 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 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:
|
||||||
|
# old way, probably deprecated?
|
||||||
if not (due_date_year and due_date_month and due_date_day):
|
if not (due_date_year and due_date_month and due_date_day):
|
||||||
due_date = ticket.due_date
|
due_date = ticket.due_date
|
||||||
else:
|
else:
|
||||||
|
# NOTE: must be an easier way to create a new date than doing it this way?
|
||||||
if ticket.due_date:
|
if ticket.due_date:
|
||||||
due_date = ticket.due_date
|
due_date = ticket.due_date
|
||||||
else:
|
else:
|
||||||
@ -859,6 +864,10 @@ def ticket_list(request):
|
|||||||
from helpdesk.lib import b64decode
|
from helpdesk.lib import b64decode
|
||||||
try:
|
try:
|
||||||
if six.PY3:
|
if six.PY3:
|
||||||
|
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())
|
query_params = json.loads(b64decode(str(saved_query.query)).decode())
|
||||||
else:
|
else:
|
||||||
query_params = json.loads(b64decode(str(saved_query.query)))
|
query_params = json.loads(b64decode(str(saved_query.query)))
|
||||||
@ -1123,31 +1132,18 @@ def report_index(request):
|
|||||||
# Open Resolved
|
# Open Resolved
|
||||||
# Queue 1 10 4
|
# Queue 1 10 4
|
||||||
# Queue 2 4 12
|
# 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)
|
dash_tickets = []
|
||||||
|
for queue in Queues:
|
||||||
from_clause = """FROM helpdesk_ticket t,
|
dash_ticket = {
|
||||||
helpdesk_queue q"""
|
'queue': queue.id,
|
||||||
if queues:
|
'name': queue.title,
|
||||||
where_clause = """WHERE q.id = t.queue_id AND
|
'open': queue.ticket_set.filter(status__in=[1, 2]).count(),
|
||||||
q.id IN (%s)""" % (",".join(("%d" % pk for pk in queues)))
|
'resolved': queue.ticket_set.filter(status=3).count(),
|
||||||
else:
|
'closed': queue.ticket_set.filter(status=4).count(),
|
||||||
where_clause = """WHERE q.id = t.queue_id"""
|
}
|
||||||
|
dash_tickets.append(dash_ticket)
|
||||||
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/report_index.html', {
|
return render(request, 'helpdesk/report_index.html', {
|
||||||
'number_tickets': number_tickets,
|
'number_tickets': number_tickets,
|
||||||
@ -1187,6 +1183,10 @@ def run_report(request, report):
|
|||||||
from helpdesk.lib import b64decode
|
from helpdesk.lib import b64decode
|
||||||
try:
|
try:
|
||||||
if six.PY3:
|
if six.PY3:
|
||||||
|
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())
|
query_params = json.loads(b64decode(str(saved_query.query)).decode())
|
||||||
else:
|
else:
|
||||||
query_params = json.loads(b64decode(str(saved_query.query)))
|
query_params = json.loads(b64decode(str(saved_query.query)))
|
||||||
|
3
setup.py
3
setup.py
@ -128,14 +128,11 @@ setup(
|
|||||||
classifiers=[
|
classifiers=[
|
||||||
"Development Status :: 4 - Beta",
|
"Development Status :: 4 - Beta",
|
||||||
"Programming Language :: Python",
|
"Programming Language :: Python",
|
||||||
"Programming Language :: Python :: 2",
|
|
||||||
"Programming Language :: Python :: 2.7",
|
|
||||||
"Programming Language :: Python :: 3",
|
"Programming Language :: Python :: 3",
|
||||||
"Programming Language :: Python :: 3.4",
|
"Programming Language :: Python :: 3.4",
|
||||||
"Programming Language :: Python :: 3.5",
|
"Programming Language :: Python :: 3.5",
|
||||||
"Programming Language :: Python :: 3.6",
|
"Programming Language :: Python :: 3.6",
|
||||||
"Framework :: Django",
|
"Framework :: Django",
|
||||||
"Framework :: Django :: 1.11",
|
|
||||||
"Framework :: Django :: 2.0",
|
"Framework :: Django :: 2.0",
|
||||||
"Environment :: Web Environment",
|
"Environment :: Web Environment",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
|
Loading…
Reference in New Issue
Block a user