summaryrefslogtreecommitdiffstats
path: root/apps/patchwork/filters.py
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2008-08-21 09:38:06 +0800
committerJeremy Kerr <jk@ozlabs.org>2008-08-21 09:38:06 +0800
commitc561ebe710d6e6a43aa4afc6c2036a215378ce87 (patch)
tree7d4a56233ef53a0457646c47895ac5c6e7a65d31 /apps/patchwork/filters.py
downloadpatchwork-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.py433
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">&nbsp;' % 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' + \
+ '&nbsp;&nbsp;&nbsp;&nbsp;') % \
+ {'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