]> git.ozlabs.org Git - patchwork/blob - apps/patchwork/filters.py
Don't apply delegate = Nobody filter by default
[patchwork] / apps / patchwork / filters.py
1 # Patchwork - automated patch tracking system
2 # Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
3 #
4 # This file is part of the Patchwork package.
5 #
6 # Patchwork is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # Patchwork is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Patchwork; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20
21 from patchwork.models import Person, State
22 from django.utils.safestring import mark_safe
23 from django.utils.html import escape
24 from django.contrib.auth.models import User
25
26 class Filter(object):
27     def __init__(self, filters):
28         self.filters = filters
29         self.applied = False
30         self.forced = False
31
32     def name(self):
33         """The 'name' of the filter, to be displayed in the filter UI"""
34         return self.name
35
36     def condition(self):
37         """The current condition of the filter, to be displayed in the
38            filter UI"""
39         return self.key
40
41     def key(self):
42         """The key for this filter, to appear in the querystring. A key of
43            None will remove the param=ley pair from the querystring."""
44         return None
45
46     def set_status(self, *kwargs):
47         """Views can call this to force a specific filter status. For example,
48            a user's todo page needs to setup the delegate filter to show
49            that user's delegated patches"""
50         pass
51
52     def parse(self, dict):
53         if self.param not in dict.keys():
54             return
55         self._set_key(dict[self.param])
56
57     def url_without_me(self):
58         return self.filters.querystring_without_filter(self)
59
60     def form_function(self):
61         return 'function(form) { return "unimplemented" }'
62
63     def form(self):
64         if self.forced:
65             return mark_safe('<input type="hidden" value="%s">%s' % (self.param,
66                         self.condition()))
67             return self.condition()
68         return self._form()
69
70     def kwargs(self):
71         return {}
72
73     def __str__(self):
74         return '%s: %s' % (self.name, self.kwargs())
75
76
77 class SubmitterFilter(Filter):
78     param = 'submitter'
79     def __init__(self, filters):
80         super(SubmitterFilter, self).__init__(filters)
81         self.name = 'Submitter'
82         self.person = None
83         self.person_match = None
84
85     def _set_key(self, str):
86         self.person = None
87         self.person_match = None
88         submitter_id = None
89         try:
90             submitter_id = int(str)
91         except ValueError:
92             pass
93         except:
94             return
95
96         if submitter_id:
97             self.person = Person.objects.get(id = int(str))
98             self.applied = True
99             return
100
101
102         people = Person.objects.filter(name__icontains = str)
103
104         if not people:
105             return
106
107         self.person_match = str
108         self.applied = True
109
110     def kwargs(self):
111         if self.person:
112             user = self.person.user
113             if user:
114                 return {'submitter__in':
115                     Person.objects.filter(user = user).values('pk').query}
116             return {'submitter': self.person}
117
118         if self.person_match:
119             return {'submitter__name__icontains': self.person_match}
120         return {}
121
122     def condition(self):
123         if self.person:
124             return self.person.name
125         elif self.person_match:
126             return self.person_match
127         return ''
128
129     def _form(self):
130         name = ''
131         if self.person:
132             name = self.person.name
133         return mark_safe(('<input onKeyUp="submitter_field_change(this)" ' +
134                 'name="submitter" id="submitter_input" ' +
135                         'value="%s">&nbsp;' % escape(name)) +
136                 '<select id="submitter_select" ' +
137                 'disabled="true"></select>')
138
139     def key(self):
140         if self.person:
141             return self.person.id
142         return self.person_match
143
144 class StateFilter(Filter):
145     param = 'state'
146     any_key = '*'
147     action_req_str = 'Action Required'
148
149     def __init__(self, filters):
150         super(StateFilter, self).__init__(filters)
151         self.name = 'State'
152         self.state = None
153         self.applied = True
154
155     def _set_key(self, str):
156         self.state = None
157
158         if str == self.any_key:
159             self.applied = False
160             return
161
162         try:
163             self.state = State.objects.get(id=int(str))
164         except:
165             return
166
167         self.applied = True
168
169     def kwargs(self):
170         if self.state is not None:
171             return {'state': self.state}
172         else:
173             return {'state__in': \
174                         State.objects.filter(action_required = True) \
175                             .values('pk').query}
176
177     def condition(self):
178         if self.state:
179             return self.state.name
180         return self.action_req_str
181
182     def key(self):
183         if self.state is not None:
184             return self.state.id
185         if not self.applied:
186             return '*'
187         return None
188
189     def _form(self):
190         str = '<select name="%s">' % self.param
191         str += '<option value="%s">any</option>' % self.any_key
192         str += '<option value="">%s</option>' % self.action_req_str
193         for state in State.objects.all():
194             selected = ''
195             if self.state and self.state == state:
196                 selected = ' selected="true"'
197
198             str += '<option value="%d" %s>%s</option>' % \
199                 (state.id, selected, state.name)
200         str += '</select>'
201         return mark_safe(str);
202
203     def form_function(self):
204         return 'function(form) { return form.x.value }'
205
206     def url_without_me(self):
207         qs = self.filters.querystring_without_filter(self)
208         if qs != '?':
209             qs += '&'
210         return qs + '%s=%s' % (self.param, self.any_key)
211
212 class SearchFilter(Filter):
213     param = 'q'
214     def __init__(self, filters):
215         super(SearchFilter, self).__init__(filters)
216         self.name = 'Search'
217         self.param = 'q'
218         self.search = None
219
220     def _set_key(self, str):
221         str = str.strip()
222         if str == '':
223             return
224         self.search = str
225         self.applied = True
226
227     def kwargs(self):
228         return {'name__icontains': self.search}
229
230     def condition(self):
231         return self.search
232
233     def key(self):
234         return self.search
235
236     def _form(self):
237         value = ''
238         if self.search:
239             value = escape(self.search)
240         return mark_safe('<input name="%s" value="%s">' %\
241                 (self.param, value))
242
243     def form_function(self):
244         return mark_safe('function(form) { return form.x.value }')
245
246 class ArchiveFilter(Filter):
247     param = 'archive'
248     def __init__(self, filters):
249         super(ArchiveFilter, self).__init__(filters)
250         self.name = 'Archived'
251         self.archive_state = False
252         self.applied = True
253         self.param_map = {
254             True: 'true',
255             False: '',
256             None:  'both'
257         }
258         self.description_map = {
259             True: 'Yes',
260             False: 'No',
261             None: 'Both'
262         }
263
264     def _set_key(self, str):
265         self.archive_state = False
266         self.applied = True
267         for (k, v) in self.param_map.iteritems():
268             if str == v:
269                 self.archive_state = k
270         if self.archive_state == None:
271             self.applied = False
272
273     def kwargs(self):
274         if self.archive_state == None:
275             return {}
276         return {'archived': self.archive_state}
277
278     def condition(self):
279         return self.description_map[self.archive_state]
280
281     def key(self):
282         if self.archive_state == False:
283             return None
284         return self.param_map[self.archive_state]
285
286     def _form(self):
287         s = ''
288         for b in [False, True, None]:
289             label = self.description_map[b]
290             selected = ''
291             if self.archive_state == b:
292                 selected = 'checked="true"'
293             s += ('<input type="radio" name="%(param)s" ' + \
294                    '%(selected)s value="%(value)s">%(label)s' + \
295                    '&nbsp;&nbsp;&nbsp;&nbsp;') % \
296                     {'label': label,
297                      'param': self.param,
298                      'selected': selected,
299                      'value': self.param_map[b]
300                     }
301         return mark_safe(s)
302
303     def url_without_me(self):
304         qs = self.filters.querystring_without_filter(self)
305         if qs != '?':
306             qs += '&'
307         return qs + 'archive=both'
308
309
310 class DelegateFilter(Filter):
311     param = 'delegate'
312     no_delegate_key = '-'
313     no_delegate_str = 'Nobody'
314     AnyDelegate = 1
315
316     def __init__(self, filters):
317         super(DelegateFilter, self).__init__(filters)
318         self.name = 'Delegate'
319         self.param = 'delegate'
320         self.delegate = None
321
322     def _set_key(self, str):
323         if str == self.no_delegate_key:
324             self.applied = True
325             self.delegate = None
326             return
327
328         applied = False
329         try:
330             self.delegate = User.objects.get(id = str)
331             self.applied = True
332         except:
333             pass
334
335     def kwargs(self):
336         if not self.applied:
337             return {}
338         return {'delegate': self.delegate}
339
340     def condition(self):
341         if self.delegate:
342             return self.delegate.get_profile().name()
343         return self.no_delegate_str
344
345     def _form(self):
346         delegates = User.objects.filter(userprofile__maintainer_projects =
347                 self.filters.project)
348
349         str = '<select name="delegate">'
350
351         selected = ''
352         if not self.applied:
353             selected = 'selected'
354
355         str += '<option %s value="">------</option>' % selected
356
357         selected = ''
358         if self.applied and self.delegate is None:
359             selected = 'selected'
360
361         str += '<option %s value="%s">%s</option>' % \
362                 (selected, self.no_delegate_key, self.no_delegate_str)
363
364         for d in delegates:
365             selected = ''
366             if d == self.delegate:
367                 selected = ' selected'
368
369             str += '<option %s value="%s">%s</option>' % (selected,
370                     d.id, d.get_profile().name())
371         str += '</select>'
372
373         return mark_safe(str)
374
375     def key(self):
376         if self.delegate:
377             return self.delegate.id
378         if self.applied:
379             return self.no_delegate_key
380         return None
381
382     def set_status(self, *args, **kwargs):
383         if 'delegate' in kwargs:
384             self.applied = self.forced = True
385             self.delegate = kwargs['delegate']
386         if self.AnyDelegate in args:
387             self.applied = False
388             self.forced = True
389
390 filterclasses = [SubmitterFilter, \
391                  StateFilter,
392                  SearchFilter,
393                  ArchiveFilter,
394                  DelegateFilter]
395
396 class Filters:
397
398     def __init__(self, request):
399         self._filters = map(lambda c: c(self), filterclasses)
400         self.dict = request.GET
401         self.project = None
402
403         for f in self._filters:
404             f.parse(self.dict)
405
406     def set_project(self, project):
407         self.project = project
408
409     def filter_conditions(self):
410         kwargs = {}
411         for f in self._filters:
412             if f.applied:
413                 kwargs.update(f.kwargs())
414         return kwargs
415
416     def apply(self, queryset):
417         kwargs = self.filter_conditions()
418         if not kwargs:
419             return queryset
420         return queryset.filter(**kwargs)
421
422     def params(self):
423         return [ (f.param, f.key()) for f in self._filters \
424                 if f.key() is not None ]
425
426     def querystring(self, remove = None):
427         params = dict(self.params())
428
429         for (k, v) in self.dict.iteritems():
430             if k not in params:
431                 params[k] = v[0]
432
433         if remove is not None:
434             if remove.param in params.keys():
435                 del params[remove.param]
436
437         return '?' + '&'.join(['%s=%s' % x for x in params.iteritems()])
438
439     def querystring_without_filter(self, filter):
440         return self.querystring(filter)
441
442     def applied_filters(self):
443         return filter(lambda x: x.applied, self._filters)
444
445     def available_filters(self):
446         return self._filters
447
448     def set_status(self, filterclass, *args, **kwargs):
449         for f in self._filters:
450             if isinstance(f, filterclass):
451                 f.set_status(*args, **kwargs)
452                 return