Merge pull request #115 from plone/apply-hotfix-20161129-master

Apply hotfix 20161129 [master]
This commit is contained in:
Maurits van Rees 2017-01-16 16:39:32 +01:00 committed by GitHub
commit 31e7fab26c
17 changed files with 272 additions and 46 deletions

View File

@ -14,7 +14,8 @@ New features:
Bug fixes: Bug fixes:
- *add item here* - Make comment on private content not publicly available in search results.
Part of PloneHotfix20161129. [vangheem, maurits]
2.4.19 (2017-01-02) 2.4.19 (2017-01-02)

View File

@ -125,7 +125,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
output.append('globally_enabled') output.append('globally_enabled')
# Comment moderation # Comment moderation
one_state_worklow_disabled = 'one_state_workflow' not in workflow_chain one_state_worklow_disabled = 'comment_one_state_workflow' not in workflow_chain
comment_review_workflow_disabled = \ comment_review_workflow_disabled = \
'comment_review_workflow' not in workflow_chain 'comment_review_workflow' not in workflow_chain
if one_state_worklow_disabled and comment_review_workflow_disabled: if one_state_worklow_disabled and comment_review_workflow_disabled:
@ -174,7 +174,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
""" """
wftool = getToolByName(self.context, 'portal_workflow', None) wftool = getToolByName(self.context, 'portal_workflow', None)
workflow_chain = wftool.getChainForPortalType('Discussion Item') workflow_chain = wftool.getChainForPortalType('Discussion Item')
one_state_workflow_enabled = 'one_state_workflow' in workflow_chain one_state_workflow_enabled = 'comment_one_state_workflow' in workflow_chain
comment_review_workflow_enabled = \ comment_review_workflow_enabled = \
'comment_review_workflow' in workflow_chain 'comment_review_workflow' in workflow_chain
if one_state_workflow_enabled or comment_review_workflow_enabled: if one_state_workflow_enabled or comment_review_workflow_enabled:
@ -199,7 +199,7 @@ def notify_configuration_changed(event):
else: else:
# Disable moderation workflow # Disable moderation workflow
wftool.setChainForPortalTypes(('Discussion Item',), wftool.setChainForPortalTypes(('Discussion Item',),
'one_state_workflow') 'comment_one_state_workflow')
if IConfigurationChangedEvent.providedBy(event): if IConfigurationChangedEvent.providedBy(event):
# Types control panel setting changed # Types control panel setting changed
@ -209,7 +209,7 @@ def notify_configuration_changed(event):
workflow_chain = wftool.getChainForPortalType('Discussion Item') workflow_chain = wftool.getChainForPortalType('Discussion Item')
if workflow_chain: if workflow_chain:
workflow = workflow_chain[0] workflow = workflow_chain[0]
if workflow == 'one_state_workflow': if workflow == 'comment_one_state_workflow':
settings.moderation_enabled = False settings.moderation_enabled = False
elif workflow == 'comment_review_workflow': elif workflow == 'comment_review_workflow':
settings.moderation_enabled = True settings.moderation_enabled = True

View File

@ -40,26 +40,7 @@
provides="Products.GenericSetup.interfaces.EXTENSION" provides="Products.GenericSetup.interfaces.EXTENSION"
for="Products.CMFPlone.interfaces.IPloneSiteRoot" for="Products.CMFPlone.interfaces.IPloneSiteRoot"
/> />
<!-- For upgrade steps see upgrades.zcml. -->
<genericsetup:upgradeStep
title="edit comments and delete own comments"
description="reload registry config to enable new fields edit_comment_enabled and delete_own_comment_enabled"
source="100"
destination="101"
handler=".upgrades.update_registry"
sortkey="1"
profile="plone.app.discussion:default"
/>
<genericsetup:upgradeStep
title="delete comments and delete own comments"
description="reload rolemap config to enable new permissions 'Delete comments' and 'Delete own comments'"
source="101"
destination="102"
handler=".upgrades.update_rolemap"
sortkey="1"
profile="plone.app.discussion:default"
/>
<!-- Comments --> <!-- Comments -->

View File

@ -1,5 +1,5 @@
<metadata> <metadata>
<version>102</version> <version>1000</version>
<dependencies> <dependencies>
<dependency>profile-plone.app.registry:default</dependency> <dependency>profile-plone.app.registry:default</dependency>
</dependencies> </dependencies>

View File

@ -1,9 +1,10 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<object name="portal_workflow" meta_type="Plone Workflow Tool"> <object name="portal_workflow" meta_type="Plone Workflow Tool">
<object name="comment_review_workflow" meta_type="Workflow"/> <object name="comment_review_workflow" meta_type="Workflow"/>
<object name="comment_one_state_workflow" meta_type="Workflow"/>
<bindings> <bindings>
<type type_id="Discussion Item"> <type type_id="Discussion Item">
<bound-workflow workflow_id="one_state_workflow" /> <bound-workflow workflow_id="comment_one_state_workflow" />
</type> </type>
</bindings> </bindings>
</object> </object>

View File

@ -0,0 +1,80 @@
<?xml version="1.0"?>
<dc-workflow workflow_id="comment_one_state_workflow" title="Single State Workflow" description="- Essentially a workflow with no transitions, but has a Published state, so portlets and applications that expect that state will continue to work." state_variable="review_state" initial_state="published" manager_bypass="False" >
<permission>Access contents information</permission>
<permission>Change portal events</permission>
<permission>Modify portal content</permission>
<permission>View</permission>
<state state_id="published" title="Published" >
<description>Visible to everyone, editable by the owner.</description>
<permission-map name="Access contents information" acquired="False">
<permission-role>Anonymous</permission-role>
</permission-map>
<permission-map name="Change portal events" acquired="False">
<permission-role>Manager</permission-role>
<permission-role>Owner</permission-role>
<permission-role>Editor</permission-role>
<permission-role>Site Administrator</permission-role>
</permission-map>
<permission-map name="Modify portal content" acquired="False">
<permission-role>Manager</permission-role>
<permission-role>Owner</permission-role>
<permission-role>Editor</permission-role>
<permission-role>Site Administrator</permission-role>
</permission-map>
<permission-map name="View" acquired="True">
</permission-map>
</state>
<variable variable_id="action" for_catalog="False" for_status="True" update_always="True" >
<description>Previous transition</description>
<default>
<expression>transition/getId|nothing</expression>
</default>
<guard >
</guard>
</variable>
<variable variable_id="actor" for_catalog="False" for_status="True" update_always="True" >
<description>The ID of the user who performed the previous transition</description>
<default>
<expression>user/getId</expression>
</default>
<guard >
</guard>
</variable>
<variable variable_id="comments" for_catalog="False" for_status="True" update_always="True" >
<description>Comment about the last transition</description>
<default>
<expression>python:state_change.kwargs.get('comment', '')</expression>
</default>
<guard >
</guard>
</variable>
<variable variable_id="review_history" for_catalog="False" for_status="False" update_always="False" >
<description>Provides access to workflow history</description>
<default>
<expression>state_change/getHistory</expression>
</default>
<guard >
<guard-permission>Request review</guard-permission>
<guard-permission>Review portal content</guard-permission>
</guard>
</variable>
<variable variable_id="time" for_catalog="False" for_status="True" update_always="True" >
<description>When the previous transition was performed</description>
<default>
<expression>state_change/getDateTime</expression>
</default>
<guard >
</guard>
</variable>
</dc-workflow>

View File

@ -41,14 +41,12 @@
<description i18n:translate=""> <description i18n:translate="">
Visible to everyone, non-editable. Visible to everyone, non-editable.
</description> </description>
<permission-map name="Access contents information" acquired="False"> <permission-map name="Access contents information" acquired="True">
<permission-role>Anonymous</permission-role>
</permission-map> </permission-map>
<permission-map name="Modify portal content" acquired="False"> <permission-map name="Modify portal content" acquired="False">
<permission-role>Manager</permission-role> <permission-role>Manager</permission-role>
</permission-map> </permission-map>
<permission-map name="View" acquired="False"> <permission-map name="View" acquired="True">
<permission-role>Anonymous</permission-role>
</permission-map> </permission-map>
<permission-map name="Reply to item" acquired="True"> <permission-map name="Reply to item" acquired="True">
</permission-map> </permission-map>

View File

@ -59,6 +59,10 @@ class ConversationCatalogTest(unittest.TestCase):
def setUp(self): def setUp(self):
self.portal = self.layer['portal'] self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager']) setRoles(self.portal, TEST_USER_ID, ['Manager'])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
self.catalog = getToolByName(self.portal, 'portal_catalog') self.catalog = getToolByName(self.portal, 'portal_catalog')
conversation = IConversation(self.portal.doc1) conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')

View File

@ -27,6 +27,9 @@ class CommentTest(unittest.TestCase):
self.portal = self.layer['portal'] self.portal = self.layer['portal']
self.request = self.layer['request'] self.request = self.layer['request']
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
setRoles(self.portal, TEST_USER_ID, ['Manager']) setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.catalog = getToolByName(self.portal, 'portal_catalog') self.catalog = getToolByName(self.portal, 'portal_catalog')
self.document_brain = self.catalog.searchResults( self.document_brain = self.catalog.searchResults(
@ -351,6 +354,9 @@ class RepliesTest(unittest.TestCase):
self.portal = self.layer['portal'] self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager']) setRoles(self.portal, TEST_USER_ID, ['Manager'])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
def test_add_comment(self): def test_add_comment(self):
# Add comments to a CommentReplies adapter # Add comments to a CommentReplies adapter

View File

@ -458,7 +458,7 @@ class TestCommentsViewlet(unittest.TestCase):
) )
self.workflowTool = getToolByName(self.portal, 'portal_workflow') self.workflowTool = getToolByName(self.portal, 'portal_workflow')
self.workflowTool.setDefaultChain('one_state_workflow') self.workflowTool.setDefaultChain('comment_one_state_workflow')
self.membershipTool = getToolByName(self.folder, 'portal_membership') self.membershipTool = getToolByName(self.folder, 'portal_membership')
self.memberdata = self.portal.portal_memberdata self.memberdata = self.portal.portal_memberdata

View File

@ -163,9 +163,9 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
the 'comment_moderation' setting in the discussion control panel the 'comment_moderation' setting in the discussion control panel
changes. changes.
""" """
# By default the one_state_workflow without moderation is enabled # By default the comment_one_state_workflow without moderation is enabled
self.assertEqual( self.assertEqual(
('one_state_workflow',), ('comment_one_state_workflow',),
self.portal.portal_workflow.getChainForPortalType( self.portal.portal_workflow.getChainForPortalType(
'Discussion Item' 'Discussion Item'
) )
@ -185,7 +185,7 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
# And back # And back
self.settings.moderation_enabled = False self.settings.moderation_enabled = False
self.assertEqual( self.assertEqual(
('one_state_workflow',), ('comment_one_state_workflow',),
self.portal.portal_workflow.getChainForPortalType( self.portal.portal_workflow.getChainForPortalType(
'Discussion Item' 'Discussion Item'
) )
@ -211,7 +211,7 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
# Enable the 'comment_review_workflow' with moderation enabled # Enable the 'comment_review_workflow' with moderation enabled
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('one_state_workflow',) ('comment_one_state_workflow',)
) )
self.settings.moderation_enabled = True self.settings.moderation_enabled = True

View File

@ -50,6 +50,9 @@ class ConversationTest(unittest.TestCase):
settings = registry.forInterface(IDiscussionSettings) settings = registry.forInterface(IDiscussionSettings)
settings.globally_enabled = True settings.globally_enabled = True
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
def test_add_comment(self): def test_add_comment(self):
# Create a conversation. In this case we doesn't assign it to an # Create a conversation. In this case we doesn't assign it to an
# object, as we just want to check the Conversation object API. # object, as we just want to check the Conversation object API.
@ -744,6 +747,9 @@ class RepliesTest(unittest.TestCase):
self.portal = self.layer['portal'] self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager']) setRoles(self.portal, TEST_USER_ID, ['Manager'])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
def test_add_comment(self): def test_add_comment(self):
# Add comments to a ConversationReplies adapter # Add comments to a ConversationReplies adapter

View File

@ -35,6 +35,9 @@ class ConversationIndexersTest(unittest.TestCase):
self.portal = self.layer['portal'] self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager']) setRoles(self.portal, TEST_USER_ID, ['Manager'])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
# Create a conversation. # Create a conversation.
conversation = IConversation(self.portal.doc1) conversation = IConversation(self.portal.doc1)

View File

@ -46,9 +46,9 @@ class ModerationViewTest(unittest.TestCase):
# If workflow is not set, enabled must return False # If workflow is not set, enabled must return False
self.wf_tool.setChainForPortalTypes(('Discussion Item',), ()) self.wf_tool.setChainForPortalTypes(('Discussion Item',), ())
self.assertEqual(self.view.moderation_enabled(), False) self.assertEqual(self.view.moderation_enabled(), False)
# The one_state_workflow does not have a 'pending' state # The comment_one_state_workflow does not have a 'pending' state
self.wf_tool.setChainForPortalTypes(('Discussion Item',), self.wf_tool.setChainForPortalTypes(('Discussion Item',),
('one_state_workflow,')) ('comment_one_state_workflow,'))
self.assertEqual(self.view.moderation_enabled(), False) self.assertEqual(self.view.moderation_enabled(), False)
# The comment_review_workflow does have a 'pending' state # The comment_review_workflow does have a 'pending' state
self.wf_tool.setChainForPortalTypes(('Discussion Item',), self.wf_tool.setChainForPortalTypes(('Discussion Item',),

View File

@ -9,6 +9,7 @@ from plone.app.testing import login
from plone.app.testing import logout from plone.app.testing import logout
from plone.app.testing import setRoles from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID from plone.app.testing import TEST_USER_ID
from plone.app.testing import TEST_USER_NAME
from Products.CMFCore.permissions import View from Products.CMFCore.permissions import View
from Products.CMFCore.utils import _checkPermission as checkPerm from Products.CMFCore.utils import _checkPermission as checkPerm
from zope.component import createObject from zope.component import createObject
@ -35,7 +36,7 @@ class WorkflowSetupTest(unittest.TestCase):
def test_workflows_installed(self): def test_workflows_installed(self):
"""Make sure both comment workflows have been installed properly. """Make sure both comment workflows have been installed properly.
""" """
self.assertTrue('one_state_workflow' in self.assertTrue('comment_one_state_workflow' in
self.portal.portal_workflow.objectIds()) self.portal.portal_workflow.objectIds())
self.assertTrue('comment_review_workflow' in self.assertTrue('comment_review_workflow' in
self.portal.portal_workflow.objectIds()) self.portal.portal_workflow.objectIds())
@ -44,7 +45,7 @@ class WorkflowSetupTest(unittest.TestCase):
"""Make sure one_state_workflow is the default workflow. """Make sure one_state_workflow is the default workflow.
""" """
self.assertEqual( self.assertEqual(
('one_state_workflow',), ('comment_one_state_workflow',),
self.portal.portal_workflow.getChainForPortalType( self.portal.portal_workflow.getChainForPortalType(
'Discussion Item' 'Discussion Item'
) )
@ -102,7 +103,7 @@ class PermissionsSetupTest(unittest.TestCase):
class CommentOneStateWorkflowTest(unittest.TestCase): class CommentOneStateWorkflowTest(unittest.TestCase):
"""Test the one_state_workflow that ships with plone.app.discussion. """Test the comment_one_state_workflow that ships with plone.app.discussion.
""" """
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
@ -114,8 +115,6 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
self.folder = self.portal['test-folder'] self.folder = self.portal['test-folder']
self.catalog = self.portal.portal_catalog self.catalog = self.portal.portal_catalog
self.workflow = self.portal.portal_workflow self.workflow = self.portal.portal_workflow
self.workflow.setChainForPortalTypes(['Document'],
'one_state_workflow')
self.folder.invokeFactory('Document', 'doc1') self.folder.invokeFactory('Document', 'doc1')
self.doc = self.folder.doc1 self.doc = self.folder.doc1
@ -137,10 +136,10 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
self.portal.acl_users._doAddUser('reader', 'secret', ['Reader'], []) self.portal.acl_users._doAddUser('reader', 'secret', ['Reader'], [])
def test_initial_workflow_state(self): def test_initial_workflow_state(self):
"""Make sure the initial workflow state of a comment is 'published'. """Make sure the initial workflow state of a comment is 'private'.
""" """
self.assertEqual(self.workflow.getInfoFor(self.doc, 'review_state'), self.assertEqual(self.workflow.getInfoFor(self.doc, 'review_state'),
'published') 'private')
def test_view_comments(self): def test_view_comments(self):
"""Make sure published comments can be viewed by everyone. """Make sure published comments can be viewed by everyone.
@ -149,6 +148,10 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
# self.login(default_user) # self.login(default_user)
# self.assertTrue(checkPerm(View, self.doc)) # self.assertTrue(checkPerm(View, self.doc))
# Member is allowed # Member is allowed
login(self.portal, TEST_USER_NAME)
workflow = self.portal.portal_workflow
workflow.doActionFor(self.doc, 'publish')
login(self.portal, 'member') login(self.portal, 'member')
self.assertTrue(checkPerm(View, self.comment)) self.assertTrue(checkPerm(View, self.comment))
# Reviewer is allowed # Reviewer is allowed
@ -164,6 +167,30 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
login(self.portal, 'reader') login(self.portal, 'reader')
self.assertTrue(checkPerm(View, self.comment)) self.assertTrue(checkPerm(View, self.comment))
def test_comment_on_private_content_not_visible_to_world(self):
logout()
self.assertFalse(checkPerm(View, self.comment))
def test_migration(self):
from plone.app.discussion.upgrades import upgrade_comment_workflows
# Fake permission according to earlier one_comment_workflow.
self.comment._View_Permission = ('Anonymous',)
# Anonymous can see the comment.
logout()
self.assertTrue(checkPerm(View, self.comment))
# Run the upgrade.
login(self.portal, TEST_USER_NAME)
upgrade_comment_workflows(self.portal.portal_setup)
# The workflow chain is still what we want.
self.assertEqual(
self.portal.portal_workflow.getChainFor('Discussion Item'),
('comment_one_state_workflow',))
# A Manager can still see the comment.
self.assertTrue(checkPerm(View, self.comment))
# Anonymous cannot see the comment.
logout()
self.assertFalse(checkPerm(View, self.comment))
class CommentReviewWorkflowTest(unittest.TestCase): class CommentReviewWorkflowTest(unittest.TestCase):
"""Test the comment_review_workflow that ships with plone.app.discussion. """Test the comment_review_workflow that ships with plone.app.discussion.
@ -269,3 +296,35 @@ class CommentReviewWorkflowTest(unittest.TestCase):
'review_state' 'review_state'
) )
) )
def test_publish_comment_on_private_content_not_visible_to_world(self):
logout()
self.assertFalse(checkPerm(View, self.comment))
# publish comment and check again
login(self.portal, TEST_USER_NAME)
workflow = self.portal.portal_workflow
workflow.doActionFor(self.comment, 'publish')
logout()
self.assertFalse(checkPerm(View, self.comment))
def test_migration(self):
from plone.app.discussion.upgrades import upgrade_comment_workflows
# Fake permission according to earlier comment_review_workflow.
self.comment._View_Permission = ('Anonymous',)
# Anonymous can see the comment.
logout()
self.assertTrue(checkPerm(View, self.comment))
# Run the upgrade.
login(self.portal, TEST_USER_NAME)
upgrade_comment_workflows(self.portal.portal_setup)
# The workflow chain is still what we want.
self.assertEqual(
self.portal.portal_workflow.getChainFor('Discussion Item'),
('comment_review_workflow',))
# A Manager can still see the comment.
self.assertTrue(checkPerm(View, self.comment))
# Anonymous cannot see the comment.
logout()
self.assertFalse(checkPerm(View, self.comment))

View File

@ -1,10 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import IDiscussionSettings from plone.app.discussion.interfaces import IDiscussionSettings
from plone.registry.interfaces import IRegistry from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName
from zope.component import getUtility from zope.component import getUtility
import logging
default_profile = 'profile-plone.app.discussion:default' default_profile = 'profile-plone.app.discussion:default'
logger = logging.getLogger('plone.app.discussion')
def update_registry(context): def update_registry(context):
@ -14,3 +18,46 @@ def update_registry(context):
def update_rolemap(context): def update_rolemap(context):
context.runImportStepFromProfile(default_profile, 'rolemap') context.runImportStepFromProfile(default_profile, 'rolemap')
def upgrade_comment_workflows(context):
# If the current comment workflow is the one_state_workflow, running our
# import step will change it to comment_one_state_workflow. This is good.
# If it was anything else, we should restore this. So get the original
# chain.
portal_type = 'Discussion Item'
wf_tool = getToolByName(context, 'portal_workflow')
orig_chain = list(wf_tool.getChainFor(portal_type))
# Run the workflow step. This sets the chain to
# comment_one_state_workflow.
context.runImportStepFromProfile(default_profile, 'workflow')
# Restore original workflow chain if needed.
old_workflow = 'one_state_workflow'
if old_workflow not in orig_chain:
# Restore the chain. Probably comment_review_workflow.
wf_tool.setChainForPortalTypes([portal_type], orig_chain)
elif len(orig_chain) > 1:
# This is strange, but I guess it could happen.
if old_workflow in orig_chain:
# Replace with new one.
idx = orig_chain.index(old_workflow)
orig_chain[idx] = 'comment_one_state_workflow'
# Restore the chain.
wf_tool.setChainForPortalTypes([portal_type], orig_chain)
new_chain = list(wf_tool.getChainFor(portal_type))
workflows = [wf_tool.getWorkflowById(wf_id)
for wf_id in new_chain]
# Now go over the comments, update their role mappings, and reindex the
# allowedRolesAndUsers index.
catalog = getToolByName(context, 'portal_catalog')
for brain in catalog.unrestrictedSearchResults(portal_type=portal_type):
try:
comment = brain.getObject()
for wf in workflows:
wf.updateRoleMappingsFor(comment)
comment.reindexObjectSecurity()
except (AttributeError, KeyError):
logger.info('Could not reindex comment %s' % brain.getURL())

View File

@ -11,4 +11,44 @@
handler=".upgrades.update_registry" handler=".upgrades.update_registry"
/> />
<genericsetup:upgradeStep
title="edit comments and delete own comments"
description="reload registry config to enable new fields edit_comment_enabled and delete_own_comment_enabled"
source="100"
destination="101"
handler=".upgrades.update_registry"
sortkey="1"
profile="plone.app.discussion:default"
/>
<genericsetup:upgradeStep
title="delete comments and delete own comments"
description="reload rolemap config to enable new permissions 'Delete comments' and 'Delete own comments'"
source="101"
destination="102"
handler=".upgrades.update_rolemap"
sortkey="1"
profile="plone.app.discussion:default"
/>
<genericsetup:upgradeSteps
source="102"
destination="1000"
profile="plone.app.discussion:default">
<!-- Apply the update rolemap step again, to avoid missing it when
updating from plone.app.discussion 2.2.x. When originally
adding this step in the 2.3.x release, we should have made a
bigger metadata revision increase to leave some room for new
upgrade steps in 2.2.x. -->
<genericsetup:upgradeStep
title="delete comments and delete own comments"
description="reload rolemap config to enable new permissions 'Delete comments' and 'Delete own comments'"
handler=".upgrades.update_rolemap"
/>
<genericsetup:upgradeStep
title="Update plone.app.discussion workflows"
handler=".upgrades.upgrade_comment_workflows"
/>
</genericsetup:upgradeSteps>
</configure> </configure>