Commit aa5f7fe12dedefd86329699d3c6652f7900aa705

Authored by Alexandre A. Barbosa
2 parents 16a5527f e1694f21

Merge pull request #90 from colab/search_filters

Search filters
colab/accounts/filters.py 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +from django.utils.translation import ugettext as _
  2 +
  3 +
  4 +def get_filters(request):
  5 + return {
  6 + 'user': {
  7 + 'name': _(u'User'),
  8 + 'icon': 'user',
  9 + 'fields': (
  10 + (
  11 + 'username',
  12 + _(u'Username'),
  13 + request.get('username'),
  14 + ),
  15 + ('name', _(u'Name'), request.get('name')),
  16 + (
  17 + 'institution',
  18 + _(u'Institution'),
  19 + request.get('institution'),
  20 + ),
  21 + ('role', _(u'Role'), request.get('role'))
  22 + ),
  23 + },
  24 + }
colab/plugins/utils/filters_importer.py 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +#!/usr/bin/env python
  2 +
  3 +import importlib
  4 +
  5 +from django.conf import settings
  6 +
  7 +
  8 +def import_plugin_filters(request):
  9 + plugin_filters = {}
  10 + for app_name in settings.INSTALLED_APPS:
  11 +
  12 + module_name = '{}.filters'.format(app_name)
  13 + try:
  14 + module = importlib.import_module(module_name)
  15 + except ImportError:
  16 + continue
  17 +
  18 + get_filters = getattr(module, 'get_filters', None)
  19 + if get_filters:
  20 + plugin_filters.update(get_filters(request))
  21 +
  22 + return plugin_filters
colab/search/forms.py
@@ -35,6 +35,10 @@ class ColabSearchForm(SearchForm): @@ -35,6 +35,10 @@ class ColabSearchForm(SearchForm):
35 keywords = forms.CharField(required=False, label=_(u'Keywords')) 35 keywords = forms.CharField(required=False, label=_(u'Keywords'))
36 collaborators = forms.CharField(required=False, label=_(u'Collaborators')) 36 collaborators = forms.CharField(required=False, label=_(u'Collaborators'))
37 repository_name = forms.CharField(required=False, label=_(u'Repository')) 37 repository_name = forms.CharField(required=False, label=_(u'Repository'))
  38 + body = forms.CharField(required=False, label=_(u'Content'))
  39 + description = forms.CharField(required=False, label=_(u'Description'))
  40 + category = forms.CharField(required=False, label=_(u'Category'))
  41 + title = forms.CharField(required=False, label=_(u'Title'))
38 username = forms.CharField(required=False, label=_(u'Username')) 42 username = forms.CharField(required=False, label=_(u'Username'))
39 name = forms.CharField(required=False, label=_(u'Name')) 43 name = forms.CharField(required=False, label=_(u'Name'))
40 institution = forms.CharField(required=False, label=_(u'Institution')) 44 institution = forms.CharField(required=False, label=_(u'Institution'))
@@ -151,6 +155,14 @@ class ColabSearchForm(SearchForm): @@ -151,6 +155,14 @@ class ColabSearchForm(SearchForm):
151 sqs = sqs.filter( 155 sqs = sqs.filter(
152 repository_name=self.cleaned_data['repository_name'] 156 repository_name=self.cleaned_data['repository_name']
153 ) 157 )
  158 + if self.cleaned_data['body']:
  159 + sqs = sqs.filter(body=self.cleaned_data['body'])
  160 + if self.cleaned_data['description']:
  161 + sqs = sqs.filter(description=self.cleaned_data['description'])
  162 + if self.cleaned_data['category']:
  163 + sqs = sqs.filter(category=self.cleaned_data['category'])
  164 + if self.cleaned_data['title']:
  165 + sqs = sqs.filter(title=self.cleaned_data['title'])
154 if self.cleaned_data['username']: 166 if self.cleaned_data['username']:
155 sqs = sqs.filter(username=self.cleaned_data['username']) 167 sqs = sqs.filter(username=self.cleaned_data['username'])
156 if self.cleaned_data['name']: 168 if self.cleaned_data['name']:
colab/search/templates/search/includes/search_filters.html
@@ -16,12 +16,12 @@ @@ -16,12 +16,12 @@
16 <input type="hidden" name="since" value="{{ request.GET.since }}" /> 16 <input type="hidden" name="since" value="{{ request.GET.since }}" />
17 <input type="hidden" name="until" value="{{ request.GET.until }}" /> 17 <input type="hidden" name="until" value="{{ request.GET.until }}" />
18 18
19 - {% for field_lookup, field_display, field_value in filters.fields %} 19 + {% for field_lookup, field_display, field_value, field_type, field_choices in filters.fields %}
20 <div class="form-group"> 20 <div class="form-group">
21 <label for="{{ field_lookup }}">{{ field_display }}</label> 21 <label for="{{ field_lookup }}">{{ field_display }}</label>
22 - {% if field_lookup == "list" %} 22 + {% if field_type == "list" %}
23 <select name="{{ field_lookup }}" class="form-control" multiple> 23 <select name="{{ field_lookup }}" class="form-control" multiple>
24 - {% for value, option in form.fields.list.choices %} 24 + {% for value, option in field_choices %}
25 <option value="{{ value }}" {% if value in field_value %}selected{% endif %}>{{ option }}</option> 25 <option value="{{ value }}" {% if value in field_value %}selected{% endif %}>{{ option }}</option>
26 {% endfor %} 26 {% endfor %}
27 </select> 27 </select>
@@ -112,10 +112,12 @@ @@ -112,10 +112,12 @@
112 112
113 <ul class="unstyled-list"> 113 <ul class="unstyled-list">
114 114
115 - <li>  
116 - <span class="glyphicon glyphicon-envelope"></span>  
117 - <a href="{% append_to_get type='thread' %}">{% trans "Discussion" %}</a>  
118 - </li> 115 + {% for type, name, icon in filters_options %}
  116 + <li>
  117 + <span class="glyphicon glyphicon-{{icon}}"></span>
  118 + <a href="{% append_to_get type=type %}">{% trans name %}</a>
  119 + </li>
  120 + {% endfor %}
119 </ul> 121 </ul>
120 {% endif %} 122 {% endif %}
121 <hr /> 123 <hr />
colab/search/templates/search/search.html
@@ -25,13 +25,6 @@ We must use STATIC_URL because we have a language composing the URL @@ -25,13 +25,6 @@ We must use STATIC_URL because we have a language composing the URL
25 {% endif %} 25 {% endif %}
26 }); 26 });
27 27
28 - $('#collapseFilters').on('hide.bs.collapse', function() {  
29 - $('.collapse-icon-controller').toggleClass('glyphicon-collapse-down glyphicon-collapse-up');  
30 - });  
31 - $('#collapseFilters').on('show.bs.collapse', function() {  
32 - $('.collapse-icon-controller').toggleClass('glyphicon-collapse-down glyphicon-collapse-up');  
33 - });  
34 -  
35 }); 28 });
36 </script> 29 </script>
37 {% endblock %} 30 {% endblock %}
@@ -74,28 +67,6 @@ We must use STATIC_URL because we have a language composing the URL @@ -74,28 +67,6 @@ We must use STATIC_URL because we have a language composing the URL
74 <h3>{% trans "Filters" %}</h3> 67 <h3>{% trans "Filters" %}</h3>
75 {% include "search/includes/search_filters.html" %} 68 {% include "search/includes/search_filters.html" %}
76 </div> 69 </div>
77 -  
78 - <div class="col-xs-12 col-sm-12 hidden-md hidden-lg">  
79 - <div class="panel-group" id="accordion">  
80 - <div class="panel panel-default">  
81 - <div class="panel-heading subject">  
82 - <a data-toggle="collapse" data-parent="#accordion" href="#collapseFilters">  
83 - <h4 class="panel-title">  
84 - {% trans "Filters" %}  
85 - <span class="glyphicon glyphicon-collapse-down pull-right collapse-icon-controller"></span>  
86 - </h4>  
87 - </a>  
88 - </div>  
89 - <div id="collapseFilters" class="panel-collapse collapse">  
90 - <div class="panel-body">  
91 - {% include "search/includes/search_filters.html" %}  
92 - </div>  
93 - </div>  
94 - </div>  
95 - </div>  
96 - <hr />  
97 - </div>  
98 -  
99 <div class="col-md-10 col-lg-10"> 70 <div class="col-md-10 col-lg-10">
100 <ul class="list-unstyled"> 71 <ul class="list-unstyled">
101 {% for result in page.object_list %} 72 {% for result in page.object_list %}
colab/search/tests.py
1 # -*- coding:utf-8 -*- 1 # -*- coding:utf-8 -*-
2 2
  3 +import mock
  4 +
  5 +from colab.plugins.utils import filters_importer
3 from django.test import TestCase, Client 6 from django.test import TestCase, Client
4 from django.core.management import call_command 7 from django.core.management import call_command
5 8
@@ -57,3 +60,23 @@ class SearchViewTest(TestCase): @@ -57,3 +60,23 @@ class SearchViewTest(TestCase):
57 self.assertIn('Chuck', user_list[0].object.first_name) 60 self.assertIn('Chuck', user_list[0].object.first_name)
58 self.assertIn('Norris', user_list[0].object.last_name) 61 self.assertIn('Norris', user_list[0].object.last_name)
59 self.assertIn('chucknorris', user_list[0].object.username) 62 self.assertIn('chucknorris', user_list[0].object.username)
  63 +
  64 + def test_search_plugin_filters(self):
  65 + plugin_filter = {
  66 + 'plugin_name': {
  67 + 'name': 'PluginData',
  68 + 'icon': 'plugin_icon',
  69 + 'fields': (
  70 + ('field_1', 'Field1', ''),
  71 + ('field_2', 'Field2', ''),
  72 + ),
  73 + },
  74 + }
  75 + filters_importer.import_plugin_filters = mock.Mock(
  76 + return_value=plugin_filter)
  77 +
  78 + request = self.client.get('/search/?q=')
  79 +
  80 + value = [('plugin_name', 'PluginData', 'plugin_icon')]
  81 +
  82 + self.assertEqual(request.context['filters_options'], value)
colab/search/views.py
1 # -*- coding:utf-8 -*- 1 # -*- coding:utf-8 -*-
2 2
3 from django.conf import settings 3 from django.conf import settings
4 -from django.utils.translation import ugettext as _  
5 4
6 from haystack.views import SearchView 5 from haystack.views import SearchView
  6 +from colab.plugins.utils import filters_importer
7 7
8 8
9 class ColabSearchView(SearchView): 9 class ColabSearchView(SearchView):
@@ -13,127 +13,6 @@ class ColabSearchView(SearchView): @@ -13,127 +13,6 @@ class ColabSearchView(SearchView):
13 self.request.LANGUAGE_CODE, (None, None) 13 self.request.LANGUAGE_CODE, (None, None)
14 ) 14 )
15 15
16 - types = {  
17 - 'thread': {  
18 - 'name': _(u'Discussion'),  
19 - 'fields': (  
20 - ('author', _(u'Author'), self.request.GET.get('author')),  
21 - (  
22 - 'list',  
23 - _(u'Mailinglist'),  
24 - self.request.GET.getlist('list')  
25 - ),  
26 - ),  
27 - },  
28 - }  
29 - # TODO: Replace for a more generic plugin architecture  
30 - # if settings.TRAC_ENABLED:  
31 - # types['wiki'] = {  
32 - # 'name': _(u'Wiki'),  
33 - # 'fields': (  
34 - # ('author', _(u'Author'), self.request.GET.get('author')),  
35 - # (  
36 - # 'collaborators',  
37 - # _(u'Collaborators'),  
38 - # self.request.GET.get('collaborators'),  
39 - # ),  
40 - # ),  
41 - # }  
42 -  
43 - # types['ticket'] = {  
44 - # 'name': _(u'Ticket'),  
45 - # 'fields': (  
46 - # (  
47 - # 'milestone',  
48 - # _(u'Milestone'),  
49 - # self.request.GET.get('milestone')  
50 - # ),  
51 - # (  
52 - # 'priority',  
53 - # _(u'Priority'),  
54 - # self.request.GET.get('priority')  
55 - # ),  
56 - # (  
57 - # 'component',  
58 - # _(u'Component'),  
59 - # self.request.GET.get('component')  
60 - # ),  
61 - # (  
62 - # 'severity',  
63 - # _(u'Severity'),  
64 - # self.request.GET.get('severity')  
65 - # ),  
66 - # (  
67 - # 'reporter',  
68 - # _(u'Reporter'),  
69 - # self.request.GET.get('reporter')  
70 - # ),  
71 - # ('author', _(u'Author'), self.request.GET.get('author')),  
72 - # ('tag', _(u'Status'), self.request.GET.get('tag')),  
73 - # (  
74 - # 'keywords',  
75 - # _(u'Keywords'),  
76 - # self.request.GET.get('keywords'),  
77 - # ),  
78 - # (  
79 - # 'collaborators',  
80 - # _(u'Collaborators'),  
81 - # self.request.GET.get('collaborators')  
82 - # ),  
83 - # ),  
84 - # }  
85 -  
86 - # types['changeset'] = {  
87 - # 'name': _(u'Changeset'),  
88 - # 'fields': (  
89 - # ('author', _(u'Author'), self.request.GET.get('author')),  
90 - # (  
91 - # 'repository_name',  
92 - # _(u'Repository'),  
93 - # self.request.GET.get('repository_name'),  
94 - # ),  
95 - # )  
96 - # }  
97 -  
98 - # types['user'] = {  
99 - # 'name': _(u'User'),  
100 - # 'fields': (  
101 - # (  
102 - # 'username',  
103 - # _(u'Username'),  
104 - # self.request.GET.get('username'),  
105 - # ),  
106 - # ('name', _(u'Name'), self.request.GET.get('name')),  
107 - # (  
108 - # 'institution',  
109 - # _(u'Institution'),  
110 - # self.request.GET.get('institution'),  
111 - # ),  
112 - # ('role', _(u'Role'), self.request.GET.get('role'))  
113 - # ),  
114 - # }  
115 -  
116 - # types['attachment'] = {  
117 - # 'name': _(u'Attachment'),  
118 - # 'fields': (  
119 - # (  
120 - # 'filename',  
121 - # _(u'Filename'),  
122 - # self.request.GET.get('filename')  
123 - # ),  
124 - # ('author', _(u'Author'), self.request.GET.get('author')),  
125 - # (  
126 - # 'used_by',  
127 - # _(u'Used by'), self.request.GET.get('used_by')),  
128 - # (  
129 - # 'mimetype',  
130 - # _(u'File type'),  
131 - # self.request.GET.get('mimetype')  
132 - # ),  
133 - # ('size', _(u'Size'), self.request.GET.get('size')),  
134 - # )  
135 - # }  
136 -  
137 try: 16 try:
138 type_chosen = self.form.cleaned_data.get('type') 17 type_chosen = self.form.cleaned_data.get('type')
139 except AttributeError: 18 except AttributeError:
@@ -143,26 +22,17 @@ class ColabSearchView(SearchView): @@ -143,26 +22,17 @@ class ColabSearchView(SearchView):
143 size_choices = () 22 size_choices = ()
144 used_by_choices = () 23 used_by_choices = ()
145 24
146 - # if type_chosen == 'attachment':  
147 - # mimetype_choices = [  
148 - # (type_, display)  
149 - # for type_, display, mimelist_ in settings.FILE_TYPE_GROUPINGS]  
150 - # size_choices = [  
151 - # ('<500KB', u'< 500 KB'),  
152 - # ('500KB__10MB', u'>= 500 KB <= 10 MB'),  
153 - # ('>10MB', u'> 10 MB'),  
154 - # ]  
155 - # used_by_choices = set([  
156 - # (v, v) for v in Attachment.objects.values_list('used_by',  
157 - # flat=True)  
158 - # ])  
159 -  
160 mimetype_chosen = self.request.GET.get('mimetype') 25 mimetype_chosen = self.request.GET.get('mimetype')
161 size_chosen = self.request.GET.get('size') 26 size_chosen = self.request.GET.get('size')
162 used_by_chosen = self.request.GET.get('used_by') 27 used_by_chosen = self.request.GET.get('used_by')
163 28
  29 + types = filters_importer.import_plugin_filters(self.request.GET)
  30 +
  31 + filters_options = [(k, v['name'], v['icon'])
  32 + for (k, v) in types.iteritems()]
164 return dict( 33 return dict(
165 filters=types.get(type_chosen), 34 filters=types.get(type_chosen),
  35 + filters_options=filters_options,
166 type_chosen=type_chosen, 36 type_chosen=type_chosen,
167 order_data=settings.ORDERING_DATA, 37 order_data=settings.ORDERING_DATA,
168 date_format=date_format, 38 date_format=date_format,
colab/super_archives/filters.py 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +from django.utils.translation import ugettext as _
  2 +from colab.super_archives.models import MailingList
  3 +
  4 +
  5 +def get_filters(request):
  6 + return {
  7 + 'thread': {
  8 + 'name': _(u'Discussion'),
  9 + 'icon': 'envelope',
  10 + 'fields': (
  11 + ('author', _(u'Author'), request.get('author')),
  12 + (
  13 + 'list',
  14 + _(u'Mailinglist'),
  15 + request.get('list'),
  16 + 'list',
  17 + [(v, v) for v in MailingList.objects.values_list(
  18 + 'name', flat=True)]
  19 + ),
  20 + ),
  21 + },
  22 + }