From bdc7baf25a3ab9cc0382620909348cf4de9af9c0 Mon Sep 17 00:00:00 2001 From: Gaetan Delannay Date: Thu, 14 Jan 2010 17:54:18 +0100 Subject: [PATCH] Bugfix in the search engine, implemented float fields in the advanced search, execute batchjobs as Zope admin. --- bin/backup.py | 15 +++++------ bin/job.py | 25 +++++++++++++------ gen/plone25/mixins/ToolMixin.py | 43 +++++++++++++++++++------------- gen/plone25/skin/widgets.pt | 10 +++++++- gen/plone25/wrappers/__init__.py | 4 +-- 5 files changed, 61 insertions(+), 36 deletions(-) diff --git a/bin/backup.py b/bin/backup.py index 46c8d03..a85b3eb 100644 --- a/bin/backup.py +++ b/bin/backup.py @@ -247,10 +247,10 @@ class ZodbBackupScript: # Check command format if options.command: parts = options.command.split(':') - if len(parts) not in (3,4): + if len(parts) not in (4,5): raise BackupError('Command format must be ' \ - '::' \ - '[:]') + '::' \ + '[:]') def run(self): optParser = OptionParser(usage=ZodbBackupScript.__doc__) @@ -313,10 +313,11 @@ class ZodbBackupScript: type='string') optParser.add_option("-c", "--command", dest="command", help="Command to execute while Zope is running. It must have the " \ - "following format: ::" \ - "[:]. is the path, " \ - "within Zope, to the Plone Site object (if not at the root of " \ - "the Zope hierarchy, use '/' as folder separator); " \ + "following format: ::" \ + ":[:]. is the " \ + "user name of the Zope administrator; is the " \ + "path, within Zope, to the Plone Site object (if not at the " \ + "root of the Zope hierarchy, use '/' as folder separator); " \ " is the name of the Appy application; " \ " is the name of the method to call on the tool " \ "in this Appy application; (optional) are the arguments " \ diff --git a/bin/job.py b/bin/job.py index 530cf78..d06398a 100644 --- a/bin/job.py +++ b/bin/job.py @@ -1,8 +1,9 @@ '''job.py must be executed by a "zopectl run" command and, as single arg, must get a string with the following format: - ::[:]. + ::[:]. + is the userName of the Zope administrator for this instance. is the path, within Zope, to the Plone Site object (if not at the root of the Zope hierarchy, use '/' as folder separator); @@ -16,7 +17,8 @@ are supported). Several arguments must be separated by '*'.''' # ------------------------------------------------------------------------------ -import sys +import sys, transaction + # Check that job.py is called with the right parameters. if len(sys.argv) != 2: print 'job.py was called with wrong args.' @@ -24,20 +26,26 @@ if len(sys.argv) != 2: else: command = sys.argv[1] parts = command.split(':') - if len(parts) not in (3,4): + if len(parts) not in (4,5): print 'job.py was called with wrong args.' print __doc__ else: # Unwrap parameters - if len(parts) == 3: - plonePath, appName, toolMethod = parts + if len(parts) == 4: + zopeUser, plonePath, appName, toolMethod = parts args = () else: - plonePath, appName, toolMethod, args = parts - # Zope was initialized in a minimal way. Complete Zope and Plone - # installation. + zopeUser, plonePath, appName, toolMethod, args = parts + # Zope was initialized in a minimal way. Complete Zope install. from Testing import makerequest app = makerequest.makerequest(app) + # Log as Zope admin + from AccessControl.SecurityManagement import newSecurityManager + user = app.acl_users.getUserById(zopeUser) + if not hasattr(user, 'aq_base'): + user = user.__of__(uf) + newSecurityManager(None, user) + # Get the Plone site ploneSite = app # Initialised with the Zope root object. for elem in plonePath.split('/'): @@ -48,4 +56,5 @@ else: # Execute the method on the tool if args: args = args.split('*') exec 'tool.%s(*args)' % toolMethod + transaction.commit() # ------------------------------------------------------------------------------ diff --git a/gen/plone25/mixins/ToolMixin.py b/gen/plone25/mixins/ToolMixin.py index f25652a..55ad05e 100644 --- a/gen/plone25/mixins/ToolMixin.py +++ b/gen/plone25/mixins/ToolMixin.py @@ -176,17 +176,22 @@ class ToolMixin(AbstractMixin): v = fieldValue[:-1] params[attrName] = {'query':(v,v+'Z'), 'range':'minmax'} elif type(fieldValue) in sequenceTypes: - # We have a range of values instead of a single value - minv, maxv = fieldValue - rangev = 'minmax' - queryv = fieldValue - if minv == None: - rangev = 'max' - queryv = maxv - elif maxv == None: - rangev = 'min' - queryv = minv - params[attrName] = {'query':queryv, 'range':rangev} + if fieldValue and isinstance(fieldValue[0], basestring): + # We have a list of string values (ie: we need to + # search v1 or v2 or...) + params[attrName] = fieldValue + else: + # We have a range of (int, float, DateTime...) values + minv, maxv = fieldValue + rangev = 'minmax' + queryv = fieldValue + if minv == None: + rangev = 'max' + queryv = maxv + elif maxv == None: + rangev = 'min' + queryv = minv + params[attrName] = {'query':queryv, 'range':rangev} else: params[attrName] = fieldValue # Add a sort order if specified @@ -405,9 +410,9 @@ class ToolMixin(AbstractMixin): '''Returns True if request value in key p_key can be considered as empty.''' rq = self.REQUEST.form - if key.endswith('*int'): + if key.endswith('*int') or key.endswith('*float'): # We return True if "from" AND "to" values are empty. - toKey = '%s_to' % key[2:-4] + toKey = '%s_to' % key[2:key.find('*')] return not rq[key].strip() and not rq[toKey].strip() elif key.endswith('*date'): # We return True if "from" AND "to" values are empty. A value is @@ -459,14 +464,16 @@ class ToolMixin(AbstractMixin): attrName, attrType = attrName.split('*') if attrType == 'bool': exec 'attrValue = %s' % attrValue - elif attrType == 'int': + elif attrType in ('int', 'float'): # Get the "from" value if not attrValue.strip(): attrValue = None - else: attrValue = int(attrValue) + else: + exec 'attrValue = %s(attrValue)' % attrType # Get the "to" value toValue = rq.form['%s_to' % attrName[2:]].strip() - if not toValue: toValue = None - else: toValue = int(toValue) + if not toValue: toValue = None + else: + exec 'toValue = %s(toValue)' % attrType attrValue = (attrValue, toValue) elif attrType == 'date': prefix = attrName[2:] @@ -703,6 +710,6 @@ class ToolMixin(AbstractMixin): res = [] for v in validator: text = self.translate('%s_list_%s' % (appyType['label'], v)) - res.append((v, self.truncate(text, 50))) + res.append((v, self.truncate(text, 30))) return res # ------------------------------------------------------------------------------ diff --git a/gen/plone25/skin/widgets.pt b/gen/plone25/skin/widgets.pt index fcd4b0e..c59308f 100644 --- a/gen/plone25/skin/widgets.pt +++ b/gen/plone25/skin/widgets.pt @@ -11,7 +11,15 @@ -

Hello

+
   + + + + + + + +
diff --git a/gen/plone25/wrappers/__init__.py b/gen/plone25/wrappers/__init__.py index 830764d..eb7fa4e 100644 --- a/gen/plone25/wrappers/__init__.py +++ b/gen/plone25/wrappers/__init__.py @@ -283,7 +283,7 @@ class AbstractWrapper: maxResults=maxResults, noSecurity=noSecurity) return [o.appy() for o in res['objects']] - def count(self, klass, **fields): + def count(self, klass, noSecurity=False, **fields): '''Identical to m_search above, but returns the number of objects that match the search instead of returning the objects themselves. Use this method instead of writing len(self.search(...)).''' @@ -291,7 +291,7 @@ class AbstractWrapper: contentType = flavour.o.getPortalType(klass) search = Search('customSearch', **fields) res = self.tool.o.executeQuery(contentType,flavour.number,search=search, - brainsOnly=True) + brainsOnly=True, noSecurity=noSecurity) if res: return res._len # It is a LazyMap instance else: return 0