Reputation: 243
Using the Intranet workflow, and when the user selects the hide transition to move the content to the private state, I want to disable local role acquisition. I think I'll want to re-enable when they move it back to internal draft.
I can see how this is done by the sharing view within plone.app.workflow. It has a method, update_inherit, that sets context.__ac_local_roles_block__
to either True
or None
.
How might I do something similar with a transition after_script?
More info on my use case:
We have two users, contributor_1 and contributor_2, possessing only the Member role globally. At the site root, create a folder and assign the two users local roles to add, edit, and view.
Here is the default private state/manage_permissions:
If contributor_1 creates a page and tries to hide it, contributor_2 can still view, edit, and transition it back to internal draft because contributor_2 is inheriting those local roles.
Here is what I first tried:
While this does effectively make the page private to only contributor_1 and any Manager, contributor_1 cannot share access with contributor_2 while the item is in the private state. No private collaboration. UPDATE: contributor_1 can manipulate the sharing view (ie. they have access to delegate local roles), but delegating those local roles (Contributor, Editor, Reader) does not translate to their respective access since I have revoked the role-permission mapping in the above workflow.
Now, if set back to the default permission map, users can achieve the private state they want by hiding the content item and then going to the sharing tab and disabling local role acquisition. The problem is they don't want to have to remember to click the checkbox on the sharing tab every time they want to hide something.
Upvotes: 0
Views: 336
Reputation: 243
I created a utils.py module within my package containing one method: a (nearly) straight copypasta of the update_inherit method the sharing view uses. Then, I imported utils in my package's __init__.py
.
from AccessControl import Unauthorized
from AccessControl.SecurityInfo import ModuleSecurityInfo
from Acquisition import aq_base
from Products.CMFCore import permissions
from Products.CMFCore.utils import getToolByName
security = ModuleSecurityInfo( 'united.policy.utils' )
security.declarePublic('update_inherit')
def update_inherit(context, status=True, reindex=True):
"""Enable or disable local role acquisition on the context.
Returns True if changes were made, or False if the new settings are the
same as the existing settings.
"""
portal_membership = getToolByName(context, 'portal_membership')
if not portal_membership.checkPermission(permissions.ModifyPortalContent,
context):
raise Unauthorized
block = not status
oldblock = bool(getattr(aq_base(context), '__ac_local_roles_block__',
False))
if block == oldblock:
return False
if block:
# If user has inherited local roles and removes inheritance, locally
# set roles he inherited before to avoid definitive loss of access
# (refs #11945)
user = portal_membership.getAuthenticatedMember()
context_roles = user.getRolesInContext(context)
global_roles = user.getRoles()
local_roles = [r for r in context_roles if r not in global_roles]
if local_roles:
context.manage_setLocalRoles(user.getId(), local_roles)
context.__ac_local_roles_block__ = block and True or None
if reindex:
context.reindexObjectSecurity()
return True
Then, I created two scripts within my ./profiles/default/workflows/intranet_workflow/scripts/
directory bound to their respective transitions:
after_hide.py
## Script (Python) "after_hide"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=review_state
##title=
##
from united.policy.utils import update_inherit
update_inherit(review_state.object, False)
after_show.py
## Script (Python) "after_show"
##bind container=container
##bind context=context
##bind namespace=
##bind script=script
##bind subpath=traverse_subpath
##parameters=review_state
##title=
##
from united.policy.utils import update_inherit
update_inherit(review_state.object, True)
Upvotes: 1
Reputation: 6839
As SteveM already commented, the workflow tool can handle this for you.
You need need to manage all the necessary permission with your workflow, this depends on your needs. UPDATE: You workflow has to manage the "Delegate Roles XYZ [Reader/Contributor/etc.]" and "Change local roles" permissions. This way the user "contributor_1" can delegate roles in the "Private" area.
Do NOT acquire any permission settings on your hidden
state.
In your case the Owner (probably the manager too) needs some permissions to view/edit/changestate.
Another hint for defining workflows. Check this package it generally manages all the permissions in action groups, like View (View, Access content permissions, etc) or Add (Add Folders, Add portal content, Add..., etc.) All Plone default permissions are mapped to the right action group, and it let's you create a workflow within 5 minutes. The best part is, you can write the workflow in human readable specification file (custom DSL).
Upvotes: 1