diff --git a/demo/demodesk/config/settings.py b/demo/demodesk/config/settings.py index b672dfc4..e1ac8106 100644 --- a/demo/demodesk/config/settings.py +++ b/demo/demodesk/config/settings.py @@ -106,9 +106,6 @@ HELPDESK_REDIRECT_TO_LOGIN_BY_DEFAULT = False LOGIN_URL = '/login/' LOGIN_REDIRECT_URL = '/login/' -# Turn off server-side processing for this local demo -HELPDESK_USE_SERVERSIDE_PROCESSING = False - # Database # - by default, we use SQLite3 for the demo, but you can also # configure MySQL or PostgreSQL, see the docs for more: diff --git a/docs/settings.rst b/docs/settings.rst index 72792849..0502f0e2 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -90,11 +90,6 @@ These changes are visible throughout django-helpdesk **Default:** ``HELPDESK_ANON_ACCESS_RAISES_404 = False`` -- **HELPDESK_USE_SERVERSIDE_PROCESSING** If True, may improve performance by utilizing server-side processing of the full ticket list whenever performing queries on the ticket list. Set to False to restore the "classic" functionality using javascript. - - **Default:** ``HELPDESK_USE_SERVERSIDE_PROCESSING = True`` - - Options shown on public pages ----------------------------- diff --git a/helpdesk/lib.py b/helpdesk/lib.py index 3a84596a..9a48af5b 100644 --- a/helpdesk/lib.py +++ b/helpdesk/lib.py @@ -11,98 +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')) - - -def query_from_base64(b64data): - """ - Converts base64-encoded bytes object back to a query dict object. - """ - return json.loads(b64decode(b64data).decode('utf-8')) - - -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', None) - 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 = {} @@ -238,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 TicketSerializer 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 diff --git a/helpdesk/models.py b/helpdesk/models.py index 9179b60a..339f4c9f 100644 --- a/helpdesk/models.py +++ b/helpdesk/models.py @@ -28,6 +28,8 @@ from markdown.extensions import Extension import uuid +from helpdesk import settings as helpdesk_settings + from .templated_email import send_templated_mail @@ -685,7 +687,7 @@ class Ticket(models.Model): site = Site.objects.get_current() except ImproperlyConfigured: site = Site(domain='configure-django-sites.com') - if settings.HELPDESK_USE_HTTPS_IN_EMAIL_LINK: + if helpdesk_settings.HELPDESK_USE_HTTPS_IN_EMAIL_LINK: protocol = 'https' else: protocol = 'http' @@ -711,7 +713,7 @@ class Ticket(models.Model): site = Site.objects.get_current() except ImproperlyConfigured: site = Site(domain='configure-django-sites.com') - if settings.HELPDESK_USE_HTTPS_IN_EMAIL_LINK: + if helpdesk_settings.HELPDESK_USE_HTTPS_IN_EMAIL_LINK: protocol = 'https' else: protocol = 'http' diff --git a/helpdesk/query.py b/helpdesk/query.py new file mode 100644 index 00000000..81fe4082 --- /dev/null +++ b/helpdesk/query.py @@ -0,0 +1,156 @@ +from django.db.models import Q +from django.core.cache import cache + +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 + + +def get_query(query, huser): + # Prefilter the allowed tickets + objects = cache.get(huser.user.email + query) + if objects is not None: + return objects + tickets = huser.get_tickets_in_queues().select_related() + query_params = query_from_base64(query) + ticket_qs = apply_query(tickets, query_params) + cache.set(huser.user.email + query, ticket_qs, timeout=60*60) + return ticket_qs + + +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 + } diff --git a/helpdesk/serializers.py b/helpdesk/serializers.py index bb7fca5d..c3b311b5 100644 --- a/helpdesk/serializers.py +++ b/helpdesk/serializers.py @@ -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() diff --git a/helpdesk/settings.py b/helpdesk/settings.py index 7142ce18..32afacc6 100644 --- a/helpdesk/settings.py +++ b/helpdesk/settings.py @@ -151,7 +151,3 @@ HELPDESK_ENABLE_PER_QUEUE_STAFF_PERMISSION = getattr( # use https in the email links HELPDESK_USE_HTTPS_IN_EMAIL_LINK = getattr(settings, 'HELPDESK_USE_HTTPS_IN_EMAIL_LINK', False) - -# Asynchronous Datatables - Optional -HELPDESK_USE_SERVERSIDE_PROCESSING = getattr( - settings, 'HELPDESK_USE_SERVERSIDE_PROCESSING', True) diff --git a/helpdesk/templates/helpdesk/filters/keywords.html b/helpdesk/templates/helpdesk/filters/keywords.html index e46a17ab..60af3fd6 100644 --- a/helpdesk/templates/helpdesk/filters/keywords.html +++ b/helpdesk/templates/helpdesk/filters/keywords.html @@ -4,7 +4,7 @@
@@ -229,135 +226,126 @@ {% block helpdesk_js %}