From d600a3d239a8442002d83b777448c4e733333996 Mon Sep 17 00:00:00 2001
From: Tanner Prestegard <tanner.prestegard@ligo.org>
Date: Fri, 25 May 2018 10:42:34 -0500
Subject: [PATCH] adding search filter and ordering filter to superevents api

---
 gracedb/superevents/api/filters.py | 79 ++++++++++++++++++++++++++++++
 gracedb/superevents/api/views.py   |  6 ++-
 2 files changed, 84 insertions(+), 1 deletion(-)
 create mode 100644 gracedb/superevents/api/filters.py

diff --git a/gracedb/superevents/api/filters.py b/gracedb/superevents/api/filters.py
new file mode 100644
index 000000000..185354ecc
--- /dev/null
+++ b/gracedb/superevents/api/filters.py
@@ -0,0 +1,79 @@
+from rest_framework import filters, exceptions
+
+from django.http import HttpResponseBadRequest
+
+from ..query import parseSupereventQuery
+
+from pyparsing import ParseException
+import logging
+logger = logging.getLogger(__name__)
+
+class SupereventSearchFilter(filters.SearchFilter):
+    search_param = 'query'
+
+    def get_search_terms(self, request):
+        # Custom because we don't want default behavior of splitting on spaces
+        return request.query_params.get(self.search_param, '')
+
+    def filter_queryset(self, request, queryset, view):
+        query = self.get_search_terms(request)
+        
+        if not query:
+            return queryset
+
+        # Do filtering
+        try:
+            filter_params = parseSupereventQuery(query)
+        except ParseException as e:
+            raise exceptions.ParseError('Invalid query')
+
+        return queryset.filter(filter_params)
+
+
+class SupereventOrderingFilter(filters.OrderingFilter):
+    ordering_param = 'sort'
+    field_map = {
+        'created': u'date_created',
+        'preferred_event': u'preferred_event__id',
+        'id': [u't_0_date', u'is_gw', u'gw_date_number', 'base_date_number'],
+        'superevent_id': [u't_0_date', u'is_gw', u'gw_date_number',
+            'base_date_number'],
+    }
+
+    def custom_field_mapping(self, fields):
+        out_fields = []
+        for f in fields:
+            prefix = '-' if f.startswith('-') else ''
+            f_s = f.lstrip('-')
+            if f_s in self.field_map.keys():
+                mapped_fields = self.field_map[f_s]
+                if not isinstance(mapped_fields, list):
+                    mapped_fields = [mapped_fields]
+                if prefix:
+                    mapped_fields = [prefix + f for f in mapped_fields]
+                out_fields.extend(mapped_fields)
+            else:
+                out_fields.append(f)
+        return out_fields
+
+    def get_ordering(self, request, queryset, view):
+        """
+        Same as base class get_ordering method except we add in custom
+        mappings between ordering keywords and fields.
+        """
+        # Get ordering fields from request query params
+        params = request.query_params.get(self.ordering_param)
+        if params:
+            fields = [param.strip() for param in params.split(',')]
+
+            # Get custom field mappings
+            fields = self.custom_field_mapping(fields)
+
+            # Remove invalid fields
+            ordering = self.remove_invalid_fields(queryset, fields, view,
+                request)
+            if ordering:
+                return ordering
+
+        # No ordering was included, or all the ordering fields were invalid
+        return self.get_default_ordering(view)
diff --git a/gracedb/superevents/api/views.py b/gracedb/superevents/api/views.py
index 5d094b24c..094d63fce 100644
--- a/gracedb/superevents/api/views.py
+++ b/gracedb/superevents/api/views.py
@@ -22,6 +22,7 @@ from events.view_utils import reverse as gracedb_reverse
 #from events.api.views import IsAuthorizedForPipeline, LigoLwRenderer
 from events.api.backends import LigoAuthentication
 
+from .filters import SupereventSearchFilter, SupereventOrderingFilter
 from .mixins import GetParentSupereventMixin, BaseGetObjectMixin
 from .paginators import BasePaginationFactory, CustomLabelPagination, \
     CustomLogTagPagination, CustomSupereventPagination
@@ -29,7 +30,6 @@ from .serializers import SupereventSerializer, SupereventUpdateSerializer, \
     SupereventEventSerializer, SupereventLabelSerializer, \
     SupereventLogSerializer, SupereventLogTagSerializer, \
     SupereventVOEventSerializer, SupereventEMObservationSerializer
-
 from .settings import SUPEREVENT_LOOKUP_FIELD, SUPEREVENT_LOOKUP_REGEX
 
 import os
@@ -47,6 +47,10 @@ class SupereventViewSet(viewsets.ModelViewSet):
     pagination_class = CustomSupereventPagination
     lookup_field = SUPEREVENT_LOOKUP_FIELD
     lookup_value_regex = SUPEREVENT_LOOKUP_REGEX
+    filter_backends = (SupereventSearchFilter, SupereventOrderingFilter,)
+    ordering_fields = ('date_created', 't_0', 't_start', 't_end',
+        'preferred_event__id', 't_0_date', 'is_gw', 'base_date_number',
+        'gw_date_number')
 
     def get_serializer_class(self):
         """Select a different serializer for updates"""
-- 
GitLab