Move query helper functions out of lib to special query file

This commit is contained in:
Timothy Hobbs 2019-10-11 16:31:52 +02:00
parent 0691bbabcd
commit 4ca6adbe39
3 changed files with 154 additions and 146 deletions

View File

@ -11,102 +11,15 @@ import mimetypes
import os
from django.conf import settings
from django.db.models import Q
from django.utils.encoding import smart_text, smart_str
from django.utils.safestring import mark_safe
from helpdesk.models import FollowUpAttachment, EmailTemplate
from model_utils import Choices
from base64 import b64encode
from base64 import b64decode
import json
logger = logging.getLogger('helpdesk')
def query_to_base64(query):
"""
Converts a query dict object to a base64-encoded bytes object.
"""
return b64encode(json.dumps(query).encode('UTF-8')).decode("ascii")
def query_from_base64(b64data):
"""
Converts base64-encoded bytes object back to a query dict object.
"""
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):
"""
Replacement method for cursor.dictfetchall() as that method no longer
exists in psycopg2, and I'm guessing in other backends too.
Converts the results of a raw SQL query into a list of dictionaries, suitable
for use in templates etc.
"""
output = []
for data in results:
row = {}
i = 0
for column in descriptions:
row[column[0]] = data[i]
i += 1
output.append(row)
return output
def apply_query(queryset, params):
"""
Apply a dict-based set of filters & parameters to a queryset.
queryset is a Django queryset, eg MyModel.objects.all() or
MyModel.objects.filter(user=request.user)
params is a dictionary that contains the following:
filtering: A dict of Django ORM filters, eg:
{'user__id__in': [1, 3, 103], 'title__contains': 'foo'}
search_string: A freetext search string
sorting: The name of the column to sort by
"""
for key in params['filtering'].keys():
filter = {key: params['filtering'][key]}
queryset = queryset.filter(**filter)
search = params.get('search_string', '')
if search:
qset = (
Q(title__icontains=search) |
Q(description__icontains=search) |
Q(resolution__icontains=search) |
Q(submitter_email__icontains=search) |
Q(ticketcustomfieldvalue__value__icontains=search)
)
queryset = queryset.filter(qset)
sorting = params.get('sorting', None)
if sorting:
sortreverse = params.get('sortreverse', None)
if sortreverse:
sorting = "-%s" % sorting
queryset = queryset.order_by(sorting)
return queryset
def ticket_template_context(ticket):
context = {}
@ -242,62 +155,6 @@ def process_attachments(followup, attached_files):
return attachments
ORDER_COLUMN_CHOICES = Choices(
('0', 'id'),
('2', 'priority'),
('3', 'title'),
('4', 'queue'),
('5', 'status'),
('6', 'created'),
('7', 'due_date'),
('8', 'assigned_to')
)
def query_tickets_by_args(objects, order_by, **kwargs):
"""
This function takes in a list of ticket objects from the views and throws it
to the datatables on ticket_list.html. If a search string was entered, this
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 DatatablesTicketSerializer in serializers.py.
"""
draw = int(kwargs.get('draw', None)[0])
length = int(kwargs.get('length', None)[0])
start = int(kwargs.get('start', None)[0])
search_value = kwargs.get('search[value]', None)[0]
order_column = kwargs.get('order[0][column]', None)[0]
order = kwargs.get('order[0][dir]', None)[0]
order_column = ORDER_COLUMN_CHOICES[order_column]
# django orm '-' -> desc
if order == 'desc':
order_column = '-' + order_column
queryset = objects.all().order_by(order_by)
total = queryset.count()
if search_value:
queryset = queryset.filter(Q(id__icontains=search_value) |
Q(priority__icontains=search_value) |
Q(title__icontains=search_value) |
Q(queue__title__icontains=search_value) |
Q(status__icontains=search_value) |
Q(created__icontains=search_value) |
Q(due_date__icontains=search_value) |
Q(assigned_to__email__icontains=search_value))
count = queryset.count()
queryset = queryset.order_by(order_column)[start:start + length]
return {
'items': queryset,
'count': count,
'total': total,
'draw': draw
}
def format_time_spent(time_spent):
"""Format time_spent attribute to "[H]HHh:MMm" text string to be allign in
all graphical outputs

143
helpdesk/query.py Normal file
View File

@ -0,0 +1,143 @@
from django.db.models import Q
from model_utils import Choices
from base64 import b64encode
from base64 import b64decode
import json
def query_to_base64(query):
"""
Converts a query dict object to a base64-encoded bytes object.
"""
return b64encode(json.dumps(query).encode('UTF-8')).decode("ascii")
def query_from_base64(b64data):
"""
Converts base64-encoded bytes object back to a query dict object.
"""
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):
"""
Replacement method for cursor.dictfetchall() as that method no longer
exists in psycopg2, and I'm guessing in other backends too.
Converts the results of a raw SQL query into a list of dictionaries, suitable
for use in templates etc.
"""
output = []
for data in results:
row = {}
i = 0
for column in descriptions:
row[column[0]] = data[i]
i += 1
output.append(row)
return output
def apply_query(queryset, params):
"""
Apply a dict-based set of filters & parameters to a queryset.
queryset is a Django queryset, eg MyModel.objects.all() or
MyModel.objects.filter(user=request.user)
params is a dictionary that contains the following:
filtering: A dict of Django ORM filters, eg:
{'user__id__in': [1, 3, 103], 'title__contains': 'foo'}
search_string: A freetext search string
sorting: The name of the column to sort by
"""
for key in params['filtering'].keys():
filter = {key: params['filtering'][key]}
queryset = queryset.filter(**filter)
search = params.get('search_string', '')
if search:
qset = (
Q(title__icontains=search) |
Q(description__icontains=search) |
Q(resolution__icontains=search) |
Q(submitter_email__icontains=search) |
Q(ticketcustomfieldvalue__value__icontains=search)
)
queryset = queryset.filter(qset)
sorting = params.get('sorting', None)
if sorting:
sortreverse = params.get('sortreverse', None)
if sortreverse:
sorting = "-%s" % sorting
queryset = queryset.order_by(sorting)
return queryset
ORDER_COLUMN_CHOICES = Choices(
('0', 'id'),
('2', 'priority'),
('3', 'title'),
('4', 'queue'),
('5', 'status'),
('6', 'created'),
('7', 'due_date'),
('8', 'assigned_to')
)
def query_tickets_by_args(objects, order_by, **kwargs):
"""
This function takes in a list of ticket objects from the views and throws it
to the datatables on ticket_list.html. If a search string was entered, this
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 DatatablesTicketSerializer in serializers.py.
"""
draw = int(kwargs.get('draw', None)[0])
length = int(kwargs.get('length', None)[0])
start = int(kwargs.get('start', None)[0])
search_value = kwargs.get('search[value]', None)[0]
order_column = kwargs.get('order[0][column]', None)[0]
order = kwargs.get('order[0][dir]', None)[0]
order_column = ORDER_COLUMN_CHOICES[order_column]
# django orm '-' -> desc
if order == 'desc':
order_column = '-' + order_column
queryset = objects.all().order_by(order_by)
total = queryset.count()
if search_value:
queryset = queryset.filter(Q(id__icontains=search_value) |
Q(priority__icontains=search_value) |
Q(title__icontains=search_value) |
Q(queue__title__icontains=search_value) |
Q(status__icontains=search_value) |
Q(created__icontains=search_value) |
Q(due_date__icontains=search_value) |
Q(assigned_to__email__icontains=search_value))
count = queryset.count()
queryset = queryset.order_by(order_column)[start:start + length]
return {
'items': queryset,
'count': count,
'total': total,
'draw': draw
}

View File

@ -27,7 +27,13 @@ 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, query_to_base64, query_from_base64
from helpdesk.query import (
query_to_dict,
apply_query,
query_tickets_by_args,
query_to_base64,
query_from_base64,
)
from helpdesk.serializers import DatatablesTicketSerializer
@ -41,8 +47,10 @@ from helpdesk.forms import (
)
from helpdesk.decorators import staff_member_required, superuser_required
from helpdesk.lib import (
query_to_dict, apply_query, safe_template_context,
process_attachments, queue_template_context, format_time_spent
safe_template_context,
process_attachments,
queue_template_context,
format_time_spent,
)
from helpdesk.models import (
Ticket, Queue, FollowUp, TicketChange, PreSetReply, FollowUpAttachment, SavedSearch,