Commit b3c58f18 authored by Ayush Tiwari's avatar Ayush Tiwari Committed by Ayush Tiwari

Products.ERP5Catalog: EPR5-ify catalog.

Move from SQLCatalog to ERP5Catalog as the default Catalog inside ERP5.
The major difference is use of Products.ERP5Type.Core.Folder as Catalog
base class.

Significant addition/changes in
-------------------------------

  ERP5Catalog class:
    Inherit from Catalog class from Products.ZSQLCatalog.SQLCatalog instead of copy-pasting the whole code again.
    Monkey patch some property setters and getters to maintain consistency
    Override getCatalogMethodIds cause it uses global variable in SQLCatalog.Catalog
    Add FilterDict and Filter class to have consistency with `filter_dict` attribute of SQLCatalog

  BusinessTemplate:
    Update BusinessTemplate installation with updated filter_dict
    Also, use dynamic migration while installing the catalog method objects for
    bt5. This way we have SQL Methods migrated just after installation.

  Tests:
    Update tests according to changes in portal_catalog

  SQLCatalog, testZSQLCatalog:
    Cleanup for unusable functions
parent 6f29c8b8
...@@ -153,12 +153,12 @@ SEPARATELY_EXPORTED_PROPERTY_DICT = { ...@@ -153,12 +153,12 @@ SEPARATELY_EXPORTED_PROPERTY_DICT = {
def _getCatalog(acquisition_context): def _getCatalog(acquisition_context):
""" """
Return the id of the SQLCatalog which correspond to the current BT. Return the id of the Catalog which correspond to the current BT.
""" """
catalog_method_id_list = acquisition_context.getTemplateCatalogMethodIdList() catalog_method_id_list = acquisition_context.getTemplateCatalogMethodIdList()
if len(catalog_method_id_list) == 0: if len(catalog_method_id_list) == 0:
try: try:
return acquisition_context.getPortalObject().portal_catalog.objectIds('SQLCatalog')[0] return acquisition_context.getPortalObject().portal_catalog.objectIds()[0]
except IndexError: except IndexError:
return None return None
catalog_method_id = catalog_method_id_list[0] catalog_method_id = catalog_method_id_list[0]
...@@ -1459,7 +1459,7 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -1459,7 +1459,7 @@ class ObjectTemplateItem(BaseTemplateItem):
# an object which cannot (e.g. External Method). # an object which cannot (e.g. External Method).
LOG('BusinessTemplate', WARNING, LOG('BusinessTemplate', WARNING,
'could not restore %r in %r' % (subobject_id, obj)) 'could not restore %r in %r' % (subobject_id, obj))
if obj.meta_type in ('Z SQL Method',): if obj.meta_type in ('Z SQL Method', 'ERP5 SQL Method'):
fixZSQLMethod(portal, obj) fixZSQLMethod(portal, obj)
# portal transforms specific initialization # portal transforms specific initialization
elif obj.meta_type in ('Transform', 'TransformsChain'): elif obj.meta_type in ('Transform', 'TransformsChain'):
...@@ -1951,7 +1951,7 @@ class SkinTemplateItem(ObjectTemplateItem): ...@@ -1951,7 +1951,7 @@ class SkinTemplateItem(ObjectTemplateItem):
if not force and update_dict.get(relative_url) == 'nothing': if not force and update_dict.get(relative_url) == 'nothing':
continue continue
folder = self.unrestrictedResolveValue(p, relative_url) folder = self.unrestrictedResolveValue(p, relative_url)
for obj in folder.objectValues(spec=('Z SQL Method',)): for obj in folder.objectValues(spec=('Z SQL Method', 'ERP5 SQL Method')):
fixZSQLMethod(p, obj) fixZSQLMethod(p, obj)
if folder.aq_parent.meta_type == 'CMF Skins Tool': if folder.aq_parent.meta_type == 'CMF Skins Tool':
registerSkinFolder(skin_tool, folder) registerSkinFolder(skin_tool, folder)
...@@ -2891,14 +2891,23 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): ...@@ -2891,14 +2891,23 @@ class CatalogMethodTemplateItem(ObjectTemplateItem):
"""Extracts properties for a given method in the catalog. """Extracts properties for a given method in the catalog.
Returns a mapping of property name -> boolean """ Returns a mapping of property name -> boolean """
method_properties = PersistentMapping() method_properties = PersistentMapping()
for prop in catalog._properties: property_list = list(catalog._properties)
if catalog.meta_type == 'ERP5 Catalog':
property_list = list(catalog.propertyMap())
for prop in property_list:
if prop.get('select_variable') == 'getCatalogMethodIds': if prop.get('select_variable') == 'getCatalogMethodIds':
# In case the properties are defined via property sheet 'Catalog', the
# object would have two IDs if it is of type 'selection' or
# 'multiple_selection': 'id' and 'base_id', usage of base_id is preferred
# while building objects as it maintains consistency between the old
# catalog and new erp5 catalog
prop_id = prop.get('base_id', prop['id'])
if prop['type'] == 'selection' and \ if prop['type'] == 'selection' and \
getattr(catalog, prop['id']) == method_id: getattr(catalog, prop_id) == method_id:
method_properties[prop['id']] = 1 method_properties[prop_id] = 1
elif prop['type'] == 'multiple selection' and \ elif prop['type'] == 'multiple selection' and \
method_id in getattr(catalog, prop['id']): method_id in getattr(catalog, prop_id):
method_properties[prop['id']] = 1 method_properties[prop_id] = 1
return method_properties return method_properties
def build(self, context, **kw): def build(self, context, **kw):
...@@ -2917,7 +2926,8 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): ...@@ -2917,7 +2926,8 @@ class CatalogMethodTemplateItem(ObjectTemplateItem):
method_id = obj.id method_id = obj.id
self._method_properties[method_id] = self._extractMethodProperties( self._method_properties[method_id] = self._extractMethodProperties(
catalog, method_id) catalog, method_id)
filter = catalog.filter_dict.get(method_id, {}) filter_dict = catalog._getFilterDict()
filter = filter_dict.get(method_id, {})
self._is_filtered_archive[method_id] = filter.get('filtered', 0) self._is_filtered_archive[method_id] = filter.get('filtered', 0)
for method in catalog_method_filter_list: for method in catalog_method_filter_list:
property = method[8:-8] property = method[8:-8]
...@@ -2983,6 +2993,32 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): ...@@ -2983,6 +2993,32 @@ class CatalogMethodTemplateItem(ObjectTemplateItem):
force = kw.get('force') force = kw.get('force')
values = [] values = []
# When the default catalog is of 'ERP5 Catalog' meta_type, its better to ..
# convert all the CatalogMethodTemplateItems in the current BT to the
# allowed types for ERP5 Catalog, i.e, to ERP5 SQLMethod and ERP5 Python Script
# and update the self._objects dict accordingly
if catalog.meta_type == 'ERP5 Catalog':
import erp5
from Products.ERP5.Extensions.CheckPortalTypes import changeObjectClass
# We need the dynamic portal_type classes for changing object classes
sql_class = getattr(erp5.portal_type, 'SQL Method')
script_class = getattr(erp5.portal_type, 'Python Script')
portal = self.getPortalObject()
# Will be modifying dict, so better to use .items()
# XXX: In python3 it should be .copy.items().
for path, obj in self._objects.items():
method = self.unrestrictedResolveValue(portal, path)
method_id = path.split('/')[-1]
if method.meta_type == 'Z SQL Method':
method = changeObjectClass(catalog, method_id, sql_class)
if method.meta_type == 'Script (Python)':
method = changeObjectClass(catalog, method_id, script_class)
method._compile()
new_obj = method.aq_base
self._objects[path] = new_obj
if force: # get all objects if force: # get all objects
values = self._objects.values() values = self._objects.values()
else: # get only selected object else: # get only selected object
...@@ -3009,6 +3045,8 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): ...@@ -3009,6 +3045,8 @@ class CatalogMethodTemplateItem(ObjectTemplateItem):
new_value.sort() new_value.sort()
setattr(catalog, key, tuple(new_value)) setattr(catalog, key, tuple(new_value))
filter_dict = catalog._getFilterDict()
# Restore filter # Restore filter
if self._is_filtered_archive.get(method_id, 0): if self._is_filtered_archive.get(method_id, 0):
expression = self._filter_expression_archive[method_id] expression = self._filter_expression_archive[method_id]
...@@ -3017,16 +3055,15 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): ...@@ -3017,16 +3055,15 @@ class CatalogMethodTemplateItem(ObjectTemplateItem):
expr_instance = Expression(expression) expr_instance = Expression(expression)
else: else:
expr_instance = None expr_instance = None
catalog.filter_dict[method_id] = PersistentMapping() filter_dict[method_id]['filtered'] = 1
catalog.filter_dict[method_id]['filtered'] = 1 filter_dict[method_id]['expression'] = expression
catalog.filter_dict[method_id]['expression'] = expression filter_dict[method_id]['expression_instance'] = expr_instance
catalog.filter_dict[method_id]['expression_instance'] = expr_instance filter_dict[method_id]['expression_cache_key'] = \
catalog.filter_dict[method_id]['expression_cache_key'] = \
self._filter_expression_cache_key_archive.get(method_id, ()) self._filter_expression_cache_key_archive.get(method_id, ())
catalog.filter_dict[method_id]['type'] = \ filter_dict[method_id]['type'] = \
self._filter_type_archive.get(method_id, ()) self._filter_type_archive.get(method_id, ())
elif method_id in catalog.filter_dict.keys(): elif method_id in filter_dict.keys():
catalog.filter_dict[method_id]['filtered'] = 0 filter_dict[method_id]['filtered'] = 0
# backward compatibility # backward compatibility
if hasattr(self, '_is_catalog_list_method_archive'): if hasattr(self, '_is_catalog_list_method_archive'):
...@@ -3082,18 +3119,30 @@ class CatalogMethodTemplateItem(ObjectTemplateItem): ...@@ -3082,18 +3119,30 @@ class CatalogMethodTemplateItem(ObjectTemplateItem):
values.append(value) values.append(value)
for obj in values: for obj in values:
method_id = obj.id method_id = obj.id
property_list = list(catalog._properties)
if catalog.meta_type == 'ERP5 Catalog':
property_list = list(catalog.propertyMap())
# remove method references in portal_catalog # remove method references in portal_catalog
for catalog_prop in catalog._properties: for catalog_prop in property_list:
if catalog_prop.get('select_variable') == 'getCatalogMethodIds'\ if catalog_prop.get('select_variable') == 'getCatalogMethodIds'\
and catalog_prop['type'] == 'multiple selection': and catalog_prop['type'] == 'multiple selection':
old_value = getattr(catalog, catalog_prop['id'], ()) # In case the properties are defined via property sheet 'Catalog', the
# object would have two IDs if it is of type 'selection' or
# 'multiple_selection': 'id' and 'base_id', usage of base_id is preferred
# while building objects as it maintains consistency between the old
# catalog and new erp5 catalog
catalog_prop_id = catalog_prop.get('base_id', catalog_prop['id'])
old_value = getattr(catalog, catalog_prop_id, ())
if method_id in old_value: if method_id in old_value:
new_value = list(old_value) new_value = list(old_value)
new_value.remove(method_id) new_value.remove(method_id)
setattr(catalog, catalog_prop['id'], new_value) # Better to set the attribute value as tuple as it would be consistent
# with both SQL Catalog and ERP5 Catalog.
setattr(catalog, catalog_prop_id, tuple(new_value))
if method_id in catalog.filter_dict: filter_dict = catalog._getFilterDict()
del catalog.filter_dict[method_id] if method_id in filter_dict:
del filter_dict[method_id]
# uninstall objects # uninstall objects
ObjectTemplateItem.uninstall(self, context, **kw) ObjectTemplateItem.uninstall(self, context, **kw)
......
...@@ -191,8 +191,8 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -191,8 +191,8 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
sql_uncatalog_object.remove(method_id) sql_uncatalog_object.remove(method_id)
sql_uncatalog_object.sort() sql_uncatalog_object.sort()
catalog.sql_uncatalog_object = tuple(sql_uncatalog_object) catalog.sql_uncatalog_object = tuple(sql_uncatalog_object)
if method_id in catalog.filter_dict: if method_id in catalog._getFilterDict():
del catalog.filter_dict[method_id] del catalog._getFilterDict()[method_id]
for obj_id in ('another_file', 'test_document', 'dummy_type_provider'): for obj_id in ('another_file', 'test_document', 'dummy_type_provider'):
if obj_id in self.portal.objectIds(): if obj_id in self.portal.objectIds():
self.portal.manage_delObjects([obj_id]) self.portal.manage_delObjects([obj_id])
...@@ -1585,9 +1585,9 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1585,9 +1585,9 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
catalog = pc.getSQLCatalog() catalog = pc.getSQLCatalog()
self.assertTrue(catalog is not None) self.assertTrue(catalog is not None)
method_id = "z_fake_method" method_id = "z_fake_method"
addSQLMethod = catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod addSQLMethod = catalog.newContent
addSQLMethod(id=method_id, title='', connection_id='erp5_sql_connection', addSQLMethod(portal_type='SQL Method', id=method_id, title='',
arguments='', template='') connection_id='erp5_sql_connection', arguments_src='', src='')
zsql_method = catalog._getOb(method_id, None) zsql_method = catalog._getOb(method_id, None)
self.assertTrue(zsql_method is not None) self.assertTrue(zsql_method is not None)
sequence.edit(zsql_method_id = method_id) sequence.edit(zsql_method_id = method_id)
...@@ -1599,21 +1599,20 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1599,21 +1599,20 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
# set filter for this method # set filter for this method
expression = 'python: context.isPredicate()' expression = 'python: context.isPredicate()'
expr_instance = Expression(expression) expr_instance = Expression(expression)
catalog.filter_dict[method_id] = PersistentMapping() zsql_method.setFiltered(1)
catalog.filter_dict[method_id]['filtered'] = 1 zsql_method.setExpression(expression)
catalog.filter_dict[method_id]['expression'] = expression zsql_method.setExpressionInstance(expr_instance)
catalog.filter_dict[method_id]['expression_instance'] = expr_instance zsql_method.setExpressionCacheKey('portal_type')
catalog.filter_dict[method_id]['expression_cache_key'] = 'portal_type', zsql_method.setTypeList([])
catalog.filter_dict[method_id]['type'] = []
def stepCreateUpdateCatalogMethod(self, sequence=None, **kw): def stepCreateUpdateCatalogMethod(self, sequence=None, **kw):
pc = self.getCatalogTool() pc = self.getCatalogTool()
catalog = pc.getSQLCatalog() catalog = pc.getSQLCatalog()
self.assertTrue(catalog is not None) self.assertTrue(catalog is not None)
method_id = "z_fake_method" method_id = "z_fake_method"
addSQLMethod = catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod addSQLMethod = catalog.newContent
addSQLMethod(id=method_id, title='', connection_id='erp5_sql_connection', addSQLMethod(portal_type='SQL Method', id=method_id, title='',
arguments='', template='') connection_id='erp5_sql_connection', arguments_src='', src='')
zsql_method = catalog._getOb(method_id, None) zsql_method = catalog._getOb(method_id, None)
self.assertTrue(zsql_method is not None) self.assertTrue(zsql_method is not None)
sequence.edit(zsql_method_id = method_id) sequence.edit(zsql_method_id = method_id)
...@@ -1625,20 +1624,19 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1625,20 +1624,19 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
# set filter for this method # set filter for this method
expression = 'python: context.isDelivery()' expression = 'python: context.isDelivery()'
expr_instance = Expression(expression) expr_instance = Expression(expression)
catalog.filter_dict[method_id] = PersistentMapping() zsql_method.setFiltered(1)
catalog.filter_dict[method_id]['filtered'] = 1 zsql_method.setExpression(expression)
catalog.filter_dict[method_id]['expression'] = expression zsql_method.setExpressionInstance(expr_instance)
catalog.filter_dict[method_id]['expression_instance'] = expr_instance zsql_method.setExpressionCacheKey('portal_type')
catalog.filter_dict[method_id]['expression_cache_key'] = 'portal_type', zsql_method.setTypeList([])
catalog.filter_dict[method_id]['type'] = []
def stepCreateNewCatalogMethod(self, sequence=None, **kw): def stepCreateNewCatalogMethod(self, sequence=None, **kw):
pc = self.getCatalogTool() pc = self.getCatalogTool()
catalog = pc.getSQLCatalog() catalog = pc.getSQLCatalog()
method_id = "z_another_fake_method" method_id = "z_another_fake_method"
addSQLMethod =catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod addSQLMethod =catalog.newContent
addSQLMethod(id=method_id, title='', connection_id='erp5_sql_connection', addSQLMethod(portal_type='SQL Method', id=method_id, title='',
arguments='', template='') connection_id='erp5_sql_connection', arguments_src='', src='')
zsql_method = catalog._getOb(method_id, None) zsql_method = catalog._getOb(method_id, None)
self.assertTrue(zsql_method is not None) self.assertTrue(zsql_method is not None)
sequence.edit(another_zsql_method_id = method_id) sequence.edit(another_zsql_method_id = method_id)
...@@ -1717,11 +1715,12 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1717,11 +1715,12 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
# check catalog properties # check catalog properties
self.assertIn(method_id, catalog.sql_uncatalog_object) self.assertIn(method_id, catalog.sql_uncatalog_object)
# check filter # check filter
filter_dict = catalog.filter_dict[method_id] filter_dict = catalog.getFilterDict()
filter_dict = filter_dict[method_id]
self.assertItemsEqual(filter_dict['expression_cache_key'], ['portal_type'])
self.assertEqual(filter_dict['type'], [])
self.assertEqual(filter_dict['filtered'], 1) self.assertEqual(filter_dict['filtered'], 1)
self.assertEqual(filter_dict['expression'], 'python: context.isPredicate()') self.assertEqual(filter_dict['expression'], 'python: context.isPredicate()')
self.assertEqual(filter_dict['expression_cache_key'], ('portal_type',))
self.assertEqual(filter_dict['type'], ())
def stepCheckUpdatedCatalogMethodExists(self, sequence=None, **kw): def stepCheckUpdatedCatalogMethodExists(self, sequence=None, **kw):
pc = self.getCatalogTool() pc = self.getCatalogTool()
...@@ -1733,11 +1732,12 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1733,11 +1732,12 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
# check catalog properties # check catalog properties
self.assertIn(method_id, catalog.sql_uncatalog_object) self.assertIn(method_id, catalog.sql_uncatalog_object)
# check filter # check filter
filter_dict = catalog.filter_dict[method_id] filter_dict = catalog.getFilterDict()
filter_dict = filter_dict[method_id]
self.assertItemsEqual(filter_dict['expression_cache_key'], ['portal_type'])
self.assertEqual(filter_dict['type'], [])
self.assertEqual(filter_dict['filtered'], 1) self.assertEqual(filter_dict['filtered'], 1)
self.assertEqual(filter_dict['expression'], 'python: context.isDelivery()') self.assertEqual(filter_dict['expression'], 'python: context.isDelivery()')
self.assertEqual(filter_dict['expression_cache_key'], ('portal_type',))
self.assertEqual(filter_dict['type'], ())
def stepCheckCatalogMethodRemoved(self, sequence=None, **kw): def stepCheckCatalogMethodRemoved(self, sequence=None, **kw):
""" """
...@@ -1752,7 +1752,7 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1752,7 +1752,7 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
# check catalog properties # check catalog properties
self.assertNotIn(method_id, catalog.sql_uncatalog_object) self.assertNotIn(method_id, catalog.sql_uncatalog_object)
# check filter # check filter
self.assertNotIn(method_id, catalog.filter_dict.keys()) self.assertNotIn(method_id, catalog._getFilterDict().keys())
def stepRemoveCatalogMethod(self, sequence=None, **kw): def stepRemoveCatalogMethod(self, sequence=None, **kw):
""" """
...@@ -1772,8 +1772,7 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor): ...@@ -1772,8 +1772,7 @@ class BusinessTemplateMixin(ERP5TypeTestCase, LogInterceptor):
catalog.sql_uncatalog_object = tuple(sql_uncatalog_object) catalog.sql_uncatalog_object = tuple(sql_uncatalog_object)
self.assertNotIn(method_id, catalog.sql_uncatalog_object) self.assertNotIn(method_id, catalog.sql_uncatalog_object)
# remove filter # remove filter
del catalog.filter_dict[method_id] self.assertNotIn(method_id, catalog._getFilterDict().keys())
self.assertNotIn(method_id, catalog.filter_dict.keys())
# Related key, Result key and table, and others # Related key, Result key and table, and others
def stepCreateKeysAndTable(self, sequence=list, **kw): def stepCreateKeysAndTable(self, sequence=list, **kw):
......
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2016 Nexedi SARL and Contributors. All Rights Reserved.
# Ayush Tiwari <ayush.tiwari@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program 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.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5Type.Core.Folder import Folder
from Products.ERP5Type import Permissions
from Products.ERP5Type.Base import Base
from Products.ERP5Type import PropertySheet
from Products.ERP5Type.patches.PropertyManager import PropertyManager
from Products.ZSQLCatalog.SQLCatalog import Catalog, CatalogError
import OFS.History
from AccessControl import ClassSecurityInfo
from Acquisition import aq_base
from Products.CMFCore.Expression import Expression
from zLOG import LOG, INFO, TRACE, WARNING, ERROR
import time
import urllib
class Filter(object):
"""
Class to act as filter object for filterable methods.
Added to keep consistency between how filter objects used to behave earlier
with old SQL Catalog and with the current ERP5 Catalog.
Generally, we do have 5 fixed keys, aka properties for catalog methods.
"""
def __init__(self, method):
self._method = method
def __getitem__(self, key):
#XXX: Temporary hardcode for list_type objects
if key in ('type', 'expression_cache_key'):
return self._method.getPropertyList(key)
return self._method.getProperty(key)
def get(self, key, default=None):
try:
return self[key]
except KeyError:
return default
def __setitem__(self, key, value):
self._method._setProperty(key, value)
def __iter__(self):
return iter(('type', 'expression_cache_key', 'expression',
'filtered', 'expression_instance'))
class FilterDict(object):
"""
Class to act as object everytime we need to use filter_dict as a
dictionary. It doesn't change the fact that the filter properties
are still the properties of catalog methods(SQL Method and Python Scripts).
One of important need of this class is it reduces a lot of copy and patch
which we might had to do to functions in ZSQLCatalog.SQLCatalog.Catalog
class.
Also, as in old SQLCatalog the filter_dict is used as an attribute
of Catalog, but now we have moved it to properties of method,
this class help in keeping the consistency between the old filter_dict
and new filter_dict.
For example:
Old SQL Catalog:
filter_dict = self._getFilterDict() == self.filter_dict == {Persistent Object}
ERP5 Catlaog:
filter_dict = self._getFilterDict() == FilterDict(class) == {Object of this class}
Now, both the filter_dict would have same behaviour without having any impact
on performance or so. The major use of this is in _catalogObjectList, where
we get Filter object, which is easily accessible via __getitem__ for this
class.
"""
def __init__(self, catalog):
self._catalog = catalog
def __getitem__(self, key):
return Filter(self._catalog._getOb(key))
def keys(self):
return self._catalog.getFilterDict().keys()
def __setitem__(self, key, item):
filter_ = self[key]
for k, v in item.iteritems():
filter_[k] = v
def get(self, key, default=None):
# First check if the key is in keys list of the FilterDict, because
# it is possible that the item can be get by doing `self[key]`, even though
# key doesn't exist in self.keys(). So, instead of doing `try : except`,
# we use `if : else`
if key in self:
return self[key]
else:
return default
def __iter__(self):
return iter(self._catalog.getFilterDict())
def __contains__(self, item):
return item in self._catalog.getFilterDict()
def __delitem__(self, key):
filter_ = self[key]
for prop_id in ('type', 'expression_cache_key', 'expression',
'filtered', 'expression_instance'):
filter_._method._delPropValue(prop_id)
class ERP5Catalog(Folder, Catalog):
"""
Catalog Folder inside ERP5 to store indexes
"""
meta_type = "ERP5 Catalog"
portal_type = 'Catalog'
allowed_types = ('Python Script', 'SQL Method',)
#TODO(low priority): Add an icon to display at ERP5 Zope interface
icon = None
# Activate isRADContent cause we need to generate accessors and default values
isRADContent = 1
global valid_method_meta_type_list_new
valid_method_meta_type_list_new = ('ERP5 SQL Method', 'ERP5 Python Script')
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Explicitly add tabs for manage_options
manage_options = ({'label': 'View', 'action': 'view'},
{'label': 'Contents', 'action': 'manage_main'},
{'label': 'Security', 'action': 'manage_access'},
{'label': 'Undo', 'action': 'manage_UndoForm'},
{'label': 'Ownership', 'action': 'manage_owner'},
{'label': 'Interfaces', 'action': 'manage_interfaces'},
{'label': 'Find', 'action': 'manage_findForm'},
{'label': 'History', 'action': 'manage_change_history_page'},
{'label': 'Workflows', 'action': 'manage_workflowsTab'},
)
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.SimpleItem
, PropertySheet.Folder
, PropertySheet.CategoryCore
, PropertySheet.Catalog
)
# Use functions inherited from SQLCatalog for property setters
_setPropValue = Catalog._setPropValue
getProperty = Folder.getProperty
_updateProperty = PropertyManager._updateProperty
# We don't want to index catalog as it might create circular dependencies
isIndexable = 0
__class_init__ = Catalog.__class_init__
def __init__(self, id, title='', container=None):
# Initialize both SQLCatalog as well as Folder
Catalog.__init__(self, id, title, container)
Folder.__init__(self, id)
# Filter content (ZMI))
def filtered_meta_types(self, user=None):
# Filters the list of available meta types.
meta_types = []
for meta_type in self.all_meta_types():
if meta_type['name'] in self.allowed_types:
meta_types.append(meta_type)
return meta_types
def getPropertyType(self, id, local_properties=False):
"""
Overriding the function so as to maintain consistency
between what is returned by 1 and 2
1. erp5_catalog.getProperty(<some_multivalued_property>)
2. sql_catalog.getProperty(<some_multivalued_property>)
This difference arose as now we use ERP5 PropertySheet to define
properties for Catalog which, for the multivalued properties,
generate '<id>' as '<id>_list' and a new attribute 'base_id' in the
propertyMap for the object.
"""
if local_properties:
property_map = getattr(self, '_local_properties', [])
else:
property_map = self._propertyMap()
for md in property_map:
property_id = md.get('base_id', md['id'])
if property_id==id:
return md.get('type', 'string')
return None
##### Overriding setters functions for multple_selection properties #######
##### Required as after every edit we expect the values sorted #######
def _setSqlClearCatalogList(self, value, **kw):
self._baseSetSqlClearCatalogList(sorted(value), **kw)
def _setSqlCatalogFullTextSearchKeysList(self, value, **kw):
self._baseSetSqlCatalogFullTextSearchKeysList(sorted(value), **kw)
def _setSqlCatalogObjectListList(self, value, **kw):
self._baseSetSqlCatalogObjectListList(sorted(value), **kw)
def _setSqlUncatalogObjectList(self, value, **kw):
self._baseSetSqlUncatalogObjectList(sorted(value), **kw)
def _setSqlSearchTablesList(self, value, **kw):
self._baseSetSqlSearchTablesList(sorted(value), **kw)
def _setSqlCatalogDatetimeSearchKeysList(self, value, **kw):
value = sorted(value)
self._baseSetSqlCatalogDatetimeSearchKeysList(sorted(value), **kw)
def _setSqlCatalogKeywordSearchKeysList(self, value, **kw):
self._baseSetSqlCatalogKeywordSearchKeysList(sorted(value), **kw)
def _setSqlCatalogMultivalueKeysList(self, value, **kw):
self._baseSetSqlCatalogMultivalueKeysList(sorted(value), **kw)
def _setSqlCatalogRequestKeysList(self, value, **kw):
self._baseSetSqlCatalogRequestKeysList(sorted(value), **kw)
def _setSqlCatalogIndexOnOrderKeysList(self, value, **kw):
self._baseSetSqlCatalogIndexOnOrderKeysList(sorted(value), **kw)
def _setSqlCatalogTableVoteScriptsList(self, value, **kw):
self._baseSetSqlCatalogTableVoteScriptsList(sorted(value), **kw)
def _setSqlSearchResultKeysList(self, value, **kw):
self._baseSetSqlSearchResultKeysList(sorted(value), **kw)
security.declarePublic('getCatalogMethodIds')
def getCatalogMethodIds(self,
valid_method_meta_type_list=valid_method_meta_type_list_new):
"""Find ERP5 SQL methods in the current folder and above
This function return a list of ids.
"""
return super(ERP5Catalog, self).getCatalogMethodIds(
valid_method_meta_type_list=valid_method_meta_type_list_new)
def manage_catalogReindex(self, REQUEST, RESPONSE=None, URL1=None):
""" Clear the catalog and reindex everything for the erp5 catalog.
"""
elapse = time.time()
c_elapse = time.clock()
self.aq_parent.refreshCatalog(clear=1)
elapse = time.time() - elapse
c_elapse = time.clock() - c_elapse
# Redirect the response to view url
url = self.absolute_url() + '/view' + '?portal_status_message=' \
+ urllib.quote(
'Catalog Updated\r'
'Total time: %s\r'
'Total CPU time: %s' % (`elapse`, `c_elapse`))
return REQUEST.RESPONSE.redirect(url)
def manage_catalogClear(self, REQUEST=None, RESPONSE=None, URL1=None):
""" Clears the catalog
"""
self.beforeCatalogClear()
self._clear()
if REQUEST is None:
return
response = REQUEST.response
if response:
# Redirect the response to view url
url = self.absolute_url() + '/view' \
+ '?portal_status_message=Catalog%20Cleared'
return response.redirect(url)
def manage_catalogClearReserved(self, REQUEST=None, RESPONSE=None, URL1=None):
""" Clears reserved uids """
self._clearReserved()
if REQUEST is None:
return
response = REQUEST.response
if response:
# Redirect the response to view url
url = self.absolute_url() + '/view' \
+ '?portal_status_message=Reserve%20UIDs%20Cleared'
return REQUEST.RESPONSE.redirect(url)
def _getFilterDict(self):
return FilterDict(self)
def _getCatalogMethodArgumentList(self, method):
if method.meta_type == "LDIF Method":
# Build the dictionnary of values
return method.arguments_src.split()
elif method.meta_type == "ERP5 SQL Method":
return method.getArgumentsSrc().split()
elif method.meta_type == "ERP5 Python Script":
return method.func_code.co_varnames[:method.func_code.co_argcount]
return ()
def _getCatalogMethod(self, method_name):
return self._getOb(method_name)
def manage_importProperties(self, file):
"""
Import properties from an XML file.
We also set filter properties to methods here.
"""
with open(file) as f:
doc = parse(f)
root = doc.documentElement
try:
for prop in root.getElementsByTagName("property"):
id = prop.getAttribute("id")
type = prop.getAttribute("type")
if not id or not hasattr(self, id):
raise CatalogError, 'unknown property id %r' % (id,)
if type not in ('str', 'tuple'):
raise CatalogError, 'unknown property type %r' % (type,)
if type == 'str':
value = ''
for text in prop.childNodes:
if text.nodeType == text.TEXT_NODE:
value = str(text.data)
break
else:
value = []
for item in prop.getElementsByTagName("item"):
item_type = item.getAttribute("type")
if item_type != 'str':
raise CatalogError, 'unknown item type %r' % (item_type,)
for text in item.childNodes:
if text.nodeType == text.TEXT_NODE:
value.append(str(text.data))
break
value = tuple(value)
setattr(self, id, value)
# Update filter properties for the objects.
for filt in root.getElementsByTagName("filter"):
id = str(filt.getAttribute("id"))
expression = filt.getAttribute("expression")
method = getattr(self, 'id', None)
if method:
# Use property setters for setting method properties
method.setFiltered(1)
method.setType([])
if expression:
expr_instance = Expression(expression)
method.setExpression(expression)
method.setExpressionInstance(expr_instance)
else:
method.setExpression("")
method.setExpressionInstance(None)
finally:
doc.unlink()
security.declarePrivate('isMethodFiltered')
def isMethodFiltered(self, method_name):
"""
Returns 1 if the mehtod is filtered,
else it returns o
"""
method = aq_base(self)._getOb(method_name)
if method is None:
return 0
return method.isFiltered()
security.declarePrivate('getExpression')
def getExpression(self, method_name):
""" Get the filter expression text for this method.
"""
method = aq_base(self)._getOb(method_name)
if method is None:
return ""
return method.getExpression()
security.declarePrivate('getExpressionCacheKey')
def getExpressionCacheKey(self, method_name):
""" Get the key string which is used to cache results
for the given expression.
"""
method = aq_base(self)._getOb(method_name)
if method is None:
return ""
return ' '.join(method.getExpressionCacheKeyList())
security.declarePrivate('getExpressionInstance')
def getExpressionInstance(self, method_name):
""" Get the filter expression instance for this method.
"""
method = aq_base(self)._getOb(method_name)
if method is None:
return None
return method.getExpressionInstance()
security.declarePrivate('setFilterExpression')
def setFilterExpression(self, method_name, expression):
""" Set the Expression for a certain method name. This allow set
expressions by scripts.
"""
method = aq_base(self)._getOb(method_name)
if method is None:
return None
method.setExpression(expression)
if expression:
expression_instance = Expression(expression)
else:
expression_instance = None
method.setExpressionInstance(expression)
security.declarePrivate('getFilterDict')
def getFilterDict(self):
"""
Utility Method.
Filter Dict is a dictionary and used at Python Scripts,
This method returns a filter dict as a dictionary.
"""
return {
method.getId(): {
'type': method.getTypeList(),
'filtered': 1,
'expression': method.getExpression(),
'expression_instance': method.getExpressionInstance(),
'expression_cache_key': method.getExpressionCacheKeyList()
}
for method in self.getFilterableMethodList()
if method.isFiltered()}
InitializeClass(ERP5Catalog)
class ERP5CatalogError(CatalogError): pass
...@@ -38,8 +38,9 @@ document_classes = updateGlobals( this_module, globals(), permissions_module = P ...@@ -38,8 +38,9 @@ document_classes = updateGlobals( this_module, globals(), permissions_module = P
# Define object classes and tools # Define object classes and tools
from Tool import ArchiveTool from Tool import ArchiveTool
from Document import ERP5Catalog
import CatalogTool import CatalogTool
object_classes = () object_classes = (ERP5Catalog.ERP5Catalog,)
portal_tools = (CatalogTool.CatalogTool, portal_tools = (CatalogTool.CatalogTool,
ArchiveTool.ArchiveTool) ArchiveTool.ArchiveTool)
content_classes = () content_classes = ()
......
...@@ -582,14 +582,15 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor): ...@@ -582,14 +582,15 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor):
""" % {'query_table' : query_table} """ % {'query_table' : query_table}
portal_skins_custom = portal.portal_skins.custom portal_skins_custom = portal.portal_skins.custom
portal_skins_custom.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( portal_skins_custom.newContent(
portal_type='SQL Method',
id='testMethod', id='testMethod',
title='', title='',
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
arguments="\n".join([ 'from_table_list', arguments_src="\n".join([ 'from_table_list',
'where_expression', 'where_expression',
'order_by_expression' ]), 'order_by_expression' ]),
template=sql_squeleton) src=sql_squeleton)
testMethod = portal_skins_custom['testMethod'] testMethod = portal_skins_custom['testMethod']
default_parametrs = {} default_parametrs = {}
...@@ -1476,14 +1477,20 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor): ...@@ -1476,14 +1477,20 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor):
""" """
for catalog, connection_id in ((original_catalog, original_connection_id), for catalog, connection_id in ((original_catalog, original_connection_id),
(new_catalog, self.new_erp5_sql_connection)): (new_catalog, self.new_erp5_sql_connection)):
catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( catalog.newContent(
id='z_create_dummy_table', title='', arguments="", portal_type='SQL Method',
id='z_create_dummy_table',
title='',
arguments_src="",
connection_id=connection_id, connection_id=connection_id,
template=create_dummy_table_sql) src=create_dummy_table_sql)
catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( catalog.newContent(
id='z0_drop_dummy_table', title='', arguments="", portal_type='SQL Method',
id='z0_drop_dummy_table',
title='',
arguments_src="",
connection_id=connection_id, connection_id=connection_id,
template=drop_summy_table_sql) src=drop_summy_table_sql)
# update catalog configuration and declare new ZSQLMethods # update catalog configuration and declare new ZSQLMethods
sql_clear_catalog_list = list(original_catalog.sql_clear_catalog) sql_clear_catalog_list = list(original_catalog.sql_clear_catalog)
...@@ -2389,6 +2396,9 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor): ...@@ -2389,6 +2396,9 @@ class TestERP5Catalog(ERP5TypeTestCase, LogInterceptor):
# Add a new table to the catalog # Add a new table to the catalog
sql_catalog = self.portal.portal_catalog.getSQLCatalog() sql_catalog = self.portal.portal_catalog.getSQLCatalog()
# Using newContent for an ERP5 object is not allowed to all roles, so
# better to fix the roles on the user
sql_catalog.manage_setLocalRoles(user1, ['Author', 'Auditor', 'Manager'])
local_roles_table = "test_local_roles" local_roles_table = "test_local_roles"
...@@ -2400,22 +2410,23 @@ CREATE TABLE `%s` ( ...@@ -2400,22 +2410,23 @@ CREATE TABLE `%s` (
KEY `version` (`owner_reference`) KEY `version` (`owner_reference`)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z_create_%s' % local_roles_table, id='z_create_%s' % local_roles_table,
title='', title='',
arguments="", arguments_src="",
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
template=create_local_role_table_sql) src=create_local_role_table_sql)
drop_local_role_table_sql = """ drop_local_role_table_sql = """
DROP TABLE IF EXISTS %s DROP TABLE IF EXISTS %s
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(portal_type='SQL Method',
id='z0_drop_%s' % local_roles_table, id='z0_drop_%s' % local_roles_table,
title='', title='',
arguments="", arguments_src="",
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
template=drop_local_role_table_sql) src=drop_local_role_table_sql)
catalog_local_role_sql = """ catalog_local_role_sql = """
REPLACE INTO REPLACE INTO
...@@ -2432,13 +2443,14 @@ VALUES ...@@ -2432,13 +2443,14 @@ VALUES
</dtml-if> </dtml-if>
</dtml-in> </dtml-in>
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z_catalog_%s_list' % local_roles_table, id='z_catalog_%s_list' % local_roles_table,
title='', title='',
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
arguments="\n".join(['uid', arguments_src="\n".join(['uid',
'Base_getOwnerId']), 'Base_getOwnerId']),
template=catalog_local_role_sql) src=catalog_local_role_sql)
self.commit() self.commit()
current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list
...@@ -2571,6 +2583,9 @@ VALUES ...@@ -2571,6 +2583,9 @@ VALUES
# Add a new table to the catalog # Add a new table to the catalog
sql_catalog = self.portal.portal_catalog.getSQLCatalog() sql_catalog = self.portal.portal_catalog.getSQLCatalog()
# Using newContent for an ERP5 object is not allowed to all roles, so
# better to fix the roles on the user
sql_catalog.manage_setLocalRoles(user1, ['Author', 'Auditor', 'Manager'])
local_roles_table = "test_assignee_local_roles" local_roles_table = "test_assignee_local_roles"
...@@ -2584,22 +2599,24 @@ CREATE TABLE `%s` ( ...@@ -2584,22 +2599,24 @@ CREATE TABLE `%s` (
KEY `viewable_assignee_reference` (`viewable_assignee_reference`) KEY `viewable_assignee_reference` (`viewable_assignee_reference`)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z_create_%s' % local_roles_table, id='z_create_%s' % local_roles_table,
title='', title='',
arguments="", arguments_src="",
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
template=create_local_role_table_sql) src=create_local_role_table_sql)
drop_local_role_table_sql = """ drop_local_role_table_sql = """
DROP TABLE IF EXISTS %s DROP TABLE IF EXISTS %s
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z0_drop_%s' % local_roles_table, id='z0_drop_%s' % local_roles_table,
title='', title='',
arguments="", arguments_src="",
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
template=drop_local_role_table_sql) src=drop_local_role_table_sql)
catalog_local_role_sql = """ catalog_local_role_sql = """
REPLACE INTO REPLACE INTO
...@@ -2617,14 +2634,15 @@ VALUES ...@@ -2617,14 +2634,15 @@ VALUES
</dtml-if> </dtml-if>
</dtml-in> </dtml-in>
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z_catalog_%s_list' % local_roles_table, id='z_catalog_%s_list' % local_roles_table,
title='', title='',
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
arguments="\n".join(['uid', arguments_src="\n".join(['uid',
'getAssignee', 'getAssignee',
'getViewPermissionAssignee']), 'getViewPermissionAssignee']),
template=catalog_local_role_sql) src=catalog_local_role_sql)
self.commit() self.commit()
current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list
...@@ -2729,6 +2747,9 @@ VALUES ...@@ -2729,6 +2747,9 @@ VALUES
# Add a new table to the catalog # Add a new table to the catalog
sql_catalog = self.portal.portal_catalog.getSQLCatalog() sql_catalog = self.portal.portal_catalog.getSQLCatalog()
# Using newContent for an ERP5 object is not allowed to all roles, so
# better to fix the roles on the user
sql_catalog.manage_setLocalRoles(user1, ['Author', 'Auditor', 'Manager'])
local_roles_table = "test_user_or_group_local_roles" local_roles_table = "test_user_or_group_local_roles"
...@@ -2742,22 +2763,24 @@ CREATE TABLE `%s` ( ...@@ -2742,22 +2763,24 @@ CREATE TABLE `%s` (
KEY `viewable_assignee_reference` (`viewable_assignee_reference`) KEY `viewable_assignee_reference` (`viewable_assignee_reference`)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z_create_%s' % local_roles_table, id='z_create_%s' % local_roles_table,
title='', title='',
arguments="", arguments_src="",
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
template=create_local_role_table_sql) src=create_local_role_table_sql)
drop_local_role_table_sql = """ drop_local_role_table_sql = """
DROP TABLE IF EXISTS %s DROP TABLE IF EXISTS %s
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z0_drop_%s' % local_roles_table, id='z0_drop_%s' % local_roles_table,
title='', title='',
arguments="", arguments_src="",
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
template=drop_local_role_table_sql) src=drop_local_role_table_sql)
catalog_local_role_sql = """ catalog_local_role_sql = """
REPLACE INTO REPLACE INTO
...@@ -2775,14 +2798,15 @@ VALUES ...@@ -2775,14 +2798,15 @@ VALUES
</dtml-if> </dtml-if>
</dtml-in> </dtml-in>
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
portal_type='SQL Method',
id='z_catalog_%s_list' % local_roles_table, id='z_catalog_%s_list' % local_roles_table,
title='', title='',
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
arguments="\n".join(['uid', arguments_src="\n".join(['uid',
'getAssignee', 'getAssignee',
'getViewPermissionAssignee']), 'getViewPermissionAssignee']),
template=catalog_local_role_sql) src=catalog_local_role_sql)
self.commit() self.commit()
current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list
...@@ -2983,6 +3007,9 @@ VALUES ...@@ -2983,6 +3007,9 @@ VALUES
# Add a new table to the catalog # Add a new table to the catalog
sql_catalog = self.portal.portal_catalog.getSQLCatalog() sql_catalog = self.portal.portal_catalog.getSQLCatalog()
# Using newContent for an ERP5 object is not allowed to all roles, so
# better to fix the roles on the user
sql_catalog.manage_setLocalRoles(user1, ['Author', 'Auditor', 'Manager'])
local_roles_table = "another_test_user_or_group_local_roles" local_roles_table = "another_test_user_or_group_local_roles"
...@@ -2994,22 +3021,24 @@ CREATE TABLE `%s` ( ...@@ -2994,22 +3021,24 @@ CREATE TABLE `%s` (
KEY `viewable_assignee_reference` (`viewable_assignee_reference`) KEY `viewable_assignee_reference` (`viewable_assignee_reference`)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
id='z_create_%s' % local_roles_table, portal_type='SQL Method',
title='', id = 'z_create_%s' % local_roles_table,
arguments="", title = '',
connection_id='erp5_sql_connection', arguments_src = "",
template=create_local_role_table_sql) connection_id = 'erp5_sql_connection',
src = create_local_role_table_sql)
drop_local_role_table_sql = """ drop_local_role_table_sql = """
DROP TABLE IF EXISTS %s DROP TABLE IF EXISTS %s
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
id='z0_drop_%s' % local_roles_table, portal_type='SQL Method',
title='', id = 'z0_drop_%s' % local_roles_table,
arguments="", title = '',
connection_id='erp5_sql_connection', arguments_src = "",
template=drop_local_role_table_sql) connection_id = 'erp5_sql_connection',
src = drop_local_role_table_sql)
catalog_local_role_sql = """ catalog_local_role_sql = """
REPLACE INTO REPLACE INTO
...@@ -3026,13 +3055,14 @@ VALUES ...@@ -3026,13 +3055,14 @@ VALUES
</dtml-if> </dtml-if>
</dtml-in> </dtml-in>
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
id='z_catalog_%s_list' % local_roles_table, portal_type='SQL Method',
title='', id = 'z_catalog_%s_list' % local_roles_table,
connection_id='erp5_sql_connection', title = '',
arguments="\n".join(['uid', connection_id = 'erp5_sql_connection',
'getViewPermissionAssignee']), arguments_src = "\n".join(['uid',
template=catalog_local_role_sql) 'getViewPermissionAssignee']),
src = catalog_local_role_sql)
self.commit() self.commit()
current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list
...@@ -3223,22 +3253,24 @@ CREATE TABLE `%s` ( ...@@ -3223,22 +3253,24 @@ CREATE TABLE `%s` (
KEY `viewable_assignee_reference` (`viewable_assignee_reference`) KEY `viewable_assignee_reference` (`viewable_assignee_reference`)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
id='z_create_%s' % local_roles_table, portal_type='SQL Method',
title='', id = 'z_create_%s' % local_roles_table,
arguments="", title = '',
connection_id='erp5_sql_connection', arguments_src = "",
template=create_local_role_table_sql) connection_id = 'erp5_sql_connection',
src = create_local_role_table_sql)
drop_local_role_table_sql = """ drop_local_role_table_sql = """
DROP TABLE IF EXISTS %s DROP TABLE IF EXISTS %s
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
id='z0_drop_%s' % local_roles_table, portal_type='SQL Method',
title='', id = 'z0_drop_%s' % local_roles_table,
arguments="", title = '',
connection_id='erp5_sql_connection', arguments_src = "",
template=drop_local_role_table_sql) connection_id = 'erp5_sql_connection',
src = drop_local_role_table_sql)
catalog_local_role_sql = """ catalog_local_role_sql = """
REPLACE INTO REPLACE INTO
...@@ -3255,13 +3287,14 @@ VALUES ...@@ -3255,13 +3287,14 @@ VALUES
</dtml-if> </dtml-if>
</dtml-in> </dtml-in>
""" % local_roles_table """ % local_roles_table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(
id='z_catalog_%s_list' % local_roles_table, portal_type='SQL Method',
title='', id = 'z_catalog_%s_list' % local_roles_table,
connection_id='erp5_sql_connection', title = '',
arguments="\n".join(['uid', connection_id = 'erp5_sql_connection',
'getViewPermissionAssignee']), arguments_src = "\n".join(['uid',
template=catalog_local_role_sql) 'getViewPermissionAssignee']),
src = catalog_local_role_sql)
self.commit() self.commit()
current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list current_sql_catalog_object_list = sql_catalog.sql_catalog_object_list
......
...@@ -73,12 +73,12 @@ CREATE TABLE alternate_roles_and_users ( ...@@ -73,12 +73,12 @@ CREATE TABLE alternate_roles_and_users (
'alternate_roles_and_users'] 'alternate_roles_and_users']
# Configure sql method to insert this table # Configure sql method to insert this table
sql_catalog.manage_addProduct['ZSQLMethods'].manage_addZSQLMethod( sql_catalog.newContent(portal_type='SQL Method',
id='z_catalog_alternate_roles_and_users_list', id='z_catalog_alternate_roles_and_users_list',
title='', title='',
connection_id='erp5_sql_connection', connection_id='erp5_sql_connection',
arguments="\n".join(['uid', 'alternate_security_uid']), arguments_src="\n".join(['uid', 'alternate_security_uid']),
template="""REPLACE INTO alternate_roles_and_users VALUES src="""REPLACE INTO alternate_roles_and_users VALUES
<dtml-in prefix="loop" expr="_.range(_.len(uid))"> <dtml-in prefix="loop" expr="_.range(_.len(uid))">
( <dtml-sqlvar expr="uid[loop_item]" type="int">, ( <dtml-sqlvar expr="uid[loop_item]" type="int">,
<dtml-sqlvar expr="alternate_security_uid[loop_item]" type="int" optional> <dtml-sqlvar expr="alternate_security_uid[loop_item]" type="int" optional>
......
...@@ -67,7 +67,7 @@ def manage_page_footer(self): ...@@ -67,7 +67,7 @@ def manage_page_footer(self):
+ ['printed', 'same_type', 'string', 'sequence', 'random', 'DateTime', + ['printed', 'same_type', 'string', 'sequence', 'random', 'DateTime',
'whrandom', 'reorder', 'sets', 'test', 'math']) 'whrandom', 'reorder', 'sets', 'test', 'math'])
live_check_python_script = 1 # XXX make it a preference ? live_check_python_script = 1 # XXX make it a preference ?
elif document.meta_type in ('Z SQL Method', ): elif document.meta_type in ('Z SQL Method', 'ERP5 SQL Method'):
mode = 'sql' mode = 'sql'
textarea_selector = 'textarea[name="template:text"]' textarea_selector = 'textarea[name="template:text"]'
elif document.meta_type in ('Page Template', 'ERP5 OOo Template', ): elif document.meta_type in ('Page Template', 'ERP5 OOo Template', ):
......
...@@ -3258,9 +3258,10 @@ class TestAccessControl(ERP5TypeTestCase): ...@@ -3258,9 +3258,10 @@ class TestAccessControl(ERP5TypeTestCase):
def afterSetUp(self): def afterSetUp(self):
self.login() self.login()
self.getCatalogTool().getSQLCatalog().filter_dict['z_catalog_object_list'] \ method = self.getCatalogTool().getSQLCatalog()._getOb('z_catalog_object_list')
= dict(filtered=1, type=[], expression=self.expression, method.setFiltered(1)
expression_instance=Expression(self.expression)) method.setExpression(self.expression)
method.setExpressionInstance(Expression(self.expression))
createZODBPythonScript(self.getSkinsTool().custom, createZODBPythonScript(self.getSkinsTool().custom,
'Base_immediateReindexObject', 'Base_immediateReindexObject',
......
...@@ -744,8 +744,7 @@ class Catalog(Folder, ...@@ -744,8 +744,7 @@ class Catalog(Folder,
for item in item_list: for item in item_list:
f.write(' <item type="str">%s</item>\n' % escape(str(item))) f.write(' <item type="str">%s</item>\n' % escape(str(item)))
f.write(' </property>\n') f.write(' </property>\n')
# XXX Although filters are not properties, output filters here. # Filters are now propeties in ERP5 SQL Method(s)
# XXX Ideally, filters should be properties in Z SQL Methods, shouldn't they?
filter_dict = self._getFilterDict() filter_dict = self._getFilterDict()
if filter_dict: if filter_dict:
for filter_id, filter_def in sorted(filter_dict.iteritems()): for filter_id, filter_def in sorted(filter_dict.iteritems()):
...@@ -765,61 +764,6 @@ class Catalog(Folder, ...@@ -765,61 +764,6 @@ class Catalog(Folder,
'inline;filename=properties.xml') 'inline;filename=properties.xml')
return f.getvalue() return f.getvalue()
security.declareProtected(import_export_objects, 'manage_importProperties')
def manage_importProperties(self, file):
"""
Import properties from an XML file.
"""
with open(file) as f:
doc = parse(f)
root = doc.documentElement
try:
for prop in root.getElementsByTagName("property"):
id = prop.getAttribute("id")
type = prop.getAttribute("type")
if not id or not hasattr(self, id):
raise CatalogError, 'unknown property id %r' % (id,)
if type not in ('str', 'tuple'):
raise CatalogError, 'unknown property type %r' % (type,)
if type == 'str':
value = ''
for text in prop.childNodes:
if text.nodeType == text.TEXT_NODE:
value = str(text.data)
break
else:
value = []
for item in prop.getElementsByTagName("item"):
item_type = item.getAttribute("type")
if item_type != 'str':
raise CatalogError, 'unknown item type %r' % (item_type,)
for text in item.childNodes:
if text.nodeType == text.TEXT_NODE:
value.append(str(text.data))
break
value = tuple(value)
setattr(self, id, value)
if not hasattr(self, 'filter_dict'):
self.filter_dict = PersistentMapping()
for filt in root.getElementsByTagName("filter"):
id = str(filt.getAttribute("id"))
expression = filt.getAttribute("expression")
if id not in self.filter_dict:
self.filter_dict[id] = PersistentMapping()
self.filter_dict[id]['filtered'] = 1
self.filter_dict[id]['type'] = []
if expression:
expr_instance = Expression(expression)
self.filter_dict[id]['expression'] = expression
self.filter_dict[id]['expression_instance'] = expr_instance
else:
self.filter_dict[id]['expression'] = ""
self.filter_dict[id]['expression_instance'] = None
finally:
doc.unlink()
security.declareProtected(manage_zcatalog_entries, 'manage_historyCompare') security.declareProtected(manage_zcatalog_entries, 'manage_historyCompare')
def manage_historyCompare(self, rev1, rev2, REQUEST, def manage_historyCompare(self, rev1, rev2, REQUEST,
historyComparisonResults=''): historyComparisonResults=''):
...@@ -2718,179 +2662,6 @@ class Catalog(Folder, ...@@ -2718,179 +2662,6 @@ class Catalog(Folder,
method = self._getOb(self.getSqlReadRecordedObjectList()) method = self._getOb(self.getSqlReadRecordedObjectList())
return method(catalog=catalog) return method(catalog=catalog)
# Filtering
security.declareProtected(manage_zcatalog_entries, 'manage_editFilter')
def manage_editFilter(self, REQUEST=None, RESPONSE=None, URL1=None):
"""
This methods allows to set a filter on each zsql method called,
so we can test if we should or not call a zsql method, so we can
increase a lot the speed.
"""
if withCMF:
method_id_list = [zsql_method.id for zsql_method in self.getFilterableMethodList()]
# Remove unused filters.
for id in self.filter_dict.keys():
if id not in method_id_list:
del self.filter_dict[id]
for id in method_id_list:
# We will first look if the filter is activated
if id not in self.filter_dict:
self.filter_dict[id] = PersistentMapping()
if REQUEST.has_key('%s_box' % id):
self.filter_dict[id]['filtered'] = 1
else:
self.filter_dict[id]['filtered'] = 0
expression = REQUEST.get('%s_expression' % id, '').strip()
self.filter_dict[id]['expression'] = expression
if expression:
self.filter_dict[id]['expression_instance'] = Expression(expression)
else:
self.filter_dict[id]['expression_instance'] = None
if REQUEST.has_key('%s_type' % id):
list_type = REQUEST['%s_type' % id]
if isinstance(list_type, str):
list_type = [list_type]
self.filter_dict[id]['type'] = list_type
else:
self.filter_dict[id]['type'] = []
self.filter_dict[id]['expression_cache_key'] = \
tuple(sorted(REQUEST.get('%s_expression_cache_key' % id, '').split()))
if RESPONSE and URL1:
RESPONSE.redirect(URL1 + '/manage_catalogFilter?manage_tabs_message=Filter%20Changed')
security.declarePrivate('isMethodFiltered')
def isMethodFiltered(self, method_name):
"""
Returns 1 if the method is already filtered,
else it returns 0
"""
if withCMF:
# Reset Filtet dict
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return 0
try:
return self.filter_dict[method_name]['filtered']
except KeyError:
return 0
return 0
security.declarePrivate('getExpression')
def getExpression(self, method_name):
""" Get the filter expression text for this method.
"""
if withCMF:
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return ""
try:
return self.filter_dict[method_name]['expression']
except KeyError:
return ""
return ""
security.declarePrivate('getExpressionCacheKey')
def getExpressionCacheKey(self, method_name):
""" Get the key string which is used to cache results
for the given expression.
"""
if withCMF:
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return ""
try:
return ' '.join(self.filter_dict[method_name]['expression_cache_key'])
except KeyError:
return ""
return ""
security.declarePrivate('getExpressionInstance')
def getExpressionInstance(self, method_name):
""" Get the filter expression instance for this method.
"""
if withCMF:
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return None
try:
return self.filter_dict[method_name]['expression_instance']
except KeyError:
return None
return None
security.declarePrivate('setFilterExpression')
def setFilterExpression(self, method_name, expression):
""" Set the Expression for a certain method name. This allow set
expressions by scripts.
"""
if withCMF:
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return None
self.filter_dict[method_name]['expression'] = expression
if expression:
self.filter_dict[method_name]['expression_instance'] = Expression(expression)
else:
self.filter_dict[method_name]['expression_instance'] = None
security.declarePrivate('isPortalTypeSelected')
def isPortalTypeSelected(self, method_name, portal_type):
""" Returns true if the portal type is selected for this method.
XXX deprecated
"""
if withCMF:
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return 0
try:
return portal_type in (self.filter_dict[method_name]['type'])
except KeyError:
return 0
return 0
security.declarePrivate('getFilteredPortalTypeList')
def getFilteredPortalTypeList(self, method_name):
""" Returns the list of portal types which define
the filter.
XXX deprecated
"""
if withCMF:
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return []
try:
return self.filter_dict[method_name]['type']
except KeyError:
return []
return []
security.declarePrivate('getFilterDict')
def getFilterDict(self):
"""
Utility Method.
Filter Dict is a dictionary and used at Python Scripts,
This method returns a filter dict as a dictionary.
"""
if withCMF:
if getattr(aq_base(self), 'filter_dict', None) is None:
self.filter_dict = PersistentMapping()
return None
filter_dict = {}
for key in self.filter_dict:
# Filter is also a Persistence dict.
filter_dict[key] = {}
for sub_key in self.filter_dict[key]:
filter_dict[key][sub_key] = self.filter_dict[key][sub_key]
return filter_dict
return None
security.declarePublic('getConnectionId') security.declarePublic('getConnectionId')
def getConnectionId(self, deferred=False): def getConnectionId(self, deferred=False):
""" """
...@@ -2899,7 +2670,7 @@ class Catalog(Folder, ...@@ -2899,7 +2670,7 @@ class Catalog(Folder,
If 'deferred' is True, then returns the deferred connection If 'deferred' is True, then returns the deferred connection
""" """
for method in self.objectValues(): for method in self.objectValues():
if method.meta_type == 'Z SQL Method': if method.meta_type in ('Z SQL Method', 'ERP5 SQL Method',):
if ('deferred' in method.connection_id) == deferred: if ('deferred' in method.connection_id) == deferred:
return method.connection_id return method.connection_id
......
...@@ -375,7 +375,7 @@ class ZCatalog(Folder, Persistent, Implicit): ...@@ -375,7 +375,7 @@ class ZCatalog(Folder, Persistent, Implicit):
security.declarePrivate('changeSQLConnectionIds') security.declarePrivate('changeSQLConnectionIds')
def changeSQLConnectionIds(self, folder, sql_connection_id_dict): def changeSQLConnectionIds(self, folder, sql_connection_id_dict):
if sql_connection_id_dict is not None: if sql_connection_id_dict is not None:
if folder.meta_type == 'Z SQL Method': if folder.meta_type in ('Z SQL Method', 'ERP5 SQL Method',):
connection_id = folder.connection_id connection_id = folder.connection_id
if connection_id in sql_connection_id_dict: if connection_id in sql_connection_id_dict:
folder.connection_id = sql_connection_id_dict[connection_id] folder.connection_id = sql_connection_id_dict[connection_id]
......
...@@ -55,64 +55,6 @@ class TestSQLCatalog(unittest.TestCase): ...@@ -55,64 +55,6 @@ class TestSQLCatalog(unittest.TestCase):
self.assertTrue(self._catalog.z_dummy_method in self.assertTrue(self._catalog.z_dummy_method in
self._catalog.getFilterableMethodList()) self._catalog.getFilterableMethodList())
def test_manage_editFilter(self):
request = dict(z_dummy_method_box=1, z_dummy_method_expression='python: 1')
self._catalog.manage_editFilter(REQUEST=request)
self.assertTrue(self._catalog.filter_dict.has_key('z_dummy_method'))
def test_isMethodFiltered(self):
request = dict(z_dummy_method_box=1, z_dummy_method_expression='python: 1')
self._catalog.manage_editFilter(REQUEST=request)
self.assertTrue(self._catalog.isMethodFiltered('z_dummy_method'))
self.assertFalse(self._catalog.isMethodFiltered('not_exist'))
def test_getFilterExpression(self):
request = dict(z_dummy_method_box=1, z_dummy_method_expression='python: 1')
self._catalog.manage_editFilter(REQUEST=request)
self.assertEqual('python: 1', self._catalog.getExpression('z_dummy_method'))
self.assertEqual('', self._catalog.getExpression('not_exists'))
def test_setFilterExpression(self):
request = dict(z_dummy_method_box=1, z_dummy_method_expression='python: 1')
self._catalog.manage_editFilter(REQUEST=request)
expression = self._catalog.getExpressionInstance('z_dummy_method')
self._catalog.setFilterExpression('z_dummy_method', 'python: 2')
self.assertEqual('python: 2', self._catalog.getExpression('z_dummy_method'))
self.assertNotEquals(expression,
self._catalog.getExpressionInstance('z_dummy_method'))
self._catalog.setFilterExpression('z_dummy_method', 'python: 1')
self.assertEqual('python: 1', self._catalog.getExpression('z_dummy_method'))
self.assertRaises(KeyError, self._catalog.setFilterExpression,
'not_exists', "python:1")
self.assertEqual('', self._catalog.getExpression('not_exists'))
def test_getFilterDict(self):
request = dict(z_dummy_method_box=1, z_dummy_method_expression='python: 1')
self._catalog.manage_editFilter(REQUEST=request)
filter_dict = self._catalog.getFilterDict()
self.assertEqual(self._catalog.filter_dict.keys(), filter_dict.keys())
self.assertTrue(isinstance(filter_dict, type({})))
self.assertTrue(isinstance(filter_dict['z_dummy_method'], type({})))
self.assertEqual(self._catalog.getExpression('z_dummy_method'),
filter_dict['z_dummy_method']['expression'])
def test_getFilterExpressionInstance(self):
request = dict(z_dummy_method_box=1, z_dummy_method_expression='python: 1')
self._catalog.manage_editFilter(REQUEST=request)
self.assertTrue(isinstance(
self._catalog.getExpressionInstance('z_dummy_method'), Expression))
self.assertEqual(None, self._catalog.getExpressionInstance('not_exists'))
def test_isPortalTypeSelected(self):
request = dict(z_dummy_method_box=1, z_dummy_method_type=['Selected'])
self._catalog.manage_editFilter(REQUEST=request)
self.assertTrue(
self._catalog.isPortalTypeSelected('z_dummy_method', 'Selected'))
self.assertFalse(
self._catalog.isPortalTypeSelected('z_dummy_method', 'Not Selected'))
self.assertFalse(
self._catalog.isPortalTypeSelected('not_exists', 'Selected'))
def test_getRecordByUid(self): def test_getRecordByUid(self):
class MyError(RuntimeError): class MyError(RuntimeError):
pass pass
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment