1 # Patchwork - automated patch tracking system
2 # Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
4 # This file is part of the Patchwork package.
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.
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.
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
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 from urllib import quote
28 def __init__(self, filters):
29 self.filters = filters
34 """The 'name' of the filter, to be displayed in the filter UI"""
38 """The current condition of the filter, to be displayed in the
43 """The key for this filter, to appear in the querystring. A key of
44 None will remove the param=ley pair from the querystring."""
47 def set_status(self, *kwargs):
48 """Views can call this to force a specific filter status. For example,
49 a user's todo page needs to setup the delegate filter to show
50 that user's delegated patches"""
53 def parse(self, dict):
54 if self.param not in dict.keys():
56 self._set_key(dict[self.param])
58 def url_without_me(self):
59 return self.filters.querystring_without_filter(self)
61 def form_function(self):
62 return 'function(form) { return "unimplemented" }'
66 return mark_safe('<input type="hidden" value="%s">%s' % (self.param,
68 return self.condition()
75 return '%s: %s' % (self.name, self.kwargs())
78 class SubmitterFilter(Filter):
80 def __init__(self, filters):
81 super(SubmitterFilter, self).__init__(filters)
82 self.name = 'Submitter'
84 self.person_match = None
86 def _set_key(self, str):
88 self.person_match = None
91 submitter_id = int(str)
98 self.person = Person.objects.get(id = int(str))
103 people = Person.objects.filter(name__icontains = str)
108 self.person_match = str
113 user = self.person.user
115 return {'submitter__in':
116 Person.objects.filter(user = user).values('pk').query}
117 return {'submitter': self.person}
119 if self.person_match:
120 return {'submitter__name__icontains': self.person_match}
125 return self.person.name
126 elif self.person_match:
127 return self.person_match
133 name = self.person.name
134 return mark_safe(('<input onKeyUp="submitter_field_change(this)" ' +
135 'name="submitter" id="submitter_input" ' +
136 'value="%s"> ' % escape(name)) +
137 '<select id="submitter_select" ' +
138 'disabled="true"></select>')
142 return self.person.id
143 return self.person_match
145 class StateFilter(Filter):
148 action_req_str = 'Action Required'
150 def __init__(self, filters):
151 super(StateFilter, self).__init__(filters)
156 def _set_key(self, str):
159 if str == self.any_key:
164 self.state = State.objects.get(id=int(str))
171 if self.state is not None:
172 return {'state': self.state}
174 return {'state__in': \
175 State.objects.filter(action_required = True) \
180 return self.state.name
181 return self.action_req_str
184 if self.state is not None:
191 str = '<select name="%s">' % self.param
195 selected = 'selected'
196 str += '<option %s value="%s">any</option>' % (selected, self.any_key)
199 if self.applied and self.state == None:
200 selected = 'selected'
201 str += '<option %s value="">%s</option>' % \
202 (selected, self.action_req_str)
204 for state in State.objects.all():
206 if self.state and self.state == state:
207 selected = ' selected="true"'
209 str += '<option value="%d" %s>%s</option>' % \
210 (state.id, selected, state.name)
212 return mark_safe(str);
214 def form_function(self):
215 return 'function(form) { return form.x.value }'
217 def url_without_me(self):
218 qs = self.filters.querystring_without_filter(self)
221 return qs + '%s=%s' % (self.param, self.any_key)
223 class SearchFilter(Filter):
225 def __init__(self, filters):
226 super(SearchFilter, self).__init__(filters)
231 def _set_key(self, str):
239 return {'name__icontains': self.search}
250 value = escape(self.search)
251 return mark_safe('<input name="%s" value="%s">' %\
254 def form_function(self):
255 return mark_safe('function(form) { return form.x.value }')
257 class ArchiveFilter(Filter):
259 def __init__(self, filters):
260 super(ArchiveFilter, self).__init__(filters)
261 self.name = 'Archived'
262 self.archive_state = False
269 self.description_map = {
275 def _set_key(self, str):
276 self.archive_state = False
278 for (k, v) in self.param_map.iteritems():
280 self.archive_state = k
281 if self.archive_state == None:
285 if self.archive_state == None:
287 return {'archived': self.archive_state}
290 return self.description_map[self.archive_state]
293 if self.archive_state == False:
295 return self.param_map[self.archive_state]
299 for b in [False, True, None]:
300 label = self.description_map[b]
302 if self.archive_state == b:
303 selected = 'checked="true"'
304 s += ('<input type="radio" name="%(param)s" ' + \
305 '%(selected)s value="%(value)s">%(label)s' + \
306 ' ') % \
309 'selected': selected,
310 'value': self.param_map[b]
314 def url_without_me(self):
315 qs = self.filters.querystring_without_filter(self)
318 return qs + 'archive=both'
321 class DelegateFilter(Filter):
323 no_delegate_key = '-'
324 no_delegate_str = 'Nobody'
327 def __init__(self, filters):
328 super(DelegateFilter, self).__init__(filters)
329 self.name = 'Delegate'
330 self.param = 'delegate'
333 def _set_key(self, str):
334 if str == self.no_delegate_key:
341 self.delegate = User.objects.get(id = str)
349 return {'delegate': self.delegate}
353 return self.delegate.get_profile().name()
354 return self.no_delegate_str
357 delegates = User.objects.filter(userprofile__maintainer_projects =
358 self.filters.project)
360 str = '<select name="delegate">'
364 selected = 'selected'
366 str += '<option %s value="">------</option>' % selected
369 if self.applied and self.delegate is None:
370 selected = 'selected'
372 str += '<option %s value="%s">%s</option>' % \
373 (selected, self.no_delegate_key, self.no_delegate_str)
377 if d == self.delegate:
378 selected = ' selected'
380 str += '<option %s value="%s">%s</option>' % (selected,
381 d.id, d.get_profile().name())
384 return mark_safe(str)
388 return self.delegate.id
390 return self.no_delegate_key
393 def set_status(self, *args, **kwargs):
394 if 'delegate' in kwargs:
395 self.applied = self.forced = True
396 self.delegate = kwargs['delegate']
397 if self.AnyDelegate in args:
401 filterclasses = [SubmitterFilter, \
409 def __init__(self, request):
410 self._filters = map(lambda c: c(self), filterclasses)
411 self.dict = request.GET
414 for f in self._filters:
417 def set_project(self, project):
418 self.project = project
420 def filter_conditions(self):
422 for f in self._filters:
424 kwargs.update(f.kwargs())
427 def apply(self, queryset):
428 kwargs = self.filter_conditions()
431 return queryset.filter(**kwargs)
434 return [ (f.param, f.key()) for f in self._filters \
435 if f.key() is not None ]
437 def querystring(self, remove = None):
438 params = dict(self.params())
440 for (k, v) in self.dict.iteritems():
444 if remove is not None:
445 if remove.param in params.keys():
446 del params[remove.param]
448 pairs = params.iteritems()
451 if not isinstance(s, basestring):
453 return quote(s.encode('utf-8'))
455 return '?' + '&'.join(['%s=%s' % map(sanitise, p) for p in pairs])
457 def querystring_without_filter(self, filter):
458 return self.querystring(filter)
460 def applied_filters(self):
461 return filter(lambda x: x.applied, self._filters)
463 def available_filters(self):
466 def set_status(self, filterclass, *args, **kwargs):
467 for f in self._filters:
468 if isinstance(f, filterclass):
469 f.set_status(*args, **kwargs)