[Mpuls-commits] r3488 - in base/trunk: . mpulsweb/controllers mpulsweb/lib

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Mon Aug 30 19:37:42 CEST 2010


Author: bh
Date: 2010-08-30 19:37:38 +0200 (Mon, 30 Aug 2010)
New Revision: 3488

Modified:
   base/trunk/ChangeLog
   base/trunk/mpulsweb/controllers/case_bundle.py
   base/trunk/mpulsweb/controllers/case_overview.py
   base/trunk/mpulsweb/lib/search.py
Log:
Make it possible to pass search parameters as a dict, too

* mpulsweb/controllers/case_bundle.py
(CaseBundleController._build_casebundle): Adapt to
parseSearchOptions and parseSortOptions returning dicts.

* mpulsweb/controllers/case_overview.py
(CaseOverviewController.overview): Adapt to parseSearchOptions and
parseSortOptions returning dicts.
(CaseOverviewController.parseSortOptions): Return the options as a
dictionary to make it easier to combine them with the dict
returned by parseSearchOptions

* mpulsweb/lib/search.py (Search.check_list)
(Search.check_search_options): New. Helper functions to check the
search parameters when they're given as a dictionary.
(Search.perform): Accept the search parameters as a dictionary as
well as as a string.
(CaseSearch.convert_form_parameters): Return the converted
parameters as a dictionary, not as a list of strings.
(Search.VALID_OPTIONS): Add "search_string"


Modified: base/trunk/ChangeLog
===================================================================
--- base/trunk/ChangeLog	2010-08-30 14:44:27 UTC (rev 3487)
+++ base/trunk/ChangeLog	2010-08-30 17:37:38 UTC (rev 3488)
@@ -1,5 +1,29 @@
 2010-08-30  Bernhard Herzog  <bh at intevation.de>
 
+	Make it possible to pass search parameters as a dict, too
+
+	* mpulsweb/lib/search.py (Search.check_list)
+	(Search.check_search_options): New. Helper functions to check the
+	search parameters when they're given as a dictionary.
+	(Search.perform): Accept the search parameters as a dictionary as
+	well as as a string.
+	(CaseSearch.convert_form_parameters): Return the converted
+	parameters as a dictionary, not as a list of strings.
+	(Search.VALID_OPTIONS): Add "search_string"
+
+	* mpulsweb/controllers/case_bundle.py
+	(CaseBundleController._build_casebundle): Adapt to
+	parseSearchOptions and parseSortOptions returning dicts.
+
+	* mpulsweb/controllers/case_overview.py
+	(CaseOverviewController.overview): Adapt to parseSearchOptions and
+	parseSortOptions returning dicts.
+	(CaseOverviewController.parseSortOptions): Return the options as a
+	dictionary to make it easier to combine them with the dict
+	returned by parseSearchOptions
+
+2010-08-30  Bernhard Herzog  <bh at intevation.de>
+
 	Unify the way search options and the search string are handled
 	within the search classes.  This is an incompatible change and
 	requires updates to the MPuls applications that override or extend

Modified: base/trunk/mpulsweb/controllers/case_bundle.py
===================================================================
--- base/trunk/mpulsweb/controllers/case_bundle.py	2010-08-30 14:44:27 UTC (rev 3487)
+++ base/trunk/mpulsweb/controllers/case_bundle.py	2010-08-30 17:37:38 UTC (rev 3488)
@@ -238,9 +238,9 @@
 
             search_options = (session.get('CASE_OVERVIEW_SEARCHOPTIONS')
                               or FORM_DEFAULTS)
-            search_str = ";".join(parseSearchOptions(search_options))
+            search = parseSearchOptions(search_options)
             case_bundle = MpulsCaseBundle([case.id for case in
-                                      MpulsCaseOverview().search(search_str)])
+                                           MpulsCaseOverview().search(search)])
         else:
             case_bundle = MpulsCaseBundle(options.get('case_id'))
         return case_bundle

Modified: base/trunk/mpulsweb/controllers/case_overview.py
===================================================================
--- base/trunk/mpulsweb/controllers/case_overview.py	2010-08-30 14:44:27 UTC (rev 3487)
+++ base/trunk/mpulsweb/controllers/case_overview.py	2010-08-30 17:37:38 UTC (rev 3488)
@@ -90,17 +90,15 @@
         search_options = self.parseSearchOptions(form_defaults)
         
         # Sorting the cases
-        search_options.extend(self.parseSortOptions(request.params))
-        search_str = ";".join(search_options)
+        search_options.update(self.parseSortOptions(request.params))
 
-
         if not c.form_errors:
             c.form_errors = {}
         
         # Do the search if there are no errors
         c.cases = MpulsCaseOverview()
         if not c.form_errors:
-            c.cases.search(search_str)
+            c.cases.search(search_options)
 
         # Values used in the template
         #
@@ -128,12 +126,11 @@
 
         # Hide evaluation option if someone did a search for a particular editor
         c.hide_evaluation = False
-        expr = re.compile('.*editor:[0-9]+.*')
-        if expr.match(search_str):
+        if "editor" in search_options:
             c.hide_evaluation = True
 
         overview = render('/casemanagement/overview.mako')
-        
+
         formular_defaults = form_defaults_copy or request.params.mixed()
         return formencode.htmlfill.render(overview,
                                           defaults=formular_defaults,
@@ -156,17 +153,15 @@
         return self.overview()
 
     def parseSortOptions(self, options=None):
-        search_options = []
         sort_field, sort_order = get_sort(options)
-        
+
         # Pass the sort options to the template
-        c.sort_field = sort_field 
+        c.sort_field = sort_field
         c.sort_order = sort_order
 
         # default behavior is to take the sortfield for sorting
-        search_options.append('sort_field:%s' % sort_field)
-        search_options.append('sort_order:%s' % sort_order)
-        return search_options
+        return dict(sort_field=sort_field,
+                    sort_order=sort_order)
 
     def parseSearchOptions(self, options=None):
         return parseSearchOptions(options)

Modified: base/trunk/mpulsweb/lib/search.py
===================================================================
--- base/trunk/mpulsweb/lib/search.py	2010-08-30 14:44:27 UTC (rev 3487)
+++ base/trunk/mpulsweb/lib/search.py	2010-08-30 17:37:38 UTC (rev 3488)
@@ -2,6 +2,7 @@
 import logging
 import sys
 import re
+import functools
 
 import psycopg2.extras
 
@@ -20,7 +21,7 @@
 
 class Search(object):
 
-    VALID_OPTIONS = ()
+    VALID_OPTIONS = ("search_string",)
     MULTI_OPTIONS = ()
 
     SEARCH_QUERY = """
@@ -72,6 +73,61 @@
         options["search_string"] = search
         return options
 
+    def check_list(self, option, values, expected_type, convert=None):
+        """Check that all items in values have the type expected_type.
+        The return value is a list with all items of values that have
+        the expected_type.  Values of other types are omitted from the
+        result, but warnings are written to the log when that happens.
+        If the optional parameter convert is given, it should be a
+        function or other callable object and is applied to all items in
+        the return value.
+        """
+        checked = []
+        for v in values:
+            if not isinstance(v, expected_type):
+                log.warning("Omitting one of the values for option %r because"
+                            " it does not have type %r."
+                            " Value is %r, type of value is %r",
+                            option, expected_type, v, type(v))
+                continue
+            if convert is not None:
+                v = convert(v)
+            checked.append(v)
+        return checked
+
+    def check_search_options(self, options):
+        """Check and sanitize the search options.
+
+        The return value is a dictionary with the options that are
+        considered valid.  With string values converted to only contain
+        characters as determined by the SAVE_SEARCH regular expression.
+        """
+        sanitize_string = functools.partial(SAVE_SEARCH.sub, u'')
+        checked = dict()
+        for key, value in options.iteritems():
+            if key not in self.VALID_OPTIONS:
+                log.warning("Omitting option %r because the key is not valid",
+                            (key, value))
+                continue
+            if key in self.MULTI_OPTIONS:
+                value = self.check_list(key, value, int)
+            elif key == "search_string":
+                value = self.check_list(key, value, basestring,
+                                        sanitize_string)
+            elif isinstance(value, basestring):
+                value = sanitize_string(value)
+            elif isinstance(value, int):
+                # Nothing to do for ints.
+                pass
+            else:
+                log.warning("Omitting option %r because the value has the"
+                            " unsupported type %r", (key, value), type(value))
+                continue
+
+            # else value is most likely an int
+            checked[key] = value
+        return checked
+
     def _build_sql(self, options):
         pass
 
@@ -89,9 +145,18 @@
             db.recycleConnection(con, cur)
         return rows
 
-    def perform(self, search_str):
-        '''Returns the result set of a search based on the search string'''
-        return self.queryDB(self._build_sql(self._parse_search_str(search_str)))
+    def perform(self, search):
+        """Returns the result set of a search.
+        The parameter search should be a dictionary with the search
+        options.  Alternatively, for backwards compatibility it may be a
+        string containing the search options in the format parsed by the
+        _parse_search_str method.
+        """
+        if isinstance(search, basestring):
+            options = self._parse_search_str(search)
+        else:
+            options = self.check_search_options(search)
+        return self.queryDB(self._build_sql(options))
 
 
 class CaseSearch(Search):
@@ -127,54 +192,52 @@
         """Convert form parameters to search options.
         The parameter user is the user object for the current user.
         """
-        search_options = []
+        search_options = dict()
 
         # Searchstring
         if options.get('search_str'):
-            search_options.append(options.get('search_str'))
+            search_options["search_string"] = [options.get('search_str')]
 
         # Status
-        if options.has_key('state'):
-            for s in options['state']:
-                search_options.append('state:%s' % s)
+        if "state" in options:
+            search_options["state"] = options["state"]
 
         # Responsibilty
         # shown cases where the user is editor, or standin or both
-        if options.get('own'):
-            search_options.append('own:%s' % user.id)
-        if options.get('standin'):
-            search_options.append('standin:%s' % user.id)
+        if options.get("own"):
+            search_options["own"] = user.id
+        if options.get("standin"):
+            search_options["standin"] = user.id
 
         # Editor
         # shown cases where the user is editor or all (-1)
-        if options.get('editor') and options.get('editor') != -1:
-            search_options.append('editor:%s' % options.get('editor'))
+        if options.get("editor") and options.get("editor") != -1:
+            search_options["editor"] = options.get("editor")
 
         # Phase
-        if options.has_key('phase'):
-            for pp in options['phase']:
-                # Get phasepart ids for the selected phasepairs. Only if
-                # pairs are defined.
-                pairs = g.mpuls_config.get('phases', 'pairs')
-                if len(pairs) <= 0:
-                    continue
-                for p in pairs[0].get(str(pp), [-1]):
-                    search_options.append('phase:%s' % p)
+        if "phase" in options:
+            # Get phasepart ids for the selected phasepairs. Only if
+            # pairs are defined.
+            pairs = g.mpuls_config.get("phases", "pairs")
+            if pairs:
+                phases = []
+                for pp in options["phase"]:
+                    phases.extend((int(p) for p in pairs[0].get(str(pp), [-1])))
+                search_options["phase"] = phases
+
         # Dates
-        if (options.has_key('sdate')
-            and options.has_key('edate')
-            and options.get('sdate') is not None
-            and options.get('edate') is not None):
-            search_options.append('sdate:%s' % options.get('sdate'))
-            search_options.append('edate:%s' % options.get('edate'))
+        if (options.get("sdate") is not None
+            and options.get("edate") is not None):
+            search_options["sdate"] = options.get("sdate")
+            search_options["edate"] = options.get("edate")
 
         # gender
         if options.get("gender", -2) != -2:
-            search_options.append("gender:%s" % options["gender"])
+            search_options["gender"] = options["gender"]
 
         # branch office
         if options.get("branch"):
-            search_options.append("branch:%s" % options["branch"])
+            search_options["branch"] = options["branch"]
 
         return search_options
 



More information about the Mpuls-commits mailing list