Update dynamic_search app to work with organizations. Remove Recent search feature.
This commit is contained in:
@@ -95,6 +95,12 @@ class GenericViewTestCase(OrganizationTestCase):
|
||||
data=data, follow=follow
|
||||
)
|
||||
|
||||
def login_user(self):
|
||||
self.login(username=TEST_USER_USERNAME, password=TEST_USER_PASSWORD)
|
||||
|
||||
def login_superuser(self):
|
||||
self.login(username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD)
|
||||
|
||||
|
||||
class CommonViewTestCase(GenericViewTestCase):
|
||||
def test_about_view(self):
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import RecentSearch
|
||||
|
||||
|
||||
@admin.register(RecentSearch)
|
||||
class RecentSearchAdmin(admin.ModelAdmin):
|
||||
date_hierarchy = 'datetime_created'
|
||||
list_display = ('user', 'query', 'datetime_created', 'hits')
|
||||
list_display_links = ('user', 'query', 'datetime_created', 'hits')
|
||||
list_filter = ('user',)
|
||||
readonly_fields = ('user', 'query', 'datetime_created', 'hits')
|
||||
@@ -6,29 +6,6 @@ from rest_framework.exceptions import ParseError
|
||||
from rest_api.filters import MayanObjectPermissionsFilter
|
||||
|
||||
from .classes import SearchModel
|
||||
from .filters import RecentSearchUserFilter
|
||||
from .models import RecentSearch
|
||||
from .serializers import RecentSearchSerializer
|
||||
|
||||
|
||||
class APIRecentSearchListView(generics.ListAPIView):
|
||||
"""
|
||||
Returns a list of all the recent searches for the logged user.
|
||||
"""
|
||||
|
||||
filter_backends = (RecentSearchUserFilter,)
|
||||
queryset = RecentSearch.objects.all()
|
||||
serializer_class = RecentSearchSerializer
|
||||
|
||||
|
||||
class APIRecentSearchView(generics.RetrieveAPIView):
|
||||
"""
|
||||
Returns the selected recent search details.
|
||||
"""
|
||||
|
||||
filter_backends = (RecentSearchUserFilter,)
|
||||
queryset = RecentSearch.objects.all()
|
||||
serializer_class = RecentSearchSerializer
|
||||
|
||||
|
||||
class APISearchView(generics.ListAPIView):
|
||||
|
||||
@@ -2,10 +2,10 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common import MayanAppConfig, menu_facet, menu_sidebar
|
||||
from common import MayanAppConfig, menu_facet
|
||||
from rest_api.classes import APIEndPoint
|
||||
|
||||
from .links import link_search, link_search_advanced, link_search_again
|
||||
from .links import link_search, link_search_advanced
|
||||
|
||||
|
||||
class DynamicSearchApp(MayanAppConfig):
|
||||
@@ -26,6 +26,3 @@ class DynamicSearchApp(MayanAppConfig):
|
||||
'search:search', 'search:search_advanced', 'search:results'
|
||||
)
|
||||
)
|
||||
menu_sidebar.bind_links(
|
||||
links=(link_search_again,), sources=('search:results',)
|
||||
)
|
||||
|
||||
@@ -12,7 +12,6 @@ from django.utils.module_loading import import_string
|
||||
from acls.models import AccessControlList
|
||||
from permissions import Permission
|
||||
|
||||
from .models import RecentSearch
|
||||
from .settings import setting_limit
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -148,7 +147,7 @@ class SearchModel(object):
|
||||
for query in field_query_list:
|
||||
logger.debug('query: %s', query)
|
||||
term_query_result_set = set(
|
||||
model.objects.filter(query).values_list(
|
||||
model.on_organization.filter(query).values_list(
|
||||
data['return_value'], flat=True
|
||||
)
|
||||
)
|
||||
@@ -183,7 +182,7 @@ class SearchModel(object):
|
||||
datetime.datetime.now() - start_time
|
||||
).split(':')[2]
|
||||
|
||||
queryset = self.model.objects.filter(
|
||||
queryset = self.model.on_organization.filter(
|
||||
pk__in=list(result_set)[:setting_limit.value]
|
||||
)
|
||||
|
||||
@@ -195,10 +194,6 @@ class SearchModel(object):
|
||||
self.permission, user, queryset
|
||||
)
|
||||
|
||||
RecentSearch.objects.add_query_for_user(
|
||||
user, query_string, len(result_set)
|
||||
)
|
||||
|
||||
return queryset, result_set, elapsed_time
|
||||
|
||||
def assemble_query(self, terms, search_fields):
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework.filters import BaseFilterBackend
|
||||
|
||||
|
||||
class RecentSearchUserFilter(BaseFilterBackend):
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
if request.user.is_staff or request.user.is_superuser:
|
||||
return queryset
|
||||
else:
|
||||
return queryset.filter(user=self.request.user)
|
||||
@@ -8,4 +8,3 @@ link_search = Link(text=_('Search'), view='search:search')
|
||||
link_search_advanced = Link(
|
||||
text=_('Advanced search'), view='search:search_advanced'
|
||||
)
|
||||
link_search_again = Link(text=_('Search again'), view='search:search_again')
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
import urlparse
|
||||
|
||||
from django.contrib.auth.models import AnonymousUser
|
||||
from django.db import models
|
||||
from django.utils.http import urlencode
|
||||
|
||||
from .settings import setting_recent_count
|
||||
|
||||
|
||||
class RecentSearchManager(models.Manager):
|
||||
def add_query_for_user(self, user, query_string, hits):
|
||||
parsed_query = urlparse.parse_qs(
|
||||
urlencode(dict(query_string.items()))
|
||||
)
|
||||
|
||||
for key, value in parsed_query.items():
|
||||
parsed_query[key] = ' '.join(value)
|
||||
|
||||
if 'q' in query_string:
|
||||
# Is a simple query
|
||||
|
||||
if not query_string['q']:
|
||||
# Don't store empty simple searches
|
||||
return
|
||||
else:
|
||||
# Cleanup query string and only store the q parameter
|
||||
parsed_query = {'q': parsed_query['q']}
|
||||
|
||||
if parsed_query and not isinstance(user, AnonymousUser):
|
||||
# If the URL query has at least one variable with a value
|
||||
new_recent, created = self.model.objects.get_or_create(
|
||||
user=user, query=urlencode(parsed_query),
|
||||
defaults={'hits': hits}
|
||||
)
|
||||
if not created:
|
||||
new_recent.hits = hits
|
||||
new_recent.save()
|
||||
|
||||
for recent_to_delete in self.model.objects.filter(user=user)[setting_recent_count.value:]:
|
||||
recent_to_delete.delete()
|
||||
@@ -15,7 +15,10 @@ class Migration(migrations.Migration):
|
||||
migrations.AlterField(
|
||||
model_name='recentsearch',
|
||||
name='user',
|
||||
field=models.ForeignKey(editable=False, to=settings.AUTH_USER_MODEL, verbose_name='User'),
|
||||
field=models.ForeignKey(
|
||||
editable=False, to=settings.AUTH_USER_MODEL,
|
||||
verbose_name='User'
|
||||
),
|
||||
preserve_default=True,
|
||||
),
|
||||
]
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import urllib
|
||||
import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.utils.encoding import (
|
||||
python_2_unicode_compatible, smart_str, smart_unicode
|
||||
)
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from .managers import RecentSearchManager
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class RecentSearch(models.Model):
|
||||
"""
|
||||
Keeps a list of the [n] most recent search keywords for a given user
|
||||
"""
|
||||
|
||||
user = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL, editable=False, verbose_name=_('User')
|
||||
)
|
||||
query = models.TextField(editable=False, verbose_name=_('Query'))
|
||||
datetime_created = models.DateTimeField(
|
||||
auto_now=True, db_index=True, verbose_name=_('Datetime created')
|
||||
)
|
||||
hits = models.IntegerField(editable=False, verbose_name=_('Hits'))
|
||||
|
||||
objects = RecentSearchManager()
|
||||
|
||||
def __str__(self):
|
||||
# TODO: Fix this hack, store the search model name in the recent
|
||||
# search entry
|
||||
from .classes import SearchModel
|
||||
document_search = SearchModel.get('documents.Document')
|
||||
|
||||
query_dict = urlparse.parse_qs(
|
||||
urllib.unquote_plus(smart_str(self.query))
|
||||
)
|
||||
|
||||
if self.is_advanced():
|
||||
# Advanced search
|
||||
advanced_string = []
|
||||
for key, value in query_dict.items():
|
||||
search_field = document_search.get_search_field(key)
|
||||
advanced_string.append(
|
||||
'%s: %s' % (
|
||||
search_field.label, smart_unicode(' '.join(value))
|
||||
)
|
||||
)
|
||||
|
||||
display_string = ', '.join(advanced_string)
|
||||
else:
|
||||
# Is a simple search
|
||||
display_string = smart_unicode(' '.join(query_dict['q']))
|
||||
|
||||
return '%s (%s)' % (display_string, self.hits)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
super(RecentSearch, self).save(*args, **kwargs)
|
||||
|
||||
def url(self):
|
||||
view = 'search:results' if self.is_advanced() else 'search:search'
|
||||
return '%s?%s' % (reverse(view), self.query)
|
||||
|
||||
def is_advanced(self):
|
||||
return 'q' not in urlparse.parse_qs(self.query)
|
||||
|
||||
class Meta:
|
||||
ordering = ('-datetime_created',)
|
||||
verbose_name = _('Recent search')
|
||||
verbose_name_plural = _('Recent searches')
|
||||
@@ -1,19 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from user_management.serializers import UserSerializer
|
||||
|
||||
from .models import RecentSearch
|
||||
|
||||
|
||||
class RecentSearchSerializer(serializers.HyperlinkedModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(
|
||||
view_name='rest_api:recentsearch-detail'
|
||||
)
|
||||
user = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
fields = ('datetime_created', 'hits', 'query', 'url', 'user')
|
||||
model = RecentSearch
|
||||
read_only_fields = ('datetime_created', 'hits', 'query', 'user')
|
||||
@@ -1,38 +1,21 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from json import loads
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import override_settings
|
||||
|
||||
from rest_framework.test import APITestCase
|
||||
|
||||
from documents.models import DocumentType
|
||||
from documents.tests import TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH
|
||||
from user_management.tests import (
|
||||
TEST_ADMIN_EMAIL, TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME
|
||||
)
|
||||
from rest_api.tests import GenericAPITestCase
|
||||
|
||||
|
||||
@override_settings(OCR_AUTO_OCR=False)
|
||||
class SearchAPITestCase(APITestCase):
|
||||
class SearchAPITestCase(GenericAPITestCase):
|
||||
"""
|
||||
Test the search API endpoints
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.admin_user = get_user_model().objects.create_superuser(
|
||||
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
|
||||
password=TEST_ADMIN_PASSWORD
|
||||
)
|
||||
|
||||
self.client.login(
|
||||
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
|
||||
)
|
||||
|
||||
def test_search(self):
|
||||
document_type = DocumentType.objects.create(
|
||||
document_type = DocumentType.on_organization.create(
|
||||
label=TEST_DOCUMENT_TYPE
|
||||
)
|
||||
|
||||
@@ -45,6 +28,5 @@ class SearchAPITestCase(APITestCase):
|
||||
'{}?q={}'.format(reverse('rest_api:search-view'), document.label)
|
||||
)
|
||||
|
||||
content = loads(response.content)
|
||||
self.assertEqual(content['results'][0]['label'], document.label)
|
||||
self.assertEqual(content['count'], 1)
|
||||
self.assertEqual(response.data['results'][0]['label'], document.label)
|
||||
self.assertEqual(response.data['count'], 1)
|
||||
|
||||
@@ -1,23 +1,25 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import TestCase
|
||||
|
||||
from documents.models import DocumentType
|
||||
from documents.search import document_search
|
||||
from documents.tests import TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH
|
||||
from organizations.tests import OrganizationTestCase
|
||||
from user_management.tests import (
|
||||
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL
|
||||
)
|
||||
|
||||
|
||||
class DocumentSearchTestCase(TestCase):
|
||||
class DocumentSearchTestCase(OrganizationTestCase):
|
||||
def setUp(self):
|
||||
self.admin_user = get_user_model().objects.create_superuser(
|
||||
super(DocumentSearchTestCase, self).setUp()
|
||||
|
||||
self.admin_user = get_user_model().on_organization.create_superuser(
|
||||
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
|
||||
password=TEST_ADMIN_PASSWORD
|
||||
)
|
||||
self.document_type = DocumentType.objects.create(
|
||||
self.document_type = DocumentType.on_organization.create(
|
||||
label=TEST_DOCUMENT_TYPE
|
||||
)
|
||||
|
||||
@@ -28,6 +30,7 @@ class DocumentSearchTestCase(TestCase):
|
||||
|
||||
def tearDown(self):
|
||||
self.document_type.delete()
|
||||
super(DocumentSearchTestCase, self).tearDown()
|
||||
|
||||
def test_simple_search_after_related_name_change(self):
|
||||
"""
|
||||
|
||||
@@ -1,39 +1,26 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
from django.test.client import Client
|
||||
|
||||
from common.tests.test_views import GenericViewTestCase
|
||||
from documents.models import DocumentType
|
||||
from documents.search import document_search
|
||||
from documents.tests import TEST_DOCUMENT_TYPE, TEST_SMALL_DOCUMENT_PATH
|
||||
from user_management.tests import (
|
||||
TEST_ADMIN_PASSWORD, TEST_ADMIN_USERNAME, TEST_ADMIN_EMAIL
|
||||
)
|
||||
|
||||
|
||||
class Issue46TestCase(TestCase):
|
||||
class Issue46TestCase(GenericViewTestCase):
|
||||
"""
|
||||
Functional tests to make sure issue 46 is fixed
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.admin_user = get_user_model().objects.create_superuser(
|
||||
username=TEST_ADMIN_USERNAME, email=TEST_ADMIN_EMAIL,
|
||||
password=TEST_ADMIN_PASSWORD
|
||||
)
|
||||
self.client = Client()
|
||||
# Login the admin user
|
||||
logged_in = self.client.login(
|
||||
username=TEST_ADMIN_USERNAME, password=TEST_ADMIN_PASSWORD
|
||||
)
|
||||
self.assertTrue(logged_in)
|
||||
self.assertTrue(self.admin_user.is_authenticated())
|
||||
super(Issue46TestCase, self).setUp()
|
||||
|
||||
self.login_superuser()
|
||||
|
||||
self.document_count = 4
|
||||
|
||||
self.document_type = DocumentType.objects.create(
|
||||
self.document_type = DocumentType.on_organization.create(
|
||||
label=TEST_DOCUMENT_TYPE
|
||||
)
|
||||
|
||||
@@ -46,9 +33,11 @@ class Issue46TestCase(TestCase):
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
for document_type in DocumentType.objects.all():
|
||||
for document_type in DocumentType.on_organization.all():
|
||||
document_type.delete()
|
||||
|
||||
super(Issue46TestCase, self).tearDown()
|
||||
|
||||
def test_advanced_search_past_first_page(self):
|
||||
# Make sure all documents are returned by the search
|
||||
model_list, result_set, elapsed_time = document_search.search(
|
||||
|
||||
@@ -2,28 +2,17 @@ from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import patterns, url
|
||||
|
||||
from .api_views import (
|
||||
APIRecentSearchListView, APIRecentSearchView, APISearchView
|
||||
)
|
||||
from .api_views import APISearchView
|
||||
from .views import AdvancedSearchView, ResultsView, SearchView
|
||||
|
||||
urlpatterns = patterns(
|
||||
'dynamic_search.views',
|
||||
url(r'^$', SearchView.as_view(), name='search'),
|
||||
url(r'^advanced/$', AdvancedSearchView.as_view(), name='search_advanced'),
|
||||
url(r'^again/$', 'search_again', name='search_again'),
|
||||
url(r'^results/$', ResultsView.as_view(), name='results'),
|
||||
)
|
||||
|
||||
api_urls = patterns(
|
||||
'',
|
||||
url(
|
||||
r'^recent_searches/$', APIRecentSearchListView.as_view(),
|
||||
name='recentsearch-list'
|
||||
),
|
||||
url(
|
||||
r'^recent_searches/(?P<pk>[0-9]+)/$', APIRecentSearchView.as_view(),
|
||||
name='recentsearch-detail'
|
||||
),
|
||||
url(r'^search/$', APISearchView.as_view(), name='search-view'),
|
||||
)
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.generics import SimpleView, SingleObjectListView
|
||||
@@ -82,12 +79,3 @@ class AdvancedSearchView(SearchView):
|
||||
return AdvancedSearchForm(
|
||||
data=self.request.GET, search_model=document_search
|
||||
)
|
||||
|
||||
|
||||
def search_again(request):
|
||||
query = urlparse.urlparse(
|
||||
request.META.get('HTTP_REFERER', reverse(settings.LOGIN_REDIRECT_URL))
|
||||
).query
|
||||
return HttpResponseRedirect(
|
||||
'{}?{}'.format(reverse('search:search_advanced'), query)
|
||||
)
|
||||
|
||||
@@ -1 +1 @@
|
||||
from .base import OrganizationTestCase #NOQA
|
||||
from .base import OrganizationTestCase # NOQA
|
||||
|
||||
@@ -24,7 +24,6 @@ class GenericAPITestCase(APITestCase):
|
||||
username=self.admin_user.username, password=password
|
||||
)
|
||||
|
||||
|
||||
def tearDown(self):
|
||||
super(GenericAPITestCase, self).tearDown()
|
||||
self.admin_user.delete()
|
||||
|
||||
Reference in New Issue
Block a user