Commit 480a9fec authored by Alexandre Boeglin's avatar Alexandre Boeglin

Added the possibility to filter which skins and scripts from the portal_skins

folder can be applied on each portal type.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@3206 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 456ab1c3
...@@ -39,6 +39,9 @@ from RoleInformation import ori ...@@ -39,6 +39,9 @@ from RoleInformation import ori
from zLOG import LOG from zLOG import LOG
import re
action_basename_re = re.compile("\/([^\/\?]+)(\?.+)?$")
ERP5TYPE_ROLE_INIT_SCRIPT = 'ERP5Type_initLocalRoleMapping' ERP5TYPE_ROLE_INIT_SCRIPT = 'ERP5Type_initLocalRoleMapping'
class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
...@@ -64,7 +67,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -64,7 +67,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
+ RoleProviderBase.manage_options + RoleProviderBase.manage_options
+ SimpleItemWithProperties.manage_options[1:] + SimpleItemWithProperties.manage_options[1:]
) )
_properties = (TypeInformation._basic_properties + ( _properties = (TypeInformation._basic_properties + (
{'id':'factory', 'type': 'string', 'mode':'w', {'id':'factory', 'type': 'string', 'mode':'w',
'label':'Product factory method'}, 'label':'Product factory method'},
...@@ -96,6 +99,13 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -96,6 +99,13 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
, 'label':'Base Categories' , 'label':'Base Categories'
, 'select_variable':'getBaseCategoryList' , 'select_variable':'getBaseCategoryList'
}, },
{'id':'filter_actions', 'type': 'boolean', 'mode':'w',
'label':'Filter actions?'},
{'id':'allowed_action_list'
, 'type': 'lines'
, 'mode':'w'
, 'label':'Allowed actions'
},
)) ))
property_sheet_list = () property_sheet_list = ()
...@@ -104,13 +114,15 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -104,13 +114,15 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
product = 'ERP5Type' product = 'ERP5Type'
immediate_view = 'view' immediate_view = 'view'
hidden_content_type_list = () hidden_content_type_list = ()
filter_actions = 0
allowed_action_list = []
# #
# Acquisition editing interface # Acquisition editing interface
# #
_actions_form = DTMLFile( 'editToolsActions', _dtmldir ) _actions_form = DTMLFile( 'editToolsActions', _dtmldir )
security.declarePublic('hideFromAddMenu') security.declarePublic('hideFromAddMenu')
def hidenFromAddMenu(self): def hidenFromAddMenu(self):
""" """
...@@ -130,15 +142,15 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -130,15 +142,15 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
'container', using 'id' as its id. Return the object. 'container', using 'id' as its id. Return the object.
""" """
ob = FactoryTypeInformation.constructInstance(self, container, id, *args, **kw) ob = FactoryTypeInformation.constructInstance(self, container, id, *args, **kw)
# Try to find the local role init script # Try to find the local role init script
init_role_script = getattr(ob, ERP5TYPE_ROLE_INIT_SCRIPT, None) init_role_script = getattr(ob, ERP5TYPE_ROLE_INIT_SCRIPT, None)
if init_role_script is not None: if init_role_script is not None:
# Retrieve applicable roles # Retrieve applicable roles
role_mapping = self.getFilteredRoleListFor(object = self) # kw provided in order to take any appropriate action role_mapping = self.getFilteredRoleListFor(object = self) # kw provided in order to take any appropriate action
# Call the local role init script # Call the local role init script
init_role_script(role_mapping = role_mapping, **kw) init_role_script(role_mapping = role_mapping, **kw)
if self.init_script: if self.init_script:
# Acquire the init script in the context of this object # Acquire the init script in the context of this object
init_script = getattr(ob, self.init_script) init_script = getattr(ob, self.init_script)
...@@ -164,6 +176,29 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -164,6 +176,29 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
""" """
return self.hidden_content_type_list return self.hidden_content_type_list
security.declareProtected(ERP5Permissions.AccessContentsInformation, 'isActionAllowed')
def isActionAllowed( self, action=None ):
"""
Return list of allowed actions.
You can define a 'allowed_action_list' property (as lines) on the portal_types object
to define actions that will be available for all portal types.
"""
if not self.filter_actions :
return 1 # everything is allowed
global_allowed_action_list = list(self.portal_types.getProperty('allowed_action_list', []))
action_list = list(self.allowed_action_list) + global_allowed_action_list
for ob_action in self._actions :
action_basename = action_basename_re.search(ob_action.action.text).group(1)
if len(action_basename) :
action_list.append(action_basename_re.search(ob_action.action.text).group(1))
LOG('isActionAllowed for %s :' % self.title_or_id(), 0, 'looking for %s in %s : %s' % (action, action_list, action in action_list))
if action in action_list :
return 1
return 0
security.declareProtected(ERP5Permissions.AccessContentsInformation, 'getBaseCategoryList') security.declareProtected(ERP5Permissions.AccessContentsInformation, 'getBaseCategoryList')
def getBaseCategoryList( self ): def getBaseCategoryList( self ):
result = self.portal_categories.getBaseCategoryList() result = self.portal_categories.getBaseCategoryList()
...@@ -197,7 +232,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -197,7 +232,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
break break
else: else:
folder = aq_parent(aq_inner(folder)) folder = aq_parent(aq_inner(folder))
ec = createExprContext(folder, portal, object) ec = createExprContext(folder, portal, object)
roles = [] roles = []
append = roles.append append = roles.append
...@@ -215,9 +250,9 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -215,9 +250,9 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
if not filtered_roles.has_key(id): if not filtered_roles.has_key(id):
filtered_roles[id] = [] filtered_roles[id] = []
filtered_roles[id].append(role) filtered_roles[id].append(role)
return filtered_roles return filtered_roles
# #
# Helper methods # Helper methods
# #
...@@ -230,13 +265,13 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -230,13 +265,13 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
else: else:
for i in r: for i in r:
append(i) append(i)
def manage_editProperties(self, REQUEST): def manage_editProperties(self, REQUEST):
""" """
Method overload Method overload
Reset _aq_dynamic if property_sheet definition has changed) Reset _aq_dynamic if property_sheet definition has changed)
XXX This is only good in single thread mode. XXX This is only good in single thread mode.
In ZEO environment, we should call portal_activities In ZEO environment, we should call portal_activities
in order to implement a broadcast update in order to implement a broadcast update
...@@ -249,7 +284,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ): ...@@ -249,7 +284,7 @@ class ERP5TypeInformation( FactoryTypeInformation, RoleProviderBase ):
base_category_list != self.base_category_list: base_category_list != self.base_category_list:
from Products.ERP5Type.Base import _aq_reset from Products.ERP5Type.Base import _aq_reset
_aq_reset() # XXX We should also call it whenever we change workflow defitino _aq_reset() # XXX We should also call it whenever we change workflow defitino
return result return result
security.declareProtected( ERP5Permissions.ManagePortal, 'manage_editLocalRolesForm' ) security.declareProtected( ERP5Permissions.ManagePortal, 'manage_editLocalRolesForm' )
def manage_editLocalRolesForm( self, REQUEST, manage_tabs_message=None ): def manage_editLocalRolesForm( self, REQUEST, manage_tabs_message=None ):
......
...@@ -929,22 +929,22 @@ class OrderedPickler(Pickler): ...@@ -929,22 +929,22 @@ class OrderedPickler(Pickler):
write(MARK + DICT) write(MARK + DICT)
self.memoize(obj) self.memoize(obj)
item_list = obj.items() # New version by JPS for sorting item_list = obj.items() # New version by JPS for sorting
item_list.sort(lambda a, b: cmp(a[0], b[0])) # New version by JPS for sorting item_list.sort(lambda a, b: cmp(a[0], b[0])) # New version by JPS for sorting
self._batch_setitems(item_list.__iter__()) self._batch_setitems(item_list.__iter__())
dispatch[DictionaryType] = save_dict dispatch[DictionaryType] = save_dict
if not PyStringMap is None: if not PyStringMap is None:
dispatch[PyStringMap] = save_dict dispatch[PyStringMap] = save_dict
def reorderPickle(jar, p): def reorderPickle(jar, p):
from ZODB.ExportImport import Ghost, Unpickler, Pickler, StringIO, persistent_id from ZODB.ExportImport import Ghost, Unpickler, Pickler, StringIO, persistent_id
oids = {} oids = {}
storage = jar._storage storage = jar._storage
new_oid = storage.new_oid new_oid = storage.new_oid
store = storage.store store = storage.store
def persistent_load(ooid, def persistent_load(ooid,
Ghost=Ghost, Ghost=Ghost,
oids=oids, wrote_oid=oids.has_key, oids=oids, wrote_oid=oids.has_key,
...@@ -958,13 +958,13 @@ def reorderPickle(jar, p): ...@@ -958,13 +958,13 @@ def reorderPickle(jar, p):
Ghost=Ghost() Ghost=Ghost()
Ghost.oid=ooid Ghost.oid=ooid
return Ghost return Ghost
# Reorder pickle by doing I/O # Reorder pickle by doing I/O
pfile = StringIO(p) pfile = StringIO(p)
unpickler=Unpickler(pfile) unpickler=Unpickler(pfile)
unpickler.persistent_load=persistent_load unpickler.persistent_load=persistent_load
newp=StringIO() newp=StringIO()
pickler=OrderedPickler(newp,1) pickler=OrderedPickler(newp,1)
pickler.persistent_id=persistent_id pickler.persistent_id=persistent_id
...@@ -974,8 +974,8 @@ def reorderPickle(jar, p): ...@@ -974,8 +974,8 @@ def reorderPickle(jar, p):
pickler.dump(obj) pickler.dump(obj)
p=newp.getvalue() p=newp.getvalue()
return obj, p return obj, p
def XMLrecord(oid, plen, p, id_mapping): def XMLrecord(oid, plen, p, id_mapping):
# Proceed as usual # Proceed as usual
q=ppml.ToXMLUnpickler q=ppml.ToXMLUnpickler
f=StringIO(p) f=StringIO(p)
...@@ -1022,24 +1022,24 @@ def exportXML(jar, oid, file=None): ...@@ -1022,24 +1022,24 @@ def exportXML(jar, oid, file=None):
else: else:
o, p = reorderPickle(jar, p) o, p = reorderPickle(jar, p)
reordered_pickle.append((oid, o, p)) reordered_pickle.append((oid, o, p))
XMLrecord(oid,len(p),p, id_mapping) XMLrecord(oid,len(p),p, id_mapping)
# Determine new oids added to the list after reference calculation # Determine new oids added to the list after reference calculation
old_oids = tuple(oids) old_oids = tuple(oids)
ref(p, oids) ref(p, oids)
new_oids = [] new_oids = []
for i in oids: for i in oids:
if i not in old_oids: new_oids.append(i) if i not in old_oids: new_oids.append(i)
# Sort new oids based on id of object # Sort new oids based on id of object
new_oidict = {} new_oidict = {}
for oid in new_oids: for oid in new_oids:
try: try:
p, serial = load(oid, version) p, serial = load(oid, version)
o, p = reorderPickle(jar, p) o, p = reorderPickle(jar, p)
new_oidict[oid] = getattr(o, 'id', None) new_oidict[oid] = getattr(o, 'id', None)
except: except:
new_oidict[oid] = None # Ick, a broken reference new_oidict[oid] = None # Ick, a broken reference
new_oids.sort(lambda a,b: cmp(new_oidict[a], new_oidict[b])) new_oids.sort(lambda a,b: cmp(new_oidict[a], new_oidict[b]))
# Build new sorted oids # Build new sorted oids
oids = list(old_oids) + new_oids oids = list(old_oids) + new_oids
# Do real export # Do real export
for (oid, o, p) in reordered_pickle: for (oid, o, p) in reordered_pickle:
...@@ -1091,16 +1091,16 @@ class Scalar: ...@@ -1091,16 +1091,16 @@ class Scalar:
# The value is Immutable - let us add it the the immutable mapping # The value is Immutable - let us add it the the immutable mapping
# to reduce the number of unreadable references # to reduce the number of unreadable references
self.mapping.setImmutable(self.id, Immutable(value = result)) self.mapping.setImmutable(self.id, Immutable(value = result))
return result return result
ppml.Scalar = Scalar ppml.Scalar = Scalar
class Immutable: class Immutable:
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
def getValue(self): def getValue(self):
return self.value return self.value
class String(Scalar): class String(Scalar):
def __init__(self, v, mapping, encoding=''): def __init__(self, v, mapping, encoding=''):
...@@ -1130,7 +1130,7 @@ class String(Scalar): ...@@ -1130,7 +1130,7 @@ class String(Scalar):
# The value is Immutable - let us add it the the immutable mapping # The value is Immutable - let us add it the the immutable mapping
# to reduce the number of unreadable references # to reduce the number of unreadable references
self.mapping.setImmutable(self.id, Immutable(value = result)) self.mapping.setImmutable(self.id, Immutable(value = result))
return result return result
ppml.String = String ppml.String = String
...@@ -1253,11 +1253,11 @@ class Reference(Scalar): ...@@ -1253,11 +1253,11 @@ class Reference(Scalar):
self.mapping = mapping self.mapping = mapping
def __str__(self, indent=0): def __str__(self, indent=0):
v=self._v v=self._v
name=string.lower(self.__class__.__name__) name=string.lower(self.__class__.__name__)
#LOG('Reference', 0, str(v)) #LOG('Reference', 0, str(v))
if self.mapping.hasImmutable(v): if self.mapping.hasImmutable(v):
return self.mapping.getImmutable(v).getValue() return self.mapping.getImmutable(v).getValue()
#LOG('noImmutable', 0, "%s mapped to %s" % (v, self.mapping[v])) #LOG('noImmutable', 0, "%s mapped to %s" % (v, self.mapping[v]))
self.mapping.mark(v) self.mapping.mark(v)
return '%s<%s id="%s"/>\n' % (' '*indent,name,self.mapping[v]) return '%s<%s id="%s"/>\n' % (' '*indent,name,self.mapping[v])
...@@ -1275,13 +1275,13 @@ class Object(Sequence): ...@@ -1275,13 +1275,13 @@ class Object(Sequence):
ppml.Object = Object ppml.Object = Object
class IdentityMapping: class IdentityMapping:
def __init__(self): def __init__(self):
self.immutable = {} self.immutable = {}
def resetMapping(self): def resetMapping(self):
pass pass
def __getitem__(self, id): def __getitem__(self, id):
return id return id
...@@ -1306,7 +1306,7 @@ class IdentityMapping: ...@@ -1306,7 +1306,7 @@ class IdentityMapping:
def hasImmutable(self, k): def hasImmutable(self, k):
return self.immutable.has_key(k) return self.immutable.has_key(k)
ppml.IdentityMapping = IdentityMapping ppml.IdentityMapping = IdentityMapping
class MinimalMapping(IdentityMapping): class MinimalMapping(IdentityMapping):
...@@ -1326,7 +1326,7 @@ class MinimalMapping(IdentityMapping): ...@@ -1326,7 +1326,7 @@ class MinimalMapping(IdentityMapping):
self.last_id = 1 self.last_id = 1
self.converted_aka = {} self.converted_aka = {}
self.marked_reference = {} self.marked_reference = {}
def __getitem__(self, id): def __getitem__(self, id):
id = str(id) id = str(id)
split_id = id.split('.') split_id = id.split('.')
...@@ -1579,7 +1579,7 @@ class ToXMLUnpickler(Unpickler): ...@@ -1579,7 +1579,7 @@ class ToXMLUnpickler(Unpickler):
def __init__(self, func): def __init__(self, func):
self.func = func self.func = func
def __call__(self, context): def __call__(self, context):
#LOG('LogCall', 0, 'self.stack = %r, func = %s' % (context.stack, self.func.__name__)) #LOG('LogCall', 0, 'self.stack = %r, func = %s' % (context.stack, self.func.__name__))
return self.func(context) return self.func(context)
...@@ -1777,7 +1777,7 @@ def SQLVar_render(self, md): ...@@ -1777,7 +1777,7 @@ def SQLVar_render(self, md):
else: else:
raise ValueError, ( raise ValueError, (
'Invalid datetime value for <em>%s</em>: %r' % (name, v)) 'Invalid datetime value for <em>%s</em>: %r' % (name, v))
try: try:
if hasattr(v, 'ISO'): if hasattr(v, 'ISO'):
v=v.ISO() v=v.ISO()
...@@ -1789,7 +1789,7 @@ def SQLVar_render(self, md): ...@@ -1789,7 +1789,7 @@ def SQLVar_render(self, md):
return 'null' return 'null'
raise ValueError, ( raise ValueError, (
'Invalid datetime value for <em>%s</em>: %r' % (name, v)) 'Invalid datetime value for <em>%s</em>: %r' % (name, v))
v=md.getitem('sql_quote__',0)(v) v=md.getitem('sql_quote__',0)(v)
# End of patch # End of patch
else: else:
...@@ -1801,7 +1801,7 @@ def SQLVar_render(self, md): ...@@ -1801,7 +1801,7 @@ def SQLVar_render(self, md):
raise ValueError, ( raise ValueError, (
'Invalid string value for <em>%s</em>' % name) 'Invalid string value for <em>%s</em>' % name)
# End of patch # End of patch
if not isinstance(v, (str, unicode)): if not isinstance(v, (str, unicode)):
v=str(v) v=str(v)
if not v and t=='nb': if not v and t=='nb':
...@@ -1848,3 +1848,48 @@ def reindexObject(self, idxs=[], *args, **kw): ...@@ -1848,3 +1848,48 @@ def reindexObject(self, idxs=[], *args, **kw):
catalog.reindexObject(self, idxs=idxs, *args, **kw) catalog.reindexObject(self, idxs=idxs, *args, **kw)
CMFCatalogAware.reindexObject = reindexObject CMFCatalogAware.reindexObject = reindexObject
##########################################
# ERP5TypeInformation filtered actions
from ZPublisher.BaseRequest import BaseRequest
BaseRequest.old_traverse = BaseRequest.traverse
def new_traverse(self, path, response=None, validated_hook=None) :
import time
start_time = time.time()
object = self.old_traverse(path, response=response, validated_hook=validated_hook)
object_id_getter = getattr(object, 'getId', None)
if response is None: response=self.response
LOG('My Traverse absolute_url', 0, path )
if hasattr(object, 'unrestrictedTraverse') :
portal_skins = aq_base(object.unrestrictedTraverse('portal_skins', default=None))
if portal_skins is not None :
skin_list = []
for skin_folder in portal_skins.getSkinPath(portal_skins.getDefaultSkin()).split(',') :
skin_folder_object = getattr(portal_skins, skin_folder, None)
if skin_folder_object is not None :
for skin in skin_folder_object._objects :
skin_list.append(skin['id'])
if object_id_getter is not None :
object_id = object_id_getter()
if object_id in skin_list :
parent = object.aq_parent
portal_type_getter = getattr(parent, 'getPortalType', None)
if portal_type_getter is not None :
portal_type_object = getattr(object.portal_types, portal_type_getter(), None)
if portal_type_object is not None :
allowed = portal_type_object.isActionAllowed(action=object_id)
LOG('My Traverse allowed', 0, repr(( path, object, allowed )))
if allowed == 0 :
LOG('My Traverse failed after TIMEEEEEEEEEEE', 0, time.time() - start_time)
response.unauthorized()
LOG('My Traverse succeded after TIMEEEEEEEEEEE', 0, time.time() - start_time)
return object
BaseRequest.traverse = new_traverse
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