Commit 629d54cb authored by Jean-Paul Smets's avatar Jean-Paul Smets

Minor cosmetic changes. Also added support for optimised role indexing in the...

Minor cosmetic changes. Also added support for optimised role indexing in the catalog. (ex. owner). This is required in particular for sites which need to track owner of documents in an efficient way.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@13039 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 66baa551
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
from Products.CMFCore.CatalogTool import CatalogTool as CMFCoreCatalogTool from Products.CMFCore.CatalogTool import CatalogTool as CMFCoreCatalogTool
from Products.ZSQLCatalog.ZSQLCatalog import ZCatalog from Products.ZSQLCatalog.ZSQLCatalog import ZCatalog
from Products.ZSQLCatalog.SQLCatalog import Query, ComplexQuery
from Products.CMFCore import CMFCorePermissions from Products.CMFCore import CMFCorePermissions
from AccessControl import ClassSecurityInfo, getSecurityManager from AccessControl import ClassSecurityInfo, getSecurityManager
from Products.CMFCore.CatalogTool import IndexableObjectWrapper as CMFCoreIndexableObjectWrapper from Products.CMFCore.CatalogTool import IndexableObjectWrapper as CMFCoreIndexableObjectWrapper
...@@ -70,6 +71,8 @@ try: ...@@ -70,6 +71,8 @@ try:
except ImportError: except ImportError:
pass pass
DEFAULT_RESULT_LIMIT = 1000
def getSecurityProduct(acl_users): def getSecurityProduct(acl_users):
"""returns the security used by the user folder passed. """returns the security used by the user folder passed.
(NuxUserGroup, ERP5Security, or None if anything else). (NuxUserGroup, ERP5Security, or None if anything else).
...@@ -139,7 +142,7 @@ class IndexableObjectWrapper(CMFCoreIndexableObjectWrapper): ...@@ -139,7 +142,7 @@ class IndexableObjectWrapper(CMFCoreIndexableObjectWrapper):
# trying to reduce the number of security definitions # trying to reduce the number of security definitions
# However, this could be a bad idea if we start to use Owner role # However, this could be a bad idea if we start to use Owner role
# as a kind of Assignee and if we need it for worklists. # as a kind of Assignee and if we need it for worklists.
if role != 'Owner': if role != 'Owner':
if withnuxgroups: if withnuxgroups:
allowed[user + ':' + role] = 1 allowed[user + ':' + role] = 1
else: else:
...@@ -211,14 +214,14 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -211,14 +214,14 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
product_path = package_home(globals()) product_path = package_home(globals())
zsql_dirs = [] zsql_dirs = []
# Common methods # Common methods - for backward compatibility
# SQL code distribution is supposed to be business template based nowadays
if config_id.lower() == 'erp5_mysql': if config_id.lower() == 'erp5_mysql':
zsql_dirs.append(os.path.join(product_path, 'sql', 'common_mysql')) zsql_dirs.append(os.path.join(product_path, 'sql', 'common_mysql'))
zsql_dirs.append(os.path.join(product_path, 'sql', 'erp5_mysql')) zsql_dirs.append(os.path.join(product_path, 'sql', 'erp5_mysql'))
elif config_id.lower() == 'cps3_mysql': elif config_id.lower() == 'cps3_mysql':
zsql_dirs.append(os.path.join(product_path, 'sql', 'common_mysql')) zsql_dirs.append(os.path.join(product_path, 'sql', 'common_mysql'))
zsql_dirs.append(os.path.join(product_path, 'sql', 'cps3_mysql')) zsql_dirs.append(os.path.join(product_path, 'sql', 'cps3_mysql'))
# XXX TODO : add other cases
# Iterate over the sql directory. Add all sql methods in that directory. # Iterate over the sql directory. Add all sql methods in that directory.
for directory in zsql_dirs: for directory in zsql_dirs:
...@@ -237,7 +240,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -237,7 +240,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
# Make this the default. # Make this the default.
self.default_sql_catalog_id = config_id self.default_sql_catalog_id = config_id
security.declareProtected( 'Import/Export objects', 'exportSQLMethods' ) security.declareProtected( 'Import/Export objects', 'exportSQLMethods' )
def exportSQLMethods(self, sql_catalog_id=None, config_id='erp5'): def exportSQLMethods(self, sql_catalog_id=None, config_id='erp5'):
""" """
...@@ -258,7 +261,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -258,7 +261,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
'z_create_record', 'z_related_security', 'z_delete_recorded_object_list', 'z_create_record', 'z_related_security', 'z_delete_recorded_object_list',
'z_reserve_uid', 'z_getitem_by_path', 'z_show_columns', 'z_getitem_by_path', 'z_reserve_uid', 'z_getitem_by_path', 'z_show_columns', 'z_getitem_by_path',
'z_show_tables', 'z_getitem_by_uid', 'z_unique_values', 'z_produce_reserved_uid_list',) 'z_show_tables', 'z_getitem_by_uid', 'z_unique_values', 'z_produce_reserved_uid_list',)
msg = '' msg = ''
for id in catalog.objectIds(spec=('Z SQL Method',)): for id in catalog.objectIds(spec=('Z SQL Method',)):
if id in common_sql_list: if id in common_sql_list:
...@@ -275,7 +278,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -275,7 +278,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
f.write(text) f.write(text)
finally: finally:
f.close() f.close()
properties = self.manage_catalogExportProperties(sql_catalog_id=sql_catalog_id) properties = self.manage_catalogExportProperties(sql_catalog_id=sql_catalog_id)
name = os.path.join(config_sql_dir, 'properties.xml') name = os.path.join(config_sql_dir, 'properties.xml')
msg += 'Writing %s\n' % (name,) msg += 'Writing %s\n' % (name,)
...@@ -284,9 +287,9 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -284,9 +287,9 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
f.write(properties) f.write(properties)
finally: finally:
f.close() f.close()
return msg return msg
def _listAllowedRolesAndUsers(self, user): def _listAllowedRolesAndUsers(self, user):
security_product = getSecurityProduct(self.acl_users) security_product = getSecurityProduct(self.acl_users)
if security_product == SECURITY_USING_PAS: if security_product == SECURITY_USING_PAS:
...@@ -394,12 +397,15 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -394,12 +397,15 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
This is supposed to be used with Z SQL Methods to check permissions This is supposed to be used with Z SQL Methods to check permissions
when you list up documents. It is also able to take into account when you list up documents. It is also able to take into account
a parameter named local_roles so that list documents only include a parameter named local_roles so that listed documents only include
those documents for which the user (or the group) was those documents for which the user (or the group) was
associated one of the given local roles. associated one of the given local roles.
XXX allowedRolesAndUsers naming is wrong
""" """
user = _getAuthenticatedUser(self) user = _getAuthenticatedUser(self)
allowedRolesAndUsers = self._listAllowedRolesAndUsers(user) allowedRolesAndUsers = self._listAllowedRolesAndUsers(user)
role_column_dict = {}
# Patch for ERP5 by JP Smets in order # Patch for ERP5 by JP Smets in order
# to implement worklists and search of local roles # to implement worklists and search of local roles
...@@ -415,52 +421,84 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -415,52 +421,84 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
# Local roles now has precedence (since it comes from a WorkList) # Local roles now has precedence (since it comes from a WorkList)
for user_or_group in allowedRolesAndUsers: for user_or_group in allowedRolesAndUsers:
for role in local_roles: for role in local_roles:
if role == "Owner": # Performance optimisation
# This is for now only a placeholder to handle the case of Owner lower_role = role.lower()
# which may not be supported (see above comment arround line 135 if self.getSQLCatalog().getColumnMap().has_key(lower_role):
new_allowedRolesAndUsers.append('%s:%s' % (user_or_group, role)) # If a given role exists as a column in the catalog,
# then it is considered as single valued and indexed
# through the catalog.
role_column_dict[lower_role] = user # XXX This should be a list
# which also includes all user groups
else: else:
# Else, we use the standard approach
new_allowedRolesAndUsers.append('%s:%s' % (user_or_group, role)) new_allowedRolesAndUsers.append('%s:%s' % (user_or_group, role))
allowedRolesAndUsers = new_allowedRolesAndUsers allowedRolesAndUsers = new_allowedRolesAndUsers
return allowedRolesAndUsers return allowedRolesAndUsers, role_column_dict
security.declarePrivate('getSecurityUid') security.declarePrivate('getSecurityQuery')
def getSecurityUid(self, **kw): def getSecurityQuery(self, query=None, **kw):
""" """
Return list of security oid for given roles list Build a query based on allowed roles (DEPRECATED)
or on a list of security_uid values. The query takes into
account the fact that some roles are catalogued with columns.
""" """
allowedRolesAndUsers, role_column_dict = self.getAllowedRolesAndUsers(**kw)
catalog = self.getSQLCatalog() catalog = self.getSQLCatalog()
method = getattr(catalog, catalog.sql_search_security, '') method = getattr(catalog, catalog.sql_search_security, '')
original_query = query
if method in ('', None): if method in ('', None):
# XXX old way, should not be used anylonger # XXX old way, should not be used anylonger
warnings.warn("The usage of allowedRolesAndUsers is deprecated.\n" warnings.warn("The usage of allowedRolesAndUsers is deprecated.\n"
"Please update your business template erp5_mysql_innodb.", "Please update your business template erp5_mysql_innodb.",
DeprecationWarning) DeprecationWarning)
kw['allowedRolesAndUsers'] = self.getAllowedRolesAndUsers(**kw) if role_column_dict:
query_list = []
for key, value in role_column_dict.items():
new_query = Query(key=value)
query_list.append(new_query)
operator_kw = {'operator': 'AND'}
query = ComplexQuery(*query_list, **operator_kw)
if allowedRolesAndUsers:
query = ComplexQuery(Query(allowedRolesAndUsers=allowedRolesAndUsers),
query, operator='OR')
else:
query = Query(allowedRolesAndUsers=allowedRolesAndUsers)
else: else:
allowedRolesAndUsers = ["'%s'" % (role, ) for role in self.getAllowedRolesAndUsers(**kw)] if allowedRolesAndUsers:
security_uid_list = [x.uid for x in method(security_roles_list = allowedRolesAndUsers)] allowedRolesAndUsers = ["'%s'" % (role, ) for role in allowedRolesAndUsers]
kw['security_uid'] = security_uid_list security_uid_list = [x.uid for x in method(security_roles_list = allowedRolesAndUsers)]
return kw if role_column_dict:
query_list = []
for key, value in role_column_dict.items():
new_query = Query(key=value)
query_list.append(new_query)
operator_kw = {'operator': 'AND'}
query = ComplexQuery(*query_list, **operator_kw)
if allowedRolesAndUsers:
query = ComplexQuery(Query(security_uid=security_uid_list),
query, operator='OR')
else:
query = Query(security_uid=security_uid_list)
if original_query is not None:
query = ComplexQuery(query, original_query, operator='AND')
return query
# searchResults has inherited security assertions. # searchResults has inherited security assertions.
def searchResults(self, REQUEST=None, **kw): def searchResults(self, query=None, **kw):
""" """
Calls ZCatalog.searchResults with extra arguments that Calls ZCatalog.searchResults with extra arguments that
limit the results to what the user is allowed to see. limit the results to what the user is allowed to see.
""" """
kw = self.getSecurityUid(**kw)
if not _checkPermission( if not _checkPermission(
CMFCorePermissions.AccessInactivePortalContent, self ): CMFCorePermissions.AccessInactivePortalContent, self ):
base = aq_base( self )
now = DateTime() now = DateTime()
kw[ 'effective' ] = { 'query' : now, 'range' : 'max' } kw[ 'effective' ] = { 'query' : now, 'range' : 'max' }
kw[ 'expires' ] = { 'query' : now, 'range' : 'min' } kw[ 'expires' ] = { 'query' : now, 'range' : 'min' }
kw.setdefault('limit', 1000) query = self.getSecurityQuery(query=query, **kw)
return ZCatalog.searchResults(self, REQUEST, **kw) kw.setdefault('limit', DEFAULT_RESULT_LIMIT)
return ZCatalog.searchResults(self, query=query, **kw)
__call__ = searchResults __call__ = searchResults
...@@ -468,16 +506,14 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -468,16 +506,14 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
def unrestrictedSearchResults(self, REQUEST=None, **kw): def unrestrictedSearchResults(self, REQUEST=None, **kw):
"""Calls ZSQLCatalog.searchResults directly without restrictions. """Calls ZSQLCatalog.searchResults directly without restrictions.
""" """
kw.setdefault('limit', 1000) kw.setdefault('limit', DEFAULT_RESULT_LIMIT)
return ZCatalog.searchResults(self, REQUEST, **kw) return ZCatalog.searchResults(self, REQUEST, **kw)
def countResults(self, REQUEST=None, **kw): def countResults(self, query=None, **kw):
""" """
Calls ZCatalog.countResults with extra arguments that Calls ZCatalog.countResults with extra arguments that
limit the results to what the user is allowed to see. limit the results to what the user is allowed to see.
""" """
kw = self.getSecurityUid(**kw)
# XXX This needs to be set again # XXX This needs to be set again
#if not _checkPermission( #if not _checkPermission(
# CMFCorePermissions.AccessInactivePortalContent, self ): # CMFCorePermissions.AccessInactivePortalContent, self ):
...@@ -486,8 +522,10 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -486,8 +522,10 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
# #kw[ 'effective' ] = { 'query' : now, 'range' : 'max' } # #kw[ 'effective' ] = { 'query' : now, 'range' : 'max' }
# #kw[ 'expires' ] = { 'query' : now, 'range' : 'min' } # #kw[ 'expires' ] = { 'query' : now, 'range' : 'min' }
return ZCatalog.countResults(self, REQUEST, **kw) query = self.getSecurityQuery(query=query, **kw)
kw.setdefault('limit', DEFAULT_RESULT_LIMIT)
return ZCatalog.countResults(self, query=query, **kw)
security.declarePrivate('unrestrictedCountResults') security.declarePrivate('unrestrictedCountResults')
def unrestrictedCountResults(self, REQUEST=None, **kw): def unrestrictedCountResults(self, REQUEST=None, **kw):
"""Calls ZSQLCatalog.countResults directly without restrictions. """Calls ZSQLCatalog.countResults directly without restrictions.
...@@ -679,7 +717,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject): ...@@ -679,7 +717,7 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
else: else:
base_category_id = name[len(DYNAMIC_METHOD_NAME):] base_category_id = name[len(DYNAMIC_METHOD_NAME):]
method = RelatedBaseCategory(base_category_id) method = RelatedBaseCategory(base_category_id)
setattr(self.__class__, name, setattr(self.__class__, name,
method) method)
klass = aq_base(self).__class__ klass = aq_base(self).__class__
if hasattr(klass, 'security'): if hasattr(klass, 'security'):
......
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