Commit 930c7aa9 authored by wenjie.zheng's avatar wenjie.zheng

ERP5Workflow: Interface, Assignment of roles to permissions, New class to bind role and permission.

parent 2b781fd2
......@@ -657,6 +657,8 @@ def intializePortalTypeERP5WorkflowMethod(ptype_klass, portal_ERP5Workflow):
for tr in wf5_module._getOb(ERP5Workflow_id).objectValues(portal_type="Transition"):
tr_id = tr.id
method_id = convertToMixedCase(tr_id)
ptype_klass.security.declareProtected(Permissions.AccessContentsInformation,
method_id)
ptype_klass.registerERP5WorkflowMethod(method_id, ERP5Workflow_id, tr_id, 0)
LOG("ERP5Workflow method %s is generated"%tr_id,WARNING," for %s"%ERP5Workflow_id)
......@@ -3378,12 +3380,20 @@ class Base( CopyContainer,
There's no check that the document is actually chained to the workflow,
it's caller responsability to perform this check.
"""
workflow = self.portal_workflow.getWorkflowById(wf_id)
erp5workflow = self.workflow_module._getOb(wf_id, None)
if workflow is not None:
changed = workflow.updateRoleMappingsFor(self)
if changed:
self.reindexObjectSecurity(activate_kw={'priority':4})
### zwj: update role changed through erp5workflow
if erp5workflow is not None:
changed = erp5workflow.updateRoleMappingFor(self)
if changed:
self.reindexObjectSecurity(activate_kw={'priority':4})
# Template Management
security.declareProtected(Permissions.View, 'getDocumentTemplateList')
def getDocumentTemplateList(self) :
......
##############################################################################
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Wenjie ZHENG <wenjie.zheng@tiolive.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 Acquisition import aq_inner
from Acquisition import aq_parent
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from zLOG import LOG, ERROR, DEBUG, WARNING
class PermissionRoles(XMLObject):
"""
Permission role matrix cell unit,
Used to assign a role to a permission.
"""
meta_type = 'ERP5 PermissionRoles'
portal_type = 'PermissionRoles'
add_permission = Permissions.AddPortalContent
is_selected = 0 ### for checkerbox (True 1 /False 0)
isPortalContent = 1
isRADContent = 1
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
# Declarative properties
property_sheets = (
PropertySheet.Base,
PropertySheet.XMLObject,
PropertySheet.CategoryCore,
PropertySheet.DublinCore,
PropertySheet.State,)
def getId(self):
return self.id
def getPermissionRole(self):
if self.is_selected == 1:
permission_id = self.getId().split('_')[1]
role_id = self.getId().split('_')[2]
permission_list = sorted(self.getParent().getParent().getManagedPermissionList())
role_list = sorted(["Anonymous", "Assignee", "Assignor", "Associate",
"Auditor", "Authenticated", "Author", "Manager",
"Member", "Owner", "Reviewer"])
permission = permission_list[permission_id]
role = role_list[role_id]
LOG('zwj: Assign %s to %s' %(role, permission), WARNING, "in PermissionRole.")
return permission, role
def setPermissionRoleMap(self):
if is_selected == 1:
permission_id = self.id.split('_')[1]
role_id = self.id.split('_')[2]
permission_list = sorted(self.getParent().getParent().getManagedPermissionList())
role_list = sorted(["Anonymous", "Assignee", "Assignor", "Associate",
"Auditor", "Authenticated", "Author", "Manager",
"Member", "Owner", "Reviewer"])
permission = permission_list[permission_id]
role = role_list[role_id]
......@@ -2,7 +2,7 @@
#
# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved.
# Romain Courteaud <romain@nexedi.com>
#
# Wenjie ZHENG <wenjie.zheng@tiolive.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
......@@ -27,10 +27,13 @@
##############################################################################
from AccessControl import ClassSecurityInfo
from Persistence import PersistentMapping
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLMatrix import XMLMatrix
from Products.ERP5Type.XMLObject import XMLObject
from zLOG import LOG, ERROR, DEBUG, WARNING
from Acquisition import aq_inner
from Acquisition import aq_parent
class StateError(Exception):
"""
......@@ -38,7 +41,7 @@ class StateError(Exception):
"""
pass
class State(XMLObject):
class State(XMLObject, XMLMatrix):
"""
A ERP5 State.
"""
......@@ -47,6 +50,9 @@ class State(XMLObject):
add_permission = Permissions.AddPortalContent
isPortalContent = 1
isRADContent = 1
###zwj: security features
erp5_permission_roles = {} # { permission: [role] or (role,) }
group_roles = None
# Declarative security
security = ClassSecurityInfo()
......@@ -120,3 +126,94 @@ class State(XMLObject):
"""
status_dict = self.getParentValue().getCurrentStatusDict(document)
return status_dict[variable_name]
##### zwj: following parts related to the security features ####################
### zwj: Martix method
# Multiple inheritance definition
updateRelatedContent = XMLMatrix.updateRelatedContent
security.declareProtected(Permissions.AccessContentsInformation,
'hasCellContent')
def hasCellContent(self, base_id='movement'): ### zwj: findout what is base_id
"""Return true if the object contains cells.
"""
# Do not use XMLMatrix.hasCellContent, because it can generate
# inconsistency in catalog
# Exemple: define a line and set the matrix cell range, but do not create
# cell.
# Line was in this case consider like a movement, and was catalogued.
# But, getVariationText of the line was not empty.
# So, in ZODB, resource as without variation, but in catalog, this was
# the contrary...
cell_range = XMLMatrix.getCellRange(self, base_id=base_id)
return (cell_range is not None and len(cell_range) > 0)
# DeliveryLine can be a movement when it does not content any cell and
# matrix cell range is not empty.
# Better implementation is needed.
# We want to define a line without cell, defining a variated resource.
# If we modify the cell range, we need to move the quantity to a new
# cell, which define the same variated resource.
# return XMLMatrix.hasCellContent(self, base_id=base_id)
security.declareProtected( Permissions.AccessContentsInformation, 'getCell' )
def getCell(self, *kw , **kwd):
"""
This method can be overriden
"""
if 'base_id' not in kwd:
kwd['base_id'] = 'movement'
return XMLMatrix.getCell(self, *kw, **kwd)
security.declareProtected( Permissions.ModifyPortalContent, 'newCell' )
def newCell(self, *kw, **kwd):
"""
This method creates a new cell
"""
if 'base_id' not in kwd:
kwd['base_id'] = 'movement'
return XMLMatrix.newCell(self, *kw, **kwd)
### matrix method
def setPermission(self, permission, acquired, roles, REQUEST=None):
"""Set a permission for this State."""
pr = self.erp5_permission_roles
if pr is None:
self.erp5_permission_roles = pr = PersistentMapping()
if acquired:
roles = list(roles)
else:
roles = tuple(roles)
pr[permission] = roles
def getPermissionRoleList(self):
return self.erp5_permission_roles
def getWorkflow(self):
return aq_parent(aq_inner(aq_parent(aq_inner(self))))
def setGroups(self, REQUEST, RESPONSE=None):
"""Set the group to role mappings in REQUEST for this State.
"""
map = self.group_roles
if map is None:
self.group_roles = map = PersistentMapping()
map.clear()
all_roles = self.getWorkflow().getRoles()
for group in self.getWorkflow().getGroups():
roles = []
for role in all_roles:
if REQUEST.get('%s|%s' % (group, role), 0):
roles.append(role)
roles.sort()
roles = tuple(roles)
map[group] = roles
if RESPONSE is not None:
RESPONSE.redirect(
"%s/manage_groups?manage_tabs_message=Groups+changed."
% self.absolute_url())
......@@ -29,6 +29,7 @@
from AccessControl import ClassSecurityInfo
from Acquisition import aq_inner
from Acquisition import aq_parent
from Products.DCWorkflow.utils import modifyRolesForPermission
from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type.Globals import PersistentMapping
......@@ -53,6 +54,12 @@ class Workflow(XMLObject):
isPortalContent = 1
isRADContent = 1
### zwj: for security issue
managed_permission = ()
role = None
group = ()
erp5_permission_roles = {} # { permission: [role] or (role,) }
# Declarative security
security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation)
......@@ -127,6 +134,9 @@ class Workflow(XMLObject):
"""
return DateTime()
def getManagedPermissionList(self):
return self.managed_permission
def getStateChangeInformation(self, document, state, transition=None):
"""
Return an object used for variable tales expression.
......@@ -142,15 +152,73 @@ class Workflow(XMLObject):
def isERP5WorkflowMethodSupported(self, document, transition):
sdef = document._getDefaultAcquiredValue(self.getStateBaseCategory())
### zwj: upper line may meet problems when there are other Base categories.
if sdef is None:
return 0
if transition in sdef.getDestinationValueList():
return 1
return 0
### zwj: following parts related to the security features
security.declarePrivate('updateRoleMappingsFor')
def updateRoleMappingsFor(self, document):
"""Changes the object permissions according to the current state.
"""
changed = 0
sdef = sdef = document._getDefaultAcquiredValue(self.getStateBaseCategory())
if sdef is None:
return 0
"""
# Update the role -> permission map.
if self.permissions:
for p in self.permissions:
roles = []
if sdef.erp5_permission_roles is not None: ### permission is defined in state
roles = sdef.erp5_permission_roles.get(p, roles)
if modifyRolesForPermission(document, p, roles):
changed = 1
"""
### zwj: get all matrix cell objects
permission_role_matrix_cells = sdef.objectValues(portal_type = "PermissionRoles")
### zwj: build a permission roles dict
for perm_role in permission_role_matrix_cells:
permission,role = perm_role.getPermissionRole()
if erp5_permission_roles[permission]:
erp5_permission_roles[permission] = erp5_permission_roles[permission] + role
else:
erp5_permission_roles.update({permission : role})
### zwj: update role list to permission
for permission_roles in erp5_permission_roles:
if modifyRolesForPermission(document, permission_roles, erp5_permission_roles[permission_roles]):
changed = 1
# Update the group -> role map.
groups = self.getGroups()
managed_roles = self.getRoles()
if groups and managed_roles:
for group in groups:
roles = ()
if sdef.group_roles is not None:
roles = sdef.group_roles.get(group, ())
if modifyRolesForGroup(document, group, roles, managed_roles):
changed = 1
return changed
def _checkTransitionGuard(self, t, document, **kw):
guard = t.guard
if guard is None:
return 1
if guard.check(getSecurityManager(), self, document, **kw):
return 1
return
### Security feature end
###########
## Graph ##
############
###########
getGraph = getGraph
......
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