diff options
author | Jeremy Kerr <jk@ozlabs.org> | 2008-08-21 09:38:06 +0800 |
---|---|---|
committer | Jeremy Kerr <jk@ozlabs.org> | 2008-08-21 09:38:06 +0800 |
commit | c561ebe710d6e6a43aa4afc6c2036a215378ce87 (patch) | |
tree | 7d4a56233ef53a0457646c47895ac5c6e7a65d31 /apps/patchwork/filters.py | |
download | patchwork-c561ebe710d6e6a43aa4afc6c2036a215378ce87.tar.bz2 patchwork-c561ebe710d6e6a43aa4afc6c2036a215378ce87.tar.xz |
Inital commit
Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'apps/patchwork/filters.py')
-rw-r--r-- | apps/patchwork/filters.py | 433 |
1 files changed, 433 insertions, 0 deletions
diff --git a/apps/patchwork/filters.py b/apps/patchwork/filters.py new file mode 100644 index 0000000..f7fb652 --- /dev/null +++ b/apps/patchwork/filters.py @@ -0,0 +1,433 @@ +# Patchwork - automated patch tracking system +# Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org> +# +# This file is part of the Patchwork package. +# +# Patchwork is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# Patchwork is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Patchwork; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +from patchwork.models import Person, State +from django.utils.safestring import mark_safe +from django.utils.html import escape +from django.contrib.auth.models import User + +class Filter(object): + def __init__(self, filters): + self.filters = filters + self.applied = False + self.forced = False + + def name(self): + """The 'name' of the filter, to be displayed in the filter UI""" + return self.name + + def condition(self): + """The current condition of the filter, to be displayed in the + filter UI""" + return self.key + + def key(self): + """The key for this filter, to appear in the querystring. A key of + None will remove the param=ley pair from the querystring.""" + return None + + def set_status(self, *kwargs): + """Views can call this to force a specific filter status. For example, + a user's todo page needs to setup the delegate filter to show + that user's delegated patches""" + pass + + def parse(self, dict): + if self.param not in dict.keys(): + return + self._set_key(dict[self.param]) + + def url_without_me(self): + return self.filters.querystring_without_filter(self) + + def form_function(self): + return 'function(form) { return "unimplemented" }' + + def form(self): + if self.forced: + return mark_safe('<input type="hidden" value="%s">%s' % (self.param, + self.condition())) + return self.condition() + return self._form() + + def kwargs(self): + return {} + + def __str__(self): + return '%s: %s' % (self.name, self.kwargs()) + + +class SubmitterFilter(Filter): + param = 'submitter' + def __init__(self, filters): + super(SubmitterFilter, self).__init__(filters) + self.name = 'Submitter' + self.person = None + self.person_match = None + + def _set_key(self, str): + self.person = None + self.person_match = None + submitter_id = None + try: + submitter_id = int(str) + except ValueError: + pass + except: + return + + if submitter_id: + self.person = Person.objects.get(id = int(str)) + self.applied = True + return + + + people = Person.objects.filter(name__icontains = str) + + if not people: + return + + self.person_match = str + self.applied = True + + def kwargs(self): + if self.person: + user = self.person.user + if user: + return {'submitter__in': + Person.objects.filter(user = user).values('pk').query} + return {'submitter': self.person} + + if self.person_match: + return {'submitter__name__icontains': self.person_match} + return {} + + def condition(self): + if self.person: + return self.person.name + elif self.person_match: + return self.person_match + return '' + + def _form(self): + name = '' + if self.person: + name = self.person.name + return mark_safe(('<input onKeyUp="submitter_field_change(this)" ' + + 'name="submitter" id="submitter_input" ' + + 'value="%s"> ' % escape(name)) + + '<select id="submitter_select" ' + + 'disabled="true"></select>') + + def key(self): + if self.person: + return self.person.id + return self.person_match + +class StateFilter(Filter): + param = 'state' + def __init__(self, filters): + super(StateFilter, self).__init__(filters) + self.name = 'State' + self.state = None + + def _set_key(self, str): + try: + self.state = State.objects.get(id=int(str)) + except: + return + + self.applied = True + + def kwargs(self): + return {'state': self.state} + + def condition(self): + return self.state.name + + def key(self): + if self.state is None: + return None + return self.state.id + + def _form(self): + str = '<select name="%s">' % self.param + str += '<option value="">any</option>' + for state in State.objects.all(): + selected = '' + if self.state and self.state == state: + selected = ' selected="true"' + + str += '<option value="%d" %s>%s</option>' % \ + (state.id, selected, state.name) + str += '</select>' + return mark_safe(str); + + def form_function(self): + return 'function(form) { return form.x.value }' + +class SearchFilter(Filter): + param = 'q' + def __init__(self, filters): + super(SearchFilter, self).__init__(filters) + self.name = 'Search' + self.param = 'q' + self.search = None + + def _set_key(self, str): + str = str.strip() + if str == '': + return + self.search = str + self.applied = True + + def kwargs(self): + return {'name__icontains': self.search} + + def condition(self): + return self.search + + def key(self): + return self.search + + def _form(self): + value = '' + if self.search: + value = escape(self.search) + return mark_safe('<input name="%s" value="%s">' %\ + (self.param, value)) + + def form_function(self): + return mark_safe('function(form) { return form.x.value }') + +class ArchiveFilter(Filter): + param = 'archive' + def __init__(self, filters): + super(ArchiveFilter, self).__init__(filters) + self.name = 'Archived' + self.archive_state = False + self.applied = True + self.param_map = { + True: 'true', + False: '', + None: 'both' + } + self.description_map = { + True: 'Yes', + False: 'No', + None: 'Both' + } + + def _set_key(self, str): + self.archive_state = False + self.applied = True + for (k, v) in self.param_map.iteritems(): + if str == v: + self.archive_state = k + if self.archive_state == None: + self.applied = False + + def kwargs(self): + if self.archive_state == None: + return {} + return {'archived': self.archive_state} + + def condition(self): + return self.description_map[self.archive_state] + + def key(self): + if self.archive_state == False: + return None + return self.param_map[self.archive_state] + + def _form(self): + s = '' + for b in [False, True, None]: + label = self.description_map[b] + selected = '' + if self.archive_state == b: + selected = 'checked="true"' + s += ('<input type="radio" name="%(param)s" ' + \ + '%(selected)s value="%(value)s">%(label)s' + \ + ' ') % \ + {'label': label, + 'param': self.param, + 'selected': selected, + 'value': self.param_map[b] + } + return mark_safe(s) + + def url_without_me(self): + qs = self.filters.querystring_without_filter(self) + if qs != '?': + qs += '&' + return qs + 'archive=both' + + +class DelegateFilter(Filter): + param = 'delegate' + AnyDelegate = 1 + + def __init__(self, filters): + super(DelegateFilter, self).__init__(filters) + self.name = 'Delegate' + self.param = 'delegate' + + # default to applied, but no delegate - this will result in patches with + # no delegate + self.delegate = None + self.applied = True + + def _set_key(self, str): + if str == "*": + self.applied = False + self.delegate = None + return + + applied = False + try: + self.delegate = User.objects.get(id = str) + self.applied = True + except: + pass + + def kwargs(self): + if not self.applied: + return {} + return {'delegate': self.delegate} + + def condition(self): + if self.delegate: + return self.delegate.get_profile().name() + return 'Nobody' + + def _form(self): + delegates = User.objects.filter(userprofile__maintainer_projects = + self.filters.project) + + str = '<select name="delegate">' + + selected = '' + if not self.applied: + selected = 'selected' + + str += '<option %s value="*">------</option>' % selected + + selected = '' + if self.delegate is None: + selected = 'selected' + + str += '<option %s value="">Nobody</option>' % selected + + for d in delegates: + selected = '' + if d == self.delegate: + selected = ' selected' + + str += '<option %s value="%s">%s</option>' % (selected, + d.id, d.get_profile().name()) + str += '</select>' + + return mark_safe(str) + + def key(self): + if self.delegate: + return self.delegate.id + if self.applied: + return None + return '*' + + def url_without_me(self): + qs = self.filters.querystring_without_filter(self) + if qs != '?': + qs += '&' + return qs + ('%s=*' % self.param) + + def set_status(self, *args, **kwargs): + if 'delegate' in kwargs: + self.applied = self.forced = True + self.delegate = kwargs['delegate'] + if self.AnyDelegate in args: + self.applied = False + self.forced = True + +filterclasses = [SubmitterFilter, \ + StateFilter, + SearchFilter, + ArchiveFilter, + DelegateFilter] + +class Filters: + + def __init__(self, request): + self._filters = map(lambda c: c(self), filterclasses) + self.dict = request.GET + self.project = None + + for f in self._filters: + f.parse(self.dict) + + def set_project(self, project): + self.project = project + + def filter_conditions(self): + kwargs = {} + for f in self._filters: + if f.applied: + kwargs.update(f.kwargs()) + return kwargs + + def apply(self, queryset): + kwargs = self.filter_conditions() + if not kwargs: + return queryset + return queryset.filter(**kwargs) + + def params(self): + return [ (f.param, f.key()) for f in self._filters \ + if f.key() is not None ] + + def querystring(self, remove = None): + params = dict(self.params()) + + for (k, v) in self.dict.iteritems(): + if k not in params: + params[k] = v[0] + + if remove is not None: + if remove.param in params.keys(): + del params[remove.param] + + return '?' + '&'.join(['%s=%s' % x for x in params.iteritems()]) + + def querystring_without_filter(self, filter): + return self.querystring(filter) + + def applied_filters(self): + return filter(lambda x: x.applied, self._filters) + + def available_filters(self): + return self._filters + + def set_status(self, filterclass, *args, **kwargs): + for f in self._filters: + if isinstance(f, filterclass): + f.set_status(*args, **kwargs) + return |