Commit 2c44ec0c 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 changes:
	-Inherit from Catalog class from Products.ZSQLCatalog.SQLCatalog instead of copy-pasting the whole code again.
	-Add allowed_types for ERP5Catalog tool
	-Monkey patch some property setters and getters to maintain consistency
	-Update id and title for ERP5Catlog while class initialization
	-Set declarative securities and solve some inheritance conflicts
	-Add isRADContent for ERP5Catalog Class
 	-Solve inheritence conflict for _setPropValue function in ERP5Catalog class
	-Add SQL Method portal_type in allowed_types for ERP5Catalog class
	-Override getCatalogMethodIds cause it uses global variable in SQLCatalog.Catalog
	-Redefine security declarations
	-Add functions for object_actions of Catalog portal_type in ERP5Catalog object
	-Add filter_dict attribute for compatibilty

Also,
- Update BusinessTemplate installation with updated filter_dict
This removes the need to copy-patch or if-else on meta_type of catalog.
Use dynamic migration while installing the catalog method objects for
bt5.
- Update tests according to changes in portal_catalog
- Create FilterDict and Filter class which would be used to imitate the behaviour
of filter_dict for Catalog.
parent 546d5ce2
...@@ -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
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()
def manage_editFilter(self, REQUEST=None, RESPONSE=None, URL1=None):
"""
XXX: Deprecated
Overriding the function manage_editFilter from SQLCatalog so that we
don't waste time in setting/creating filter_dict object.
Also, from inside ERP5, we won;t be having anything to call manage_editFilter
but it is being called at some places in tests, and its better to deprecate
useless methods.
"""
raise ERP5CatalogError, 'manage_editFilter function is depreacted. Please \
refrain from using it'
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('isPortalTypeSelected')
def isPortalTypeSelected(self, method_name, portal_type):
"""
XXX Deprecated: Override so as not to fail tests
"""
return 0
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',
arguments_src = "\n".join(['uid',
'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
...@@ -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',
arguments_src = "\n".join(['uid',
'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
......
...@@ -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>
......
...@@ -3164,9 +3164,10 @@ class TestAccessControl(ERP5TypeTestCase): ...@@ -3164,9 +3164,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',
......
...@@ -771,61 +771,6 @@ class Catalog(Folder, ...@@ -771,61 +771,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=''):
...@@ -2651,179 +2596,6 @@ class Catalog(Folder, ...@@ -2651,179 +2596,6 @@ class Catalog(Folder,
method = getattr(self, self.sql_read_recorded_object_list) method = getattr(self, self.sql_read_recorded_object_list)
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):
""" """
......
...@@ -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