mirror of
https://github.com/django-helpdesk/django-helpdesk.git
synced 2025-01-31 10:29:15 +01:00
Refactor ticket list code
This commit is contained in:
parent
b862732512
commit
03d1c66dd6
@ -38,7 +38,11 @@ def query_from_base64(b64data):
|
|||||||
"""
|
"""
|
||||||
Converts base64-encoded bytes object back to a query dict object.
|
Converts base64-encoded bytes object back to a query dict object.
|
||||||
"""
|
"""
|
||||||
return json.loads(b64decode(b64data).decode('utf-8'))
|
query = {'search_string': ''}
|
||||||
|
query.update(json.loads(b64decode(b64data).decode('utf-8')))
|
||||||
|
if query['search_string'] is None:
|
||||||
|
query['search_string'] = ''
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
def query_to_dict(results, descriptions):
|
def query_to_dict(results, descriptions):
|
||||||
@ -81,7 +85,7 @@ def apply_query(queryset, params):
|
|||||||
filter = {key: params['filtering'][key]}
|
filter = {key: params['filtering'][key]}
|
||||||
queryset = queryset.filter(**filter)
|
queryset = queryset.filter(**filter)
|
||||||
|
|
||||||
search = params.get('search_string', None)
|
search = params.get('search_string', '')
|
||||||
if search:
|
if search:
|
||||||
qset = (
|
qset = (
|
||||||
Q(title__icontains=search) |
|
Q(title__icontains=search) |
|
||||||
@ -257,7 +261,7 @@ def query_tickets_by_args(objects, order_by, **kwargs):
|
|||||||
function filters existing dataset on search string and returns a filtered
|
function filters existing dataset on search string and returns a filtered
|
||||||
filtered list. The `draw`, `length` etc parameters are for datatables to
|
filtered list. The `draw`, `length` etc parameters are for datatables to
|
||||||
display meta data on the table contents. The returning queryset is passed
|
display meta data on the table contents. The returning queryset is passed
|
||||||
to a Serializer called TicketSerializer in serializers.py.
|
to a Serializer called DatatablesTicketSerializer in serializers.py.
|
||||||
"""
|
"""
|
||||||
draw = int(kwargs.get('draw', None)[0])
|
draw = int(kwargs.get('draw', None)[0])
|
||||||
length = int(kwargs.get('length', None)[0])
|
length = int(kwargs.get('length', None)[0])
|
||||||
|
@ -12,7 +12,7 @@ datatables for ticket_list.html. Called from staff.datatables_ticket_list.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TicketSerializer(serializers.ModelSerializer):
|
class DatatablesTicketSerializer(serializers.ModelSerializer):
|
||||||
ticket = serializers.SerializerMethodField()
|
ticket = serializers.SerializerMethodField()
|
||||||
assigned_to = serializers.SerializerMethodField()
|
assigned_to = serializers.SerializerMethodField()
|
||||||
created = serializers.SerializerMethodField()
|
created = serializers.SerializerMethodField()
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<label for='id_query'>{% trans "Keywords" %}</label>
|
<label for='id_query'>{% trans "Keywords" %}</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-sm-3">
|
<div class="col col-sm-3">
|
||||||
<input type='text' name='q' value='{{ query }}' id='id_query' />
|
<input type='text' name='q' value='{{ query_params.search_string }}' id='id_query' />
|
||||||
</div>
|
</div>
|
||||||
<div class="col col-sm-6">
|
<div class="col col-sm-6">
|
||||||
<button class='filterBuilderRemove btn btn-danger btn-sm float-right'><i class="fas fa-trash-alt"></i></button>
|
<button class='filterBuilderRemove btn btn-danger btn-sm float-right'><i class="fas fa-trash-alt"></i></button>
|
||||||
|
@ -84,7 +84,7 @@
|
|||||||
<li class="list-group-item filterBox{% if query_params.filtering.created__gte or query_params.filtering.created__lte %} filterBoxShow{% endif %}" id='filterBoxDates'>
|
<li class="list-group-item filterBox{% if query_params.filtering.created__gte or query_params.filtering.created__lte %} filterBoxShow{% endif %}" id='filterBoxDates'>
|
||||||
{% include './filters/date.html' %}
|
{% include './filters/date.html' %}
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item filterBox{% if query %} filterBoxShow{% endif %}" id="filterBoxKeywords">
|
<li class="list-group-item filterBox{% if query_params.search_string %} filterBoxShow{% endif %}" id="filterBoxKeywords">
|
||||||
{% include './filters/keywords.html' %}
|
{% include './filters/keywords.html' %}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -342,7 +342,7 @@
|
|||||||
{% if query_params.filtering.created__gte or query_params.filtering.created__lte %}
|
{% if query_params.filtering.created__gte or query_params.filtering.created__lte %}
|
||||||
$("#filterBuilderSelect-Dates")[0].disabled = "disabled";
|
$("#filterBuilderSelect-Dates")[0].disabled = "disabled";
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if query %}
|
{% if query_params.search_string %}
|
||||||
$("#filterBuilderSelect-Keywords")[0].disabled = "disabled";
|
$("#filterBuilderSelect-Keywords")[0].disabled = "disabled";
|
||||||
{% endif %}
|
{% endif %}
|
||||||
});
|
});
|
||||||
|
@ -7,6 +7,7 @@ views/staff.py - The bulk of the application - provides most business logic and
|
|||||||
renders all staff-facing views.
|
renders all staff-facing views.
|
||||||
"""
|
"""
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
import json
|
||||||
|
|
||||||
from django import VERSION as DJANGO_VERSION
|
from django import VERSION as DJANGO_VERSION
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -26,8 +27,9 @@ from django.utils import timezone
|
|||||||
from django.views.generic.edit import FormView, UpdateView
|
from django.views.generic.edit import FormView, UpdateView
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
|
|
||||||
from helpdesk.lib import query_tickets_by_args
|
from helpdesk.lib import query_tickets_by_args, query_to_base64, query_from_base64
|
||||||
from helpdesk.serializers import TicketSerializer
|
|
||||||
|
from helpdesk.serializers import DatatablesTicketSerializer
|
||||||
|
|
||||||
from helpdesk.decorators import (
|
from helpdesk.decorators import (
|
||||||
helpdesk_staff_member_required, helpdesk_superuser_required,
|
helpdesk_staff_member_required, helpdesk_superuser_required,
|
||||||
@ -838,16 +840,15 @@ def ticket_list(request):
|
|||||||
'filtering': {},
|
'filtering': {},
|
||||||
'sorting': None,
|
'sorting': None,
|
||||||
'sortreverse': False,
|
'sortreverse': False,
|
||||||
'keyword': None,
|
'search_string': '',
|
||||||
'search_string': None,
|
|
||||||
}
|
}
|
||||||
default_query_params = {
|
default_query_params = {
|
||||||
'filtering': {'status__in': [1, 2, 3]},
|
'filtering': {'status__in': [1, 2, 3]},
|
||||||
'sorting': 'created',
|
'sorting': 'created',
|
||||||
|
'search_string': '',
|
||||||
|
'sortreverse': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
from_saved_query = False
|
|
||||||
|
|
||||||
# If the user is coming from the header/navigation search box, lets' first
|
# If the user is coming from the header/navigation search box, lets' first
|
||||||
# look at their query to see if they have entered a valid ticket number. If
|
# look at their query to see if they have entered a valid ticket number. If
|
||||||
# they have, just redirect to that ticket number. Otherwise, we treat it as
|
# they have, just redirect to that ticket number. Otherwise, we treat it as
|
||||||
@ -882,27 +883,13 @@ def ticket_list(request):
|
|||||||
# Go on to standard keyword searching
|
# Go on to standard keyword searching
|
||||||
pass
|
pass
|
||||||
|
|
||||||
saved_query = None
|
try:
|
||||||
if request.GET.get('saved_query', None):
|
saved_query, query_params = load_saved_query(request, query_params)
|
||||||
from_saved_query = True
|
except QueryLoadError:
|
||||||
try:
|
return HttpResponseRedirect(reverse('helpdesk:list'))
|
||||||
saved_query = SavedSearch.objects.get(pk=request.GET.get('saved_query'))
|
|
||||||
except SavedSearch.DoesNotExist:
|
|
||||||
return HttpResponseRedirect(reverse('helpdesk:list'))
|
|
||||||
if not (saved_query.shared or saved_query.user == request.user):
|
|
||||||
return HttpResponseRedirect(reverse('helpdesk:list'))
|
|
||||||
|
|
||||||
import json
|
|
||||||
from helpdesk.lib import query_from_base64
|
|
||||||
try:
|
|
||||||
# we get a string like: b'stuff'
|
|
||||||
# so leave of the first two chars (b') and last (')
|
|
||||||
b64query = saved_query.query[2:-1]
|
|
||||||
query_params = query_from_base64(b64query)
|
|
||||||
except ValueError:
|
|
||||||
# Query deserialization failed. (E.g. was a pickled query)
|
|
||||||
return HttpResponseRedirect(reverse('helpdesk:list'))
|
|
||||||
|
|
||||||
|
if saved_query:
|
||||||
|
pass
|
||||||
elif not {'queue', 'assigned_to', 'status', 'q', 'sort', 'sortreverse'}.intersection(request.GET):
|
elif not {'queue', 'assigned_to', 'status', 'q', 'sort', 'sortreverse'}.intersection(request.GET):
|
||||||
# Fall-back if no querying is being done
|
# Fall-back if no querying is being done
|
||||||
all_queues = Queue.objects.all()
|
all_queues = Queue.objects.all()
|
||||||
@ -932,11 +919,9 @@ def ticket_list(request):
|
|||||||
query_params['filtering']['created__lte'] = date_to
|
query_params['filtering']['created__lte'] = date_to
|
||||||
|
|
||||||
# KEYWORD SEARCHING
|
# KEYWORD SEARCHING
|
||||||
q = request.GET.get('q', None)
|
q = request.GET.get('q', '')
|
||||||
|
context['query'] = q
|
||||||
if q:
|
query_params['search_string'] = q
|
||||||
context = dict(context, query=q)
|
|
||||||
query_params['search_string'] = q
|
|
||||||
|
|
||||||
# SORTING
|
# SORTING
|
||||||
sort = request.GET.get('sort', None)
|
sort = request.GET.get('sort', None)
|
||||||
@ -955,8 +940,14 @@ def ticket_list(request):
|
|||||||
# invalid parameters in query, return default query
|
# invalid parameters in query, return default query
|
||||||
ticket_qs = apply_query(tickets, default_query_params)
|
ticket_qs = apply_query(tickets, default_query_params)
|
||||||
|
|
||||||
|
urlsafe_query = query_to_base64(query_params)
|
||||||
|
|
||||||
|
cache.set('ticket_qs', ticket_qs)
|
||||||
|
|
||||||
|
user_saved_queries = SavedSearch.objects.filter(Q(user=request.user) | Q(shared__exact=True))
|
||||||
|
|
||||||
search_message = ''
|
search_message = ''
|
||||||
if 'query' in context and settings.DATABASES['default']['ENGINE'].endswith('sqlite'):
|
if query_params['search_string'] and settings.DATABASES['default']['ENGINE'].endswith('sqlite'):
|
||||||
search_message = _(
|
search_message = _(
|
||||||
'<p><strong>Note:</strong> Your keyword search is case sensitive '
|
'<p><strong>Note:</strong> Your keyword search is case sensitive '
|
||||||
'because of your database. This means the search will <strong>not</strong> '
|
'because of your database. This means the search will <strong>not</strong> '
|
||||||
@ -965,13 +956,6 @@ def ticket_list(request):
|
|||||||
'<a href="http://docs.djangoproject.com/en/dev/ref/databases/#sqlite-string-matching">'
|
'<a href="http://docs.djangoproject.com/en/dev/ref/databases/#sqlite-string-matching">'
|
||||||
'Django Documentation on string matching in SQLite</a>.')
|
'Django Documentation on string matching in SQLite</a>.')
|
||||||
|
|
||||||
import json
|
|
||||||
from helpdesk.lib import query_to_base64
|
|
||||||
urlsafe_query = query_to_base64(query_params)
|
|
||||||
|
|
||||||
user_saved_queries = SavedSearch.objects.filter(Q(user=request.user) | Q(shared__exact=True))
|
|
||||||
|
|
||||||
cache.set('ticket_qs', ticket_qs)
|
|
||||||
|
|
||||||
return render(request, 'helpdesk/ticket_list.html', dict(
|
return render(request, 'helpdesk/ticket_list.html', dict(
|
||||||
context,
|
context,
|
||||||
@ -982,7 +966,7 @@ def ticket_list(request):
|
|||||||
urlsafe_query=urlsafe_query,
|
urlsafe_query=urlsafe_query,
|
||||||
user_saved_queries=user_saved_queries,
|
user_saved_queries=user_saved_queries,
|
||||||
query_params=query_params,
|
query_params=query_params,
|
||||||
from_saved_query=from_saved_query,
|
from_saved_query=saved_query is not None,
|
||||||
saved_query=saved_query,
|
saved_query=saved_query,
|
||||||
search_message=search_message,
|
search_message=search_message,
|
||||||
))
|
))
|
||||||
@ -991,18 +975,43 @@ def ticket_list(request):
|
|||||||
ticket_list = staff_member_required(ticket_list)
|
ticket_list = staff_member_required(ticket_list)
|
||||||
|
|
||||||
|
|
||||||
|
class QueryLoadError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def load_saved_query(request, query_params=None):
|
||||||
|
saved_query = None
|
||||||
|
|
||||||
|
if request.GET.get('saved_query', None):
|
||||||
|
try:
|
||||||
|
saved_query = SavedSearch.objects.get(pk=request.GET.get('saved_query'))
|
||||||
|
except SavedSearch.DoesNotExist:
|
||||||
|
raise QueryLoadError()
|
||||||
|
if not (saved_query.shared or saved_query.user == request.user):
|
||||||
|
raise QueryLoadError()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# we get a string like: b'stuff'
|
||||||
|
# so leave of the first two chars (b') and last (')
|
||||||
|
b64query = saved_query.query[2:-1]
|
||||||
|
query_params = query_from_base64(b64query)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
raise QueryLoadError()
|
||||||
|
return (saved_query, query_params)
|
||||||
|
|
||||||
|
|
||||||
@helpdesk_staff_member_required
|
@helpdesk_staff_member_required
|
||||||
@api_view(['GET', 'POST'])
|
@api_view(['GET'])
|
||||||
def datatables_ticket_list(request):
|
def datatables_ticket_list(request):
|
||||||
"""
|
"""
|
||||||
Datatable on ticket_list.html uses this view from to get objects to display
|
Datatable on ticket_list.html uses this view from to get objects to display
|
||||||
on the table. query_tickets_by_args is at lib.py, TicketSerializer is in
|
on the table. query_tickets_by_args is at lib.py, DatatablesTicketSerializer is in
|
||||||
serializers.py. The serializers and this view use django-rest_framework methods
|
serializers.py. The serializers and this view use django-rest_framework methods
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
objects = cache.get('ticket_qs')
|
objects = cache.get('ticket_qs')
|
||||||
model_object = query_tickets_by_args(objects, '-date_created', **request.query_params)
|
model_object = query_tickets_by_args(objects, '-date_created', **request.query_params)
|
||||||
serializer = TicketSerializer(model_object['items'], many=True)
|
serializer = DatatablesTicketSerializer(model_object['items'], many=True)
|
||||||
result = dict()
|
result = dict()
|
||||||
result['data'] = serializer.data
|
result['data'] = serializer.data
|
||||||
result['draw'] = model_object['draw']
|
result['draw'] = model_object['draw']
|
||||||
@ -1188,28 +1197,12 @@ def run_report(request, report):
|
|||||||
queue__in=_get_user_queues(request.user)
|
queue__in=_get_user_queues(request.user)
|
||||||
)
|
)
|
||||||
|
|
||||||
from_saved_query = False
|
try:
|
||||||
saved_query = None
|
saved_query, query_params = load_saved_query(request)
|
||||||
|
except QueryLoadError:
|
||||||
|
return HttpResponseRedirect(reverse('helpdesk:report_index'))
|
||||||
|
|
||||||
if request.GET.get('saved_query', None):
|
if request.GET.get('saved_query', None):
|
||||||
from_saved_query = True
|
|
||||||
try:
|
|
||||||
saved_query = SavedSearch.objects.get(pk=request.GET.get('saved_query'))
|
|
||||||
except SavedSearch.DoesNotExist:
|
|
||||||
return HttpResponseRedirect(reverse('helpdesk:report_index'))
|
|
||||||
if not (saved_query.shared or saved_query.user == request.user):
|
|
||||||
return HttpResponseRedirect(reverse('helpdesk:report_index'))
|
|
||||||
|
|
||||||
import json
|
|
||||||
from helpdesk.lib import query_from_base64
|
|
||||||
try:
|
|
||||||
# we get a string like: b'stuff'
|
|
||||||
# so leave of the first two chars (b') and last (')
|
|
||||||
b64query = saved_query.query[2:-1]
|
|
||||||
query_params = query_from_base64(b64query)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
return HttpResponseRedirect(reverse('helpdesk:report_index'))
|
|
||||||
|
|
||||||
report_queryset = apply_query(report_queryset, query_params)
|
report_queryset = apply_query(report_queryset, query_params)
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
@ -1372,7 +1365,7 @@ def run_report(request, report):
|
|||||||
'headings': column_headings,
|
'headings': column_headings,
|
||||||
'series_names': series_names,
|
'series_names': series_names,
|
||||||
'morrisjs_data': morrisjs_data,
|
'morrisjs_data': morrisjs_data,
|
||||||
'from_saved_query': from_saved_query,
|
'from_saved_query': saved_query is not None,
|
||||||
'saved_query': saved_query,
|
'saved_query': saved_query,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user