Skip to content

Commit

Permalink
Use the Iterate permissions instead of CMF core permissions plone#67
Browse files Browse the repository at this point in the history
  • Loading branch information
rpatterson committed Feb 21, 2019
1 parent e54b33a commit 2f002a2
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 38 deletions.
2 changes: 2 additions & 0 deletions news/67.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Use the Iterate permissions instead of CMF core permissions to support
customizing the policy. [rpatterson]
2 changes: 1 addition & 1 deletion plone/app/iterate/browser/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
name="content-checkin"
class=".checkin.Checkin"
template="checkin.pt"
permission="cmf.ModifyPortalContent"
permission="plone.app.iterate.CheckInContent"
/>

<browser:page
Expand Down
15 changes: 9 additions & 6 deletions plone/app/iterate/browser/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
from plone.memoize.view import memoize
from Products.Five.browser import BrowserView

import Products.CMFCore.permissions
from .. import permissions


class Control(BrowserView):
Expand Down Expand Up @@ -62,11 +62,8 @@ def checkin_allowed(self):
if original is None:
return False

can_modify = checkPermission(
Products.CMFCore.permissions.ModifyPortalContent,
original,
)
if not can_modify:
can_check_in = checkPermission(permissions.CheckinPermission, original)
if not can_check_in:
return False

return True
Expand All @@ -75,6 +72,7 @@ def checkout_allowed(self):
"""Check if a checkout is allowed.
"""
context = aq_inner(self.context)
checkPermission = getSecurityManager().checkPermission

if not interfaces.IIterateAware.providedBy(context):
return False
Expand All @@ -94,6 +92,11 @@ def checkout_allowed(self):
if policy.getBaseline() is not None:
return False

can_check_out = checkPermission(
permissions.CheckoutPermission, context)
if not can_check_out:
return False

return True

@memoize
Expand Down
14 changes: 11 additions & 3 deletions plone/app/iterate/browser/info.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@

from AccessControl import getSecurityManager
from DateTime import DateTime

from plone.app.iterate.interfaces import IBaseline
from plone.app.iterate.interfaces import ICheckinCheckoutPolicy
from plone.app.iterate.interfaces import keys
from plone.app.iterate.permissions import CheckoutPermission
from plone.app.iterate import permissions

from plone.memoize.instance import memoize
from Products.CMFCore.permissions import ModifyPortalContent
from Products.CMFCore.utils import getToolByName
Expand Down Expand Up @@ -104,7 +106,10 @@ def render(self):
working_copy = self.working_copy()
if working_copy is not None and (
sm.checkPermission(ModifyPortalContent, self.context) or
sm.checkPermission(CheckoutPermission, self.context) or
sm.checkPermission(
permissions.CheckoutPermission, self.context) or
sm.checkPermission(
permissions.CheckinPermission, self.context) or
sm.checkPermission(ModifyPortalContent, working_copy)):
return self.index()
else:
Expand All @@ -127,7 +132,10 @@ def render(self):
baseline = self.baseline()
if baseline is not None and (
sm.checkPermission(ModifyPortalContent, self.context) or
sm.checkPermission(CheckoutPermission, baseline)):
sm.checkPermission(
permissions.CheckoutPermission, baseline) or
sm.checkPermission(
permissions.CheckinPermission, baseline)):
return self.index()
else:
return ''
Expand Down
20 changes: 10 additions & 10 deletions plone/app/iterate/configure.zcml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@
<include package="zope.annotation" />
<include package="Products.CMFCore" file="permissions.zcml" />

<permission
id="plone.app.iterate.CheckInContent"
title="iterate : Check in content"
/>

<permission
id="plone.app.iterate.CheckOutContent"
title="iterate : Check out content"
/>

<include package=".subscribers"/>
<include package=".browser"/>

Expand Down Expand Up @@ -85,16 +95,6 @@
handler=".event.handleDeletion"
/>

<permission
id="plone.app.iterate.CheckInContent"
title="iterate : Check in content"
/>

<permission
id="plone.app.iterate.CheckOutContent"
title="iterate : Check out content"
/>

<include package=".dexterity" zcml:condition="installed plone.app.relationfield" />
<include file="at.zcml" zcml:condition="installed Products.Archetypes" />

Expand Down
4 changes: 3 additions & 1 deletion plone/app/iterate/copier.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ def _replaceBaseline(self, baseline):
self.context._v_is_cp = 0

wc_id = self.context.getId()
wc_container.manage_delObjects([wc_id])
# Bypass AT security check,
# checking `iterate : Check in content` should be sufficient
wc_container._delObject(wc_id)

# move the working copy back to the baseline container
working_copy = aq_base(self.context)
Expand Down
7 changes: 4 additions & 3 deletions plone/app/iterate/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
CheckinPermission = 'iterate : Check in content'
CheckoutPermission = 'iterate : Check out content'

DEFAULT_ROLES = ('Manager', 'Owner', 'Site Administrator', 'Editor')
addPermission(CheckinPermission, default_roles=DEFAULT_ROLES)
addPermission(CheckoutPermission, default_roles=DEFAULT_ROLES)
addPermission(CheckinPermission, default_roles=(
'Manager', 'Site Administrator', 'Reviewer'))
addPermission(CheckoutPermission, default_roles=(
'Manager', 'Owner', 'Site Administrator', 'Editor'))
6 changes: 6 additions & 0 deletions plone/app/iterate/testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,16 @@
'password': 'secret',
'roles': ['Contributor'],
}
REVIEWER = {
'id': 'reviewer',
'password': 'secret',
'roles': ['Reviewer'],
}
USERS_TO_BE_ADDED = (
ADMIN,
EDITOR,
CONTRIBUTOR,
REVIEWER,
)
USERS_WITH_MEMBER_FOLDER = (
EDITOR,
Expand Down
34 changes: 20 additions & 14 deletions plone/app/iterate/tests/browser.rst
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ check out published pages::
True

>>> browser = z2.Browser(app)
>>> browser.handleErrors = False
>>> browser.addHeader('Authorization', 'Basic editor:secret')

>>> browser.open(portal.absolute_url() + '/hello-world')
Expand All @@ -113,19 +114,12 @@ therefore our Editor lacks permissions to modify the original::
...
LinkNotFoundError

The Editor could, however, ask someone to retract the original so he
gains permissions again and check in (and then possibly request for
review)::
The Reviewer can check the working copy back in to update the original
published item::

>>> browser = z2.Browser(app)
>>> browser.addHeader('Authorization',
... 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))
>>> browser.open(portal.absolute_url() + '/hello-world')
>>> browser.getLink("Published").click()
>>> browser.getControl("Retract").click()
>>> browser.getControl("Save").click()
>>> browser = z2.Browser(app)
>>> browser.addHeader('Authorization', 'Basic editor:secret')
>>> browser.handleErrors = False
>>> browser.addHeader('Authorization', 'Basic reviewer:secret')
>>> browser.open(portal.absolute_url() + '/hello-world')
>>> browser.getLink("working copy").click()
>>> browser.getLink("Check in").click()
Expand Down Expand Up @@ -261,8 +255,14 @@ Create a new page to test workflows with::

Checkout::

>>> import transaction
>>> from plone import api
>>> api.user.grant_roles(username='editor', roles=['Contributor'])
>>> transaction.commit()

>>> browser = z2.Browser(app)
>>> browser.addHeader('Authorization', 'Basic contributor:secret')
>>> browser.handleErrors = False
>>> browser.addHeader('Authorization', 'Basic editor:secret')
>>> browser.open(workflow_test_url)
>>> browser.getLink(id='plone-contentmenu-actions-iterate_checkout').click()
>>> browser.contents
Expand All @@ -271,23 +271,27 @@ Checkout::
>>> checkout_form.getControl('Parent folder').selected = True
>>> checkout_form.getControl('Check out').click()
>>> browser.contents
'...This is a working copy of...My workflow test..., made by...contributor...'
'...This is a working copy of...My workflow test..., made by...editor...'
>>> browser.contents
'...state-draft-copy...'
>>> workflow_checkout_url = browser.url

>>> api.user.revoke_roles(username='editor', roles=['Contributor'])
>>> transaction.commit()

Check get info message on original::

>>> browser.open(workflow_test_url)
>>> browser.contents
'...This item is being edited by...contributor...a working copy...'
'...This item is being edited by...editor...a working copy...'

We're going to manually give the contributor user the CheckoutPermission
to check it's used when displaying the info messages. In our workflow
once the checked out item is submitted the contributor no longer has
permission to modify it but we still want them to see the info messages::

>>> browser = z2.Browser(app)
>>> browser.handleErrors = False
>>> browser.addHeader('Authorization',
... 'Basic %s:%s' % (SITE_OWNER_NAME, SITE_OWNER_PASSWORD))

Expand All @@ -297,6 +301,7 @@ permission to modify it but we still want them to see the info messages::
>>> browser.getControl('Save Changes').click()

>>> browser = z2.Browser(app)
>>> browser.handleErrors = False
>>> browser.addHeader('Authorization', 'Basic contributor:secret')
>>> browser.open(workflow_checkout_url)
>>> browser.getLink(id='workflow-transition-submit-copy-for-publication')\
Expand All @@ -314,6 +319,7 @@ move permissions in our workflow so this should not appear in the action menu.
http://code.google.com/p/dexterity/issues/detail?id=258 ::

>>> browser = z2.Browser(app)
>>> browser.handleErrors = False
>>> browser.addHeader('Authorization', 'Basic editor:secret')
>>> browser.open(workflow_checkout_url)
>>> browser.getLink(id='plone-contentmenu-actions-copy')
Expand Down

0 comments on commit 2f002a2

Please sign in to comment.