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
27 def __init__(self, filters):
28 self.filters = filters
33 """The 'name' of the filter, to be displayed in the filter UI"""
37 """The current condition of the filter, to be displayed in the
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."""
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"""
52 def parse(self, dict):
53 if self.param not in dict.keys():
55 self._set_key(dict[self.param])
57 def url_without_me(self):
58 return self.filters.querystring_without_filter(self)
60 def form_function(self):
61 return 'function(form) { return "unimplemented" }'
65 return mark_safe('<input type="hidden" value="%s">%s' % (self.param,
67 return self.condition()
74 return '%s: %s' % (self.name, self.kwargs())
77 class SubmitterFilter(Filter):
79 def __init__(self, filters):
80 super(SubmitterFilter, self).__init__(filters)
81 self.name = 'Submitter'
83 self.person_match = None
85 def _set_key(self, str):
87 self.person_match = None
90 submitter_id = int(str)
97 self.person = Person.objects.get(id = int(str))
102 people = Person.objects.filter(name__icontains = str)
107 self.person_match = str
112 user = self.person.user
114 return {'submitter__in':
115 Person.objects.filter(user = user).values('pk').query}
116 return {'submitter': self.person}
118 if self.person_match:
119 return {'submitter__name__icontains': self.person_match}
124 return self.person.name
125 elif self.person_match:
126 return self.person_match
132 name = self.person.name
133 return mark_safe(('<input onKeyUp="submitter_field_change(this)" ' +
134 'name="submitter" id="submitter_input" ' +
135 'value="%s"> ' % escape(name)) +
136 '<select id="submitter_select" ' +
137 'disabled="true"></select>')
141 return self.person.id
142 return self.person_match
144 class StateFilter(Filter):
147 action_req_str = 'Action Required'
149 def __init__(self, filters):
150 super(StateFilter, self).__init__(filters)
155 def _set_key(self, str):
158 if str == self.any_key:
163 self.state = State.objects.get(id=int(str))
170 if self.state is not None:
171 return {'state': self.state}
173 return {'state__in': \
174 State.objects.filter(action_required = True) \
179 return self.state.name
180 return self.action_req_str
183 if self.state is not None:
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():
195 if self.state and self.state == state:
196 selected = ' selected="true"'
198 str += '<option value="%d" %s>%s</option>' % \
199 (state.id, selected, state.name)
201 return mark_safe(str);
203 def form_function(self):
204 return 'function(form) { return form.x.value }'
206 def url_without_me(self):
207 qs = self.filters.querystring_without_filter(self)
210 return qs + '%s=%s' % (self.param, self.any_key)
212 class SearchFilter(Filter):
214 def __init__(self, filters):
215 super(SearchFilter, self).__init__(filters)
220 def _set_key(self, str):
228 return {'name__icontains': self.search}
239 value = escape(self.search)
240 return mark_safe('<input name="%s" value="%s">' %\
243 def form_function(self):
244 return mark_safe('function(form) { return form.x.value }')
246 class ArchiveFilter(Filter):
248 def __init__(self, filters):
249 super(ArchiveFilter, self).__init__(filters)
250 self.name = 'Archived'
251 self.archive_state = False
258 self.description_map = {
264 def _set_key(self, str):
265 self.archive_state = False
267 for (k, v) in self.param_map.iteritems():
269 self.archive_state = k
270 if self.archive_state == None:
274 if self.archive_state == None:
276 return {'archived': self.archive_state}
279 return self.description_map[self.archive_state]
282 if self.archive_state == False:
284 return self.param_map[self.archive_state]
288 for b in [False, True, None]:
289 label = self.description_map[b]
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 ' ') % \
298 'selected': selected,
299 'value': self.param_map[b]
303 def url_without_me(self):
304 qs = self.filters.querystring_without_filter(self)
307 return qs + 'archive=both'
310 class DelegateFilter(Filter):
314 def __init__(self, filters):
315 super(DelegateFilter, self).__init__(filters)
316 self.name = 'Delegate'
317 self.param = 'delegate'
319 # default to applied, but no delegate - this will result in patches with
324 def _set_key(self, str):
332 self.delegate = User.objects.get(id = str)
340 return {'delegate': self.delegate}
344 return self.delegate.get_profile().name()
348 delegates = User.objects.filter(userprofile__maintainer_projects =
349 self.filters.project)
351 str = '<select name="delegate">'
355 selected = 'selected'
357 str += '<option %s value="*">------</option>' % selected
360 if self.delegate is None:
361 selected = 'selected'
363 str += '<option %s value="">Nobody</option>' % selected
367 if d == self.delegate:
368 selected = ' selected'
370 str += '<option %s value="%s">%s</option>' % (selected,
371 d.id, d.get_profile().name())
374 return mark_safe(str)
378 return self.delegate.id
383 def url_without_me(self):
384 qs = self.filters.querystring_without_filter(self)
387 return qs + ('%s=*' % self.param)
389 def set_status(self, *args, **kwargs):
390 if 'delegate' in kwargs:
391 self.applied = self.forced = True
392 self.delegate = kwargs['delegate']
393 if self.AnyDelegate in args:
397 filterclasses = [SubmitterFilter, \
405 def __init__(self, request):
406 self._filters = map(lambda c: c(self), filterclasses)
407 self.dict = request.GET
410 for f in self._filters:
413 def set_project(self, project):
414 self.project = project
416 def filter_conditions(self):
418 for f in self._filters:
420 kwargs.update(f.kwargs())
423 def apply(self, queryset):
424 kwargs = self.filter_conditions()
427 return queryset.filter(**kwargs)
430 return [ (f.param, f.key()) for f in self._filters \
431 if f.key() is not None ]
433 def querystring(self, remove = None):
434 params = dict(self.params())
436 for (k, v) in self.dict.iteritems():
440 if remove is not None:
441 if remove.param in params.keys():
442 del params[remove.param]
444 return '?' + '&'.join(['%s=%s' % x for x in params.iteritems()])
446 def querystring_without_filter(self, filter):
447 return self.querystring(filter)
449 def applied_filters(self):
450 return filter(lambda x: x.applied, self._filters)
452 def available_filters(self):
455 def set_status(self, filterclass, *args, **kwargs):
456 for f in self._filters:
457 if isinstance(f, filterclass):
458 f.set_status(*args, **kwargs)