From c10637aaa462a8ad665630a77bdfe529b259a232 Mon Sep 17 00:00:00 2001 From: Roberto Rosario Date: Fri, 28 Oct 2016 02:44:02 -0400 Subject: [PATCH] Update dynamic_search app API to support document page searches. --- mayan/apps/dynamic_search/api_views.py | 85 ++++++++++++++++++++++---- mayan/apps/dynamic_search/classes.py | 14 ++++- mayan/apps/dynamic_search/mixins.py | 13 ++++ mayan/apps/dynamic_search/urls.py | 11 +++- mayan/apps/dynamic_search/views.py | 17 +++--- requirements/base.txt | 2 +- 6 files changed, 117 insertions(+), 25 deletions(-) create mode 100644 mayan/apps/dynamic_search/mixins.py diff --git a/mayan/apps/dynamic_search/api_views.py b/mayan/apps/dynamic_search/api_views.py index 65f78104a9..876aaf9aec 100644 --- a/mayan/apps/dynamic_search/api_views.py +++ b/mayan/apps/dynamic_search/api_views.py @@ -1,28 +1,49 @@ from __future__ import unicode_literals +from django.http import Http404, HttpResponseRedirect + from rest_framework import generics from rest_framework.exceptions import ParseError from rest_api.filters import MayanObjectPermissionsFilter from .classes import SearchModel +from .mixins import SearchModelMixin -class APISearchView(generics.ListAPIView): +class APISearchView(SearchModelMixin, generics.ListAPIView): """ - Perform a search operaton - q -- Term that will be used for the search. + Perform a search operation + --- + GET: + omit_serializer: true + parameters: + - name: search_model + paramType: path + type: string + required: true + description: Possible values are "documents.Document" or "document.DocumentPageResult" + - name: q + paramType: query + type: string + description: Term that will be used for the search. """ + filter_backends = (MayanObjectPermissionsFilter,) def get_queryset(self): - search_class = self.get_search_class() - if search_class.permission: - self.mayan_object_permissions = {'GET': (search_class.permission,)} + search_model = self.get_search_model() + + # Override serializer class just before producing the queryset of + # search results + self.serializer_class = search_model.serializer + + if search_model.permission: + self.mayan_object_permissions = {'GET': (search_model.permission,)} try: - queryset, ids, timedelta = search_class.search( + queryset, ids, timedelta = search_model.search( query_string=self.request.GET, user=self.request.user ) except Exception as exception: @@ -30,8 +51,50 @@ class APISearchView(generics.ListAPIView): return queryset - def get_search_class(self): - return SearchModel.get('documents.Document') - def get_serializer_class(self): - return self.get_search_class().serializer +class APIAdvancedSearchView(SearchModelMixin, generics.ListAPIView): + """ + Perform an advanced search operation + --- + GET: + omit_serializer: true + parameters: + - name: search_model + paramType: path + type: string + required: true + description: Possible values are "documents.Document" or "document.DocumentPageResult" + - name: _match_all + paramType: query + type: string + description: When checked, only results that match all fields will be returned. When unchecked results that match at least one field will be returned. Possible values are "on" or "off" + """ + + filter_backends = (MayanObjectPermissionsFilter,) + + def get_queryset(self): + self.search_model = self.get_search_model() + + # Override serializer class just before producing the queryset of + # search results + self.serializer_class = self.search_model.serializer + + if self.search_model.permission: + self.mayan_object_permissions = { + 'GET': (self.search_model.permission,) + } + + if self.request.GET.get('_match_all', 'off') == 'on': + global_and_search=True + else: + global_and_search=False + + try: + queryset, ids, timedelta = self.search_model.search( + query_string=self.request.GET, user=self.request.user, + global_and_search=global_and_search + ) + except Exception as exception: + raise ParseError(unicode(exception)) + + return queryset diff --git a/mayan/apps/dynamic_search/classes.py b/mayan/apps/dynamic_search/classes.py index 18fa94aac1..0999a59a43 100644 --- a/mayan/apps/dynamic_search/classes.py +++ b/mayan/apps/dynamic_search/classes.py @@ -8,6 +8,7 @@ from django.apps import apps from django.core.exceptions import PermissionDenied from django.db.models import Q from django.utils.module_loading import import_string +from django.utils.translation import ugettext as _ from acls.models import AccessControlList from permissions import Permission @@ -22,12 +23,23 @@ class SearchModel(object): @classmethod def get(cls, full_name): - result = cls.registry[full_name] + try: + result = cls.registry[full_name] + except KeyError: + raise KeyError(_('No search model matching the query')) if not hasattr(result, 'serializer'): result.serializer = import_string(result.serializer_string) return result + @classmethod + def as_choices(cls): + return cls.registry + + @classmethod + def all(cls): + return cls.registry.values() + def __init__(self, app_label, model_name, serializer_string, label=None, permission=None): self.app_label = app_label self.model_name = model_name diff --git a/mayan/apps/dynamic_search/mixins.py b/mayan/apps/dynamic_search/mixins.py new file mode 100644 index 0000000000..a73206d764 --- /dev/null +++ b/mayan/apps/dynamic_search/mixins.py @@ -0,0 +1,13 @@ +from __future__ import unicode_literals + +from django.http import Http404 + +from .classes import SearchModel + + +class SearchModelMixin(object): + def get_search_model(self): + try: + return SearchModel.get(self.kwargs['search_model']) + except KeyError as exception: + raise Http404(unicode(exception)) diff --git a/mayan/apps/dynamic_search/urls.py b/mayan/apps/dynamic_search/urls.py index 9dba7e8c75..bcf566ca36 100644 --- a/mayan/apps/dynamic_search/urls.py +++ b/mayan/apps/dynamic_search/urls.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals from django.conf.urls import patterns, url -from .api_views import APISearchView +from .api_views import APIAdvancedSearchView, APISearchView from .views import ( AdvancedSearchView, ResultsView, SearchAgainView, SearchView ) @@ -26,5 +26,12 @@ urlpatterns = patterns( api_urls = patterns( '', - url(r'^search/$', APISearchView.as_view(), name='search-view'), + url( + r'^search/(?P[\.\w]+)/$', APISearchView.as_view(), + name='search-view' + ), + url( + r'^advanced/(?P[\.\w]+)/$', APIAdvancedSearchView.as_view(), + name='advanced-search-view' + ), ) diff --git a/mayan/apps/dynamic_search/views.py b/mayan/apps/dynamic_search/views.py index 077619f064..41838b9be6 100644 --- a/mayan/apps/dynamic_search/views.py +++ b/mayan/apps/dynamic_search/views.py @@ -5,7 +5,7 @@ import urlparse from django.conf import settings from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect +from django.http import Http404, HttpResponseRedirect from django.utils.translation import ugettext_lazy as _ from django.views.generic.base import RedirectView @@ -13,12 +13,13 @@ from common.generics import SimpleView, SingleObjectListView from .classes import SearchModel from .forms import SearchForm, AdvancedSearchForm +from .mixins import SearchModelMixin from .settings import setting_limit logger = logging.getLogger(__name__) -class ResultsView(SingleObjectListView): +class ResultsView(SearchModelMixin, SingleObjectListView): def get_extra_context(self): context = { 'hide_links': True, @@ -48,11 +49,8 @@ class ResultsView(SingleObjectListView): return queryset - def get_search_model(self): - return SearchModel.get(self.kwargs['search_model']) - -class SearchView(SimpleView): +class SearchView(SearchModelMixin, SimpleView): template_name = 'appearance/generic_form.html' title = _('Search') @@ -60,7 +58,9 @@ class SearchView(SimpleView): self.search_model = self.get_search_model() return { 'form': self.get_form(), - 'form_action': reverse('search:results', args=(self.search_model.get_full_name(),)), + 'form_action': reverse( + 'search:results', args=(self.search_model.get_full_name(),) + ), 'search_model': self.search_model, 'submit_icon': 'fa fa-search', 'submit_label': _('Search'), @@ -75,9 +75,6 @@ class SearchView(SimpleView): else: return SearchForm() - def get_search_model(self): - return SearchModel.get(self.kwargs['search_model']) - class AdvancedSearchView(SearchView): title = _('Advanced search') diff --git a/requirements/base.txt b/requirements/base.txt index 529260ad08..07bf502cdd 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -17,7 +17,7 @@ django-pure-pagination==0.3.0 django-model-utils==2.4 django-mptt==0.8.0 django-qsstats-magic==0.7.2 -django-rest-swagger==0.3.4 +django-rest-swagger==0.3.10 django-stronghold==0.2.7 django-suit==0.2.16 django-widget-tweaks==1.4.1