Commit 0de20def88c698cd8a23188dc1eb0ac043e6427c
Exists in
master
and in
39 other branches
Merge branch 'haystack'
Showing
6 changed files
with
219 additions
and
78 deletions
Show diff stats
src/search/forms.py
... | ... | @@ -8,13 +8,35 @@ from django.utils.translation import ugettext_lazy as _ |
8 | 8 | from haystack.forms import SearchForm |
9 | 9 | |
10 | 10 | from accounts.models import User |
11 | -from super_archives.models import Message | |
11 | +from super_archives.models import Message, MailingList | |
12 | 12 | |
13 | 13 | |
14 | 14 | class ColabSearchForm(SearchForm): |
15 | 15 | q = forms.CharField(label=_('Search'), required=False) |
16 | 16 | order = forms.CharField(widget=forms.HiddenInput(), required=False) |
17 | 17 | type = forms.CharField(required=False, label=_(u'Type')) |
18 | + author = forms.CharField(required=False, label=_(u'Author')) | |
19 | + # ticket status | |
20 | + tag = forms.CharField(required=False, label=_(u'Status')) | |
21 | + # mailinglist tag | |
22 | + list = forms.MultipleChoiceField( | |
23 | + required=False, | |
24 | + label=_(u'Mailinglist'), | |
25 | + choices=[(v, v) for v in MailingList.objects.values('name') | |
26 | + for (v, v) in v.items()] | |
27 | + ) | |
28 | + milestone = forms.CharField(required=False, label=_(u'Milestone')) | |
29 | + priority = forms.CharField(required=False, label=_(u'Priority')) | |
30 | + component = forms.CharField(required=False, label=_(u'Component')) | |
31 | + severity = forms.CharField(required=False, label=_(u'Severity')) | |
32 | + reporter = forms.CharField(required=False, label=_(u'Reporter')) | |
33 | + keywords = forms.CharField(required=False, label=_(u'Keywords')) | |
34 | + collaborators = forms.CharField(required=False, label=_(u'Collaborators')) | |
35 | + repository_name = forms.CharField(required=False, label=_(u'Repository')) | |
36 | + username = forms.CharField(required=False, label=_(u'Username')) | |
37 | + name = forms.CharField(required=False, label=_(u'Name')) | |
38 | + institution = forms.CharField(required=False, label=_(u'Institution')) | |
39 | + role = forms.CharField(required=False, label=_(u'Role')) | |
18 | 40 | |
19 | 41 | def search(self): |
20 | 42 | if not self.is_valid(): |
... | ... | @@ -33,25 +55,44 @@ class ColabSearchForm(SearchForm): |
33 | 55 | types = self.cleaned_data['type'] |
34 | 56 | sqs = sqs.filter(type__in=types.split()) |
35 | 57 | |
36 | - | |
37 | 58 | if self.cleaned_data['order']: |
38 | 59 | for option, dict_order in settings.ORDERING_DATA.items(): |
39 | 60 | if self.cleaned_data['order'] == option: |
40 | 61 | if dict_order['fields']: |
41 | 62 | sqs = sqs.order_by(*dict_order['fields']) |
42 | - # if self.cleaned_data['type'] == 'user': | |
43 | - # sqs = self.searchqueryset.models(User) | |
44 | - # elif self.cleaned_data['type'] in ['message', 'thread']: | |
45 | - # sqs = self.searchqueryset.models(Message) | |
46 | - # elif self.cleaned_data['type'] == 'wiki': | |
47 | - # sqs = self.searchqueryset.models(Wiki) | |
48 | - # elif self.cleaned_data['type'] == 'changeset': | |
49 | - # sqs = self.searchqueryset.models(Changeset) | |
50 | - # elif self.cleaned_data['type'] == 'ticket': | |
51 | - # sqs = self.searchqueryset.models(Ticket) | |
52 | - # else: | |
53 | - # sqs = self.searchqueryset.all() | |
54 | 63 | |
64 | + if self.cleaned_data['author']: | |
65 | + sqs = sqs.filter(author=self.cleaned_data['author']) | |
66 | + | |
67 | + if self.cleaned_data['milestone']: | |
68 | + sqs = sqs.filter(milestone=self.cleaned_data['milestone']) | |
69 | + if self.cleaned_data['priority']: | |
70 | + sqs = sqs.filter(priority=self.cleaned_data['priority']) | |
71 | + if self.cleaned_data['severity']: | |
72 | + sqs = sqs.filter(severity=self.cleaned_data['severity']) | |
73 | + if self.cleaned_data['reporter']: | |
74 | + sqs = sqs.filter(reporter=self.cleaned_data['reporter']) | |
75 | + if self.cleaned_data['keywords']: | |
76 | + sqs = sqs.filter(keywords=self.cleaned_data['keywords']) | |
77 | + if self.cleaned_data['collaborators']: | |
78 | + sqs = sqs.filter(collaborators=self.cleaned_data['collaborators']) | |
79 | + if self.cleaned_data['repository_name']: | |
80 | + sqs = sqs.filter( | |
81 | + repository_name=self.cleaned_data['repository_name'] | |
82 | + ) | |
83 | + if self.cleaned_data['username']: | |
84 | + sqs = sqs.filter(username=self.cleaned_data['username']) | |
85 | + if self.cleaned_data['name']: | |
86 | + sqs = sqs.filter(name=self.cleaned_data['name']) | |
87 | + if self.cleaned_data['institution']: | |
88 | + sqs = sqs.filter(institution=self.cleaned_data['institution']) | |
89 | + if self.cleaned_data['role']: | |
90 | + sqs = sqs.filter(role=self.cleaned_data['role']) | |
91 | + if self.cleaned_data['tag']: | |
92 | + sqs = sqs.filter(tag=self.cleaned_data['tag']) | |
93 | + | |
94 | + if self.cleaned_data['list']: | |
95 | + sqs = sqs.filter(tag__in=self.cleaned_data['list']) | |
55 | 96 | |
56 | 97 | if self.load_all: |
57 | 98 | sqs = sqs.load_all() | ... | ... |
src/search/views.py
1 | 1 | # -*- coding:utf-8 -*- |
2 | 2 | |
3 | 3 | from django.conf import settings |
4 | +from django.utils.translation import ugettext as _ | |
5 | + | |
4 | 6 | from haystack.views import SearchView |
5 | 7 | |
6 | 8 | |
7 | 9 | class ColabSearchView(SearchView): |
8 | 10 | def extra_context(self, *args, **kwargs): |
9 | - # Retornar todos os campos de cada tipo a serem filtrados | |
10 | - # retornar os nomes dos campos | |
11 | - # retornar os ícones dos tipos | |
12 | - | |
13 | - # a critical point on the system | |
14 | 11 | types = { |
15 | 12 | 'wiki': { |
16 | 13 | 'icon': 'file', |
17 | - 'fields': [ | |
18 | - 'title', 'description', 'author', 'collaborators', | |
19 | - 'created', 'modified', | |
20 | - ], | |
14 | + 'name': _(u'Wiki'), | |
15 | + 'fields': ( | |
16 | + ('author', _(u'Author'), self.request.GET.get('author')), | |
17 | + ), | |
21 | 18 | }, |
22 | - 'discussion': { | |
19 | + 'thread': { | |
23 | 20 | 'icon': 'thread', |
24 | - 'fields': [ | |
25 | - 'title', 'description', 'created', 'modified', 'author', | |
26 | - 'tag', | |
27 | - ], | |
21 | + 'name': _(u'Discussion'), | |
22 | + 'fields': ( | |
23 | + ('author', _(u'Author'), self.request.GET.get('author')), | |
24 | + ( | |
25 | + 'list', | |
26 | + _(u'Mailinglist'), | |
27 | + self.request.GET.getlist('list') | |
28 | + ), | |
29 | + ), | |
28 | 30 | }, |
29 | 31 | 'ticket': { |
30 | 32 | 'icon': 'ticket', |
31 | - 'fields': [ | |
32 | - 'title', 'description', 'milestone', 'priority', | |
33 | - 'component', 'version', 'severity', 'reporter', 'author', | |
34 | - 'status', 'keywords', 'collaborators', 'created', | |
35 | - 'modified', | |
36 | - ], | |
33 | + 'name': _(u'Ticket'), | |
34 | + 'fields': ( | |
35 | + ( | |
36 | + 'milestone', | |
37 | + _(u'Milestone'), | |
38 | + self.request.GET.get('milestone') | |
39 | + ), | |
40 | + ( | |
41 | + 'priority', | |
42 | + _(u'Priority'), | |
43 | + self.request.GET.get('priority') | |
44 | + ), | |
45 | + ( | |
46 | + 'component', | |
47 | + _(u'Component'), | |
48 | + self.request.GET.get('component') | |
49 | + ), | |
50 | + ( | |
51 | + 'severity', | |
52 | + _(u'Severity'), | |
53 | + self.request.GET.get('severity') | |
54 | + ), | |
55 | + ( | |
56 | + 'reporter', | |
57 | + _(u'Reporter'), | |
58 | + self.request.GET.get('reporter') | |
59 | + ), | |
60 | + ('author', _(u'Author'), self.request.GET.get('author')), | |
61 | + ('tag', _(u'Status'), self.request.GET.get('tag')), | |
62 | + ( | |
63 | + 'keywords', | |
64 | + _(u'Keywords'), | |
65 | + self.request.GET.get('keywords'), | |
66 | + ), | |
67 | + ( | |
68 | + 'collaborators', | |
69 | + _(u'Collaborators'), | |
70 | + self.request.GET.get('collaborators') | |
71 | + ), | |
72 | + ), | |
37 | 73 | }, |
38 | 74 | 'changeset': { |
39 | 75 | 'icon': 'changeset', |
40 | - 'fields': [ | |
41 | - 'title', 'author', 'description', 'repository_name', | |
42 | - 'created', 'modified', | |
43 | - ], | |
76 | + 'name': _(u'Changeset'), | |
77 | + 'fields': ( | |
78 | + ('author', _(u'Author'), self.request.GET.get('author')), | |
79 | + ( | |
80 | + 'repository_name', | |
81 | + _(u'Repository'), | |
82 | + self.request.GET.get('repository_name'), | |
83 | + ), | |
84 | + ) | |
44 | 85 | }, |
45 | 86 | 'user': { |
46 | 87 | 'icon': 'user', |
47 | - 'fields': [ | |
48 | - 'title', 'description', 'username', 'name', | |
49 | - 'email', 'institution', 'role', 'google_talk', 'webpage', | |
50 | - ], | |
88 | + 'name': _(u'User'), | |
89 | + 'fields': ( | |
90 | + ( | |
91 | + 'username', | |
92 | + _(u'Username'), | |
93 | + self.request.GET.get('username'), | |
94 | + ), | |
95 | + ('name', _(u'Name'), self.request.GET.get('name')), | |
96 | + ( | |
97 | + 'institution', | |
98 | + _(u'Institution'), | |
99 | + self.request.GET.get('institution'), | |
100 | + ), | |
101 | + ('role', _(u'Role'), self.request.GET.get('role')) | |
102 | + ), | |
51 | 103 | }, |
52 | 104 | } |
53 | - types = self.form.cleaned_data['type'] | |
105 | + | |
106 | + try: | |
107 | + type_chosen = self.form.cleaned_data.get('type') | |
108 | + except AttributeError: | |
109 | + type_chosen = '' | |
110 | + | |
54 | 111 | return dict( |
55 | - types=types.split(), | |
56 | - types_str=types, | |
112 | + filters=types.get(type_chosen), | |
113 | + type_chosen=type_chosen, | |
57 | 114 | order_data=settings.ORDERING_DATA |
58 | 115 | ) | ... | ... |
src/super_archives/templates/message-list.html
... | ... | @@ -27,9 +27,12 @@ |
27 | 27 | <h4>{% trans "Lists" %}</h4> |
28 | 28 | <ul class="unstyled-list"> |
29 | 29 | {% for list in lists %} |
30 | - <li {% if list.name == selected_list %} title="{% trans "Remove filter" %}" class="selected" {% endif %}> | |
31 | - <span class="glyphicon {% if list.name == selected_list %}glyphicon-remove{% else %}glyphicon-chevron-right{% endif %}"></span> <a href="{% ifnotequal list.name selected_list %} {% append_to_get list=list.name p=1 %} {% else %} {% append_to_get list="" p=1 %} | |
32 | - {% endifnotequal %}">{{ list.name }}</a></li> | |
30 | + {% with list.name|add:" "|add:selected_lists as list_name %} | |
31 | + <li {% if list.name in selected_lists %} title="{% trans "Remove filter" %}" class="selected" {% endif %}> | |
32 | + <span class="glyphicon {% if list.name in selected_lists %}glyphicon-remove{% else %}glyphicon-chevron-right{% endif %}"></span> | |
33 | + <a href="{% if not list.name in selected_lists %}{% append_to_get list=list_name p=1 %}{% else %}{% pop_from_get list=list.name %}{% endif %}">{{ list.name }}</a> | |
34 | + </li> | |
35 | + {% endwith %} | |
33 | 36 | {% endfor %} |
34 | 37 | </ul> |
35 | 38 | </div> | ... | ... |
src/super_archives/utils/url.py
... | ... | @@ -19,6 +19,7 @@ def pop_from_get(path, query=None, **kwargs): |
19 | 19 | if query_dict[key] == value: |
20 | 20 | del query_dict[key] |
21 | 21 | continue |
22 | - if not query_dict: | |
23 | - return u'{}?q='.format(path) | |
22 | + if value in query_dict[key]: | |
23 | + aux = query_dict[key].split(value) | |
24 | + query_dict[key] = u''.join(aux).strip() | |
24 | 25 | return u'{}?{}'.format(path, urllib.urlencode(query_dict)) | ... | ... |
src/super_archives/views.py
... | ... | @@ -60,8 +60,9 @@ def thread(request, mailinglist, thread_token): |
60 | 60 | |
61 | 61 | |
62 | 62 | def list_messages(request): |
63 | - | |
64 | - selected_list = request.GET.get('list') | |
63 | + selected_lists = request.GET.get('list', []) | |
64 | + if selected_lists: | |
65 | + selected_lists = selected_lists.split() | |
65 | 66 | |
66 | 67 | order_by = request.GET.get('order') |
67 | 68 | if order_by == 'hottest': |
... | ... | @@ -69,9 +70,9 @@ def list_messages(request): |
69 | 70 | else: |
70 | 71 | threads = queries.get_latest_threads() |
71 | 72 | |
72 | - mail_list = request.GET.get('list') | |
73 | + mail_list = selected_lists | |
73 | 74 | if mail_list: |
74 | - threads = threads.filter(mailinglist__name=mail_list) | |
75 | + threads = threads.filter(mailinglist__name__in=mail_list) | |
75 | 76 | |
76 | 77 | paginator = Paginator(threads, 16) |
77 | 78 | try: |
... | ... | @@ -86,7 +87,7 @@ def list_messages(request): |
86 | 87 | 'lists': lists, |
87 | 88 | 'n_results': paginator.count, |
88 | 89 | 'threads': threads, |
89 | - 'selected_list': selected_list, | |
90 | + 'selected_lists': ' '.join(selected_lists) if selected_lists else '', | |
90 | 91 | 'order_data': settings.ORDERING_DATA, |
91 | 92 | } |
92 | 93 | return render(request, 'message-list.html', template_data) | ... | ... |
src/templates/search/search.html
... | ... | @@ -17,6 +17,42 @@ |
17 | 17 | <div id="filters" class="hidden-xs hidden-sm col-md-2 col-lg-2"> |
18 | 18 | <h3>{% trans "Filters" %}</h3> |
19 | 19 | |
20 | + {% if filters %} | |
21 | + <ul class="unstyled-list"> | |
22 | + <li class="selected" title="{% trans "Remove filter" %}"> | |
23 | + <span class="glyphicon glyphicon-remove"></span> | |
24 | + <a href="{% url 'haystack_search' %}?q={{ request.GET.q }}"> | |
25 | + <span class="glyphicon glyphicon-{{ filters.icon }}"></span> | |
26 | + {{ filters.name }} | |
27 | + </a> | |
28 | + </li> | |
29 | + </ul> | |
30 | + <hr /> | |
31 | + <form role="form"> | |
32 | + <input type="hidden" name="q" value="{{ request.GET.q }}" /> | |
33 | + <input type="hidden" name="type" value="{{ type_chosen }}" /> | |
34 | + | |
35 | + {% for field_lookup, field_display, field_value in filters.fields %} | |
36 | + <div class="form-group"> | |
37 | + <label for="{{ field_lookup }}">{{ field_display }}</label> | |
38 | + {% ifequal field_lookup "list" %} | |
39 | + <select name="{{ field_lookup }}" class="form-control" multiple> | |
40 | + {% for value, option in form.fields.list.choices %} | |
41 | + <option value="{{ value }}" {% if value in field_value %}selected{% endif %}>{{ option }}</option> | |
42 | + {% endfor %} | |
43 | + </select> | |
44 | + {% else %} | |
45 | + <div class="input-group"> | |
46 | + <input type="text" class="form-control" placeholder="{{ field_display }}" name="{{ field_lookup }}" {% if field_value %}value="{{ field_value }}"{% endif %}> | |
47 | + </div> | |
48 | + {% endifequal %} | |
49 | + </div> | |
50 | + {% endfor %} | |
51 | + <input type="submit" class="btn btn-default pull-right" value="{% trans 'Filter' %}" /> | |
52 | + </form> | |
53 | + <br /><hr /> | |
54 | + {% endif %} | |
55 | + | |
20 | 56 | <h4>{% trans "Sort by" %}</h4> |
21 | 57 | <ul class="unstyled-list"> |
22 | 58 | {% for option, dict_order in order_data.items %} |
... | ... | @@ -33,30 +69,32 @@ |
33 | 69 | {% endfor %} |
34 | 70 | </ul> |
35 | 71 | |
36 | - <h4>{% trans "Types" %}</h4> | |
72 | + {% if not request.GET.type %} | |
73 | + <h4>{% trans "Types" %}</h4> | |
37 | 74 | |
38 | - <ul class="unstyled-list"> | |
39 | - <li> | |
40 | - <span class="glyphicon glyphicon-file"></span> | |
41 | - <a href="{% append_to_get type='wiki' %}">{% trans "Wiki" %}</a> | |
42 | - </li> | |
43 | - <li> | |
44 | - <span class="glyphicon glyphicon-envelope"></span> | |
45 | - <a href="{% append_to_get type='thread' %}">{% trans "Discussion" %}</a> | |
46 | - </li> | |
47 | - <li> | |
48 | - <span class="glyphicon glyphicon-tag"></span> | |
49 | - <a href="{% append_to_get type='ticket' %}">{% trans "Ticket" %}</a> | |
50 | - </li> | |
51 | - <li> | |
52 | - <span class="glyphicon glyphicon-align-right"></span> | |
53 | - <a href="{% append_to_get type='changeset' %}">{% trans "Changeset" %}</a> | |
54 | - </li> | |
55 | - <li> | |
56 | - <span class="glyphicon glyphicon-user"></span> | |
57 | - <a href="{% append_to_get type='user' %}">{% trans "User" %}</a> | |
58 | - </li> | |
59 | - </ul> | |
75 | + <ul class="unstyled-list"> | |
76 | + <li> | |
77 | + <span class="glyphicon glyphicon-file"></span> | |
78 | + <a href="{% append_to_get type='wiki' %}">{% trans "Wiki" %}</a> | |
79 | + </li> | |
80 | + <li> | |
81 | + <span class="glyphicon glyphicon-envelope"></span> | |
82 | + <a href="{% append_to_get type='thread' %}">{% trans "Discussion" %}</a> | |
83 | + </li> | |
84 | + <li> | |
85 | + <span class="glyphicon glyphicon-tag"></span> | |
86 | + <a href="{% append_to_get type='ticket' %}">{% trans "Ticket" %}</a> | |
87 | + </li> | |
88 | + <li> | |
89 | + <span class="glyphicon glyphicon-align-right"></span> | |
90 | + <a href="{% append_to_get type='changeset' %}">{% trans "Changeset" %}</a> | |
91 | + </li> | |
92 | + <li> | |
93 | + <span class="glyphicon glyphicon-user"></span> | |
94 | + <a href="{% append_to_get type='user' %}">{% trans "User" %}</a> | |
95 | + </li> | |
96 | + </ul> | |
97 | + {% endif %} | |
60 | 98 | </div> |
61 | 99 | |
62 | 100 | <div class="col-lg-10"> | ... | ... |