mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2024-11-25 01:13:31 +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.
|
||||
"""
|
||||
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):
|
||||
@ -81,7 +85,7 @@ def apply_query(queryset, params):
|
||||
filter = {key: params['filtering'][key]}
|
||||
queryset = queryset.filter(**filter)
|
||||
|
||||
search = params.get('search_string', None)
|
||||
search = params.get('search_string', '')
|
||||
if search:
|
||||
qset = (
|
||||
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
|
||||
filtered list. The `draw`, `length` etc parameters are for datatables to
|
||||
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])
|
||||
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()
|
||||
assigned_to = serializers.SerializerMethodField()
|
||||
created = serializers.SerializerMethodField()
|
||||
|
@ -4,7 +4,7 @@
|
||||
<label for='id_query'>{% trans "Keywords" %}</label>
|
||||
</div>
|
||||
<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 class="col col-sm-6">
|
||||
<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'>
|
||||
{% include './filters/date.html' %}
|
||||
</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' %}
|
||||
</li>
|
||||
</ul>
|
||||
@ -342,7 +342,7 @@
|
||||
{% if query_params.filtering.created__gte or query_params.filtering.created__lte %}
|
||||
$("#filterBuilderSelect-Dates")[0].disabled = "disabled";
|
||||
{% endif %}
|
||||
{% if query %}
|
||||
{% if query_params.search_string %}
|
||||
$("#filterBuilderSelect-Keywords")[0].disabled = "disabled";
|
||||
{% endif %}
|
||||
});
|
||||
|
@ -7,6 +7,7 @@ views/staff.py - The bulk of the application - provides most business logic and
|
||||
renders all staff-facing views.
|
||||
"""
|
||||
from copy import deepcopy
|
||||
import json
|
||||
|
||||
from django import VERSION as DJANGO_VERSION
|
||||
from django.conf import settings
|
||||
@ -26,8 +27,9 @@ from django.utils import timezone
|
||||
from django.views.generic.edit import FormView, UpdateView
|
||||
from django.core.cache import cache
|
||||
|
||||
from helpdesk.lib import query_tickets_by_args
|
||||
from helpdesk.serializers import TicketSerializer
|
||||
from helpdesk.lib import query_tickets_by_args, query_to_base64, query_from_base64
|
||||
|
||||
from helpdesk.serializers import DatatablesTicketSerializer
|
||||
|
||||
from helpdesk.decorators import (
|
||||
helpdesk_staff_member_required, helpdesk_superuser_required,
|
||||
@ -838,16 +840,15 @@ def ticket_list(request):
|
||||
'filtering': {},
|
||||
'sorting': None,
|
||||
'sortreverse': False,
|
||||
'keyword': None,
|
||||
'search_string': None,
|
||||
'search_string': '',
|
||||
}
|
||||
default_query_params = {
|
||||
'filtering': {'status__in': [1, 2, 3]},
|
||||
'sorting': 'created',
|
||||
'search_string': '',
|
||||
'sortreverse': False,
|
||||
}
|
||||
|
||||
from_saved_query = False
|
||||
|
||||
# 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
|
||||
# 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
|
||||
pass
|
||||
|
||||
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: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)
|
||||
saved_query, query_params = load_saved_query(request, query_params)
|
||||
except QueryLoadError:
|
||||
return HttpResponseRedirect(reverse('helpdesk:list'))
|
||||
|
||||
if saved_query:
|
||||
pass
|
||||
elif not {'queue', 'assigned_to', 'status', 'q', 'sort', 'sortreverse'}.intersection(request.GET):
|
||||
# Fall-back if no querying is being done
|
||||
all_queues = Queue.objects.all()
|
||||
@ -932,10 +919,8 @@ def ticket_list(request):
|
||||
query_params['filtering']['created__lte'] = date_to
|
||||
|
||||
# KEYWORD SEARCHING
|
||||
q = request.GET.get('q', None)
|
||||
|
||||
if q:
|
||||
context = dict(context, query=q)
|
||||
q = request.GET.get('q', '')
|
||||
context['query'] = q
|
||||
query_params['search_string'] = q
|
||||
|
||||
# SORTING
|
||||
@ -955,8 +940,14 @@ def ticket_list(request):
|
||||
# invalid parameters in query, return default query
|
||||
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 = ''
|
||||
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 = _(
|
||||
'<p><strong>Note:</strong> Your keyword search is case sensitive '
|
||||
'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">'
|
||||
'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(
|
||||
context,
|
||||
@ -982,7 +966,7 @@ def ticket_list(request):
|
||||
urlsafe_query=urlsafe_query,
|
||||
user_saved_queries=user_saved_queries,
|
||||
query_params=query_params,
|
||||
from_saved_query=from_saved_query,
|
||||
from_saved_query=saved_query is not None,
|
||||
saved_query=saved_query,
|
||||
search_message=search_message,
|
||||
))
|
||||
@ -991,18 +975,43 @@ def ticket_list(request):
|
||||
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
|
||||
@api_view(['GET', 'POST'])
|
||||
@api_view(['GET'])
|
||||
def datatables_ticket_list(request):
|
||||
"""
|
||||
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
|
||||
"""
|
||||
try:
|
||||
objects = cache.get('ticket_qs')
|
||||
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['data'] = serializer.data
|
||||
result['draw'] = model_object['draw']
|
||||
@ -1188,28 +1197,12 @@ def run_report(request, report):
|
||||
queue__in=_get_user_queues(request.user)
|
||||
)
|
||||
|
||||
from_saved_query = False
|
||||
saved_query = None
|
||||
try:
|
||||
saved_query, query_params = load_saved_query(request)
|
||||
except QueryLoadError:
|
||||
return HttpResponseRedirect(reverse('helpdesk:report_index'))
|
||||
|
||||
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)
|
||||
|
||||
from collections import defaultdict
|
||||
@ -1372,7 +1365,7 @@ def run_report(request, report):
|
||||
'headings': column_headings,
|
||||
'series_names': series_names,
|
||||
'morrisjs_data': morrisjs_data,
|
||||
'from_saved_query': from_saved_query,
|
||||
'from_saved_query': saved_query is not None,
|
||||
'saved_query': saved_query,
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user