244 lines
9.7 KiB
Python
244 lines
9.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
from AccessControl.User import User # before SpecialUsers
|
|
from AccessControl.SpecialUsers import nobody as user_nobody
|
|
from AccessControl.PermissionRole import rolesForPermissionOn
|
|
from Acquisition import aq_chain, aq_base
|
|
from plone.app.discussion.testing import \
|
|
PLONE_APP_DISCUSSION_INTEGRATION_TESTING
|
|
from plone.app.discussion.interfaces import IConversation
|
|
from plone.app.testing import TEST_USER_ID, setRoles
|
|
from Products.CMFCore.utils import getToolByName
|
|
from zope.component import createObject
|
|
|
|
import unittest2 as unittest
|
|
|
|
|
|
dexterity_type_name = 'sample_content_type'
|
|
dexterity_object_id = 'instance-of-dexterity-type'
|
|
archetypes_object_id = 'instance-of-archetypes-type'
|
|
one_state_workflow = 'one_state_workflow'
|
|
comment_workflow_acquired_view = 'comment_workflow_acquired_view'
|
|
|
|
class AcquisitionTest(unittest.TestCase):
|
|
""" Define the expected behaviour of wrapped and unwrapped comments. """
|
|
|
|
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
|
|
|
|
def setUp(self):
|
|
self.portal = self.layer['portal']
|
|
self.request = self.layer['request']
|
|
setRoles(self.portal, TEST_USER_ID, ['Manager'])
|
|
self.wftool = getToolByName(self.portal, 'portal_workflow')
|
|
|
|
# Use customized workflow for comments.
|
|
self.wftool.setChainForPortalTypes(
|
|
['Discussion Item'],
|
|
(comment_workflow_acquired_view,),
|
|
)
|
|
|
|
# Use one_state_workflow for Document and sample_content_type,
|
|
# so they're always published.
|
|
self.wftool.setChainForPortalTypes(
|
|
['Document', dexterity_type_name],
|
|
(one_state_workflow,),
|
|
)
|
|
|
|
# Create a dexterity item and add a comment.
|
|
self.portal.invokeFactory(
|
|
id=dexterity_object_id,
|
|
title='Instance Of Dexterity Type',
|
|
type_name=dexterity_type_name,
|
|
)
|
|
|
|
self.dexterity_object = self.portal.get(dexterity_object_id)
|
|
dx_conversation = IConversation(self.dexterity_object)
|
|
self.dexterity_conversation = dx_conversation
|
|
dx_comment = createObject('plone.Comment')
|
|
dx_conversation.addComment(dx_comment)
|
|
self.unwrapped_dexterity_comment = dx_comment
|
|
self.wrapped_dexterity_comment = dx_conversation[dx_comment.id]
|
|
|
|
# Create an Archetypes item and add a comment.
|
|
self.portal.invokeFactory(
|
|
id=archetypes_object_id,
|
|
title='Instance Of Archetypes Type',
|
|
type_name='Document',
|
|
)
|
|
|
|
self.archetypes_object = self.portal.get(archetypes_object_id)
|
|
at_conversation = IConversation(self.archetypes_object)
|
|
self.archetypes_conversation = at_conversation
|
|
at_comment = createObject('plone.Comment')
|
|
at_conversation.addComment(at_comment)
|
|
self.unwrapped_archetypes_comment = at_comment
|
|
self.wrapped_archetypes_comment = at_conversation[at_comment.id]
|
|
|
|
|
|
def test_workflows_installed(self):
|
|
"""Check that the new comment workflow has been installed properly.
|
|
(Just a test to check our test setup.)
|
|
"""
|
|
workflows = self.wftool.objectIds()
|
|
self.assertTrue('comment_workflow_acquired_view' in workflows)
|
|
|
|
def test_workflows_applied(self):
|
|
"""Check that all objects have the workflow that we expect.
|
|
(Just a test to check our test setup.)"""
|
|
self.assertEqual(
|
|
self.wftool.getChainFor(self.archetypes_object),
|
|
(one_state_workflow,)
|
|
)
|
|
self.assertEqual(
|
|
self.wftool.getChainFor(self.dexterity_object),
|
|
(one_state_workflow,)
|
|
)
|
|
self.assertEqual(
|
|
self.wftool.getChainFor(self.unwrapped_archetypes_comment),
|
|
(comment_workflow_acquired_view,)
|
|
)
|
|
self.assertEqual(
|
|
self.wftool.getChainFor(self.unwrapped_dexterity_comment),
|
|
(comment_workflow_acquired_view,)
|
|
)
|
|
|
|
def test_comment_acquisition_chain(self):
|
|
""" Test that the acquisition chains for wrapped and unwrapped
|
|
comments are as expected. """
|
|
|
|
# Unwrapped comments rely on __parent__ attributes to determine
|
|
# parentage. Frustratingly there is no guarantee that __parent__
|
|
# is always set, so the computed acquisition chain may be short.
|
|
# In this case the unwrapped AT and DX objects stored as the
|
|
# conversation parents don't have a __parent__, preventing the portal
|
|
# from being included in the chain.
|
|
self.assertNotIn(self.portal,
|
|
aq_chain(self.unwrapped_archetypes_comment))
|
|
self.assertNotIn(self.portal,
|
|
aq_chain(self.unwrapped_dexterity_comment))
|
|
|
|
# Wrapped comments however have a complete chain and thus can find the
|
|
# portal object reliably.
|
|
self.assertIn(self.portal,aq_chain(self.wrapped_archetypes_comment))
|
|
self.assertIn(self.portal,aq_chain(self.wrapped_dexterity_comment))
|
|
|
|
|
|
def test_acquiring_comment_permissions(self):
|
|
""" Unwrapped comments should not be able to acquire permissions
|
|
controlled by unreachable objects """
|
|
|
|
# We use the "Allow sendto" permission as by default it is
|
|
# controlled by the portal, which is unreachable via __parent__
|
|
# attributes on the comments.
|
|
permission = "Allow sendto"
|
|
|
|
# Unwrapped comments can't find the portal so just return manager
|
|
self.assertNotIn("Anonymous",
|
|
rolesForPermissionOn(permission,
|
|
self.unwrapped_archetypes_comment))
|
|
self.assertNotIn("Anonymous",
|
|
rolesForPermissionOn(permission,
|
|
self.unwrapped_dexterity_comment))
|
|
|
|
# Wrapped objects can find the portal and correctly return the
|
|
# anonymous role.
|
|
self.assertIn("Anonymous",
|
|
rolesForPermissionOn(permission,
|
|
self.wrapped_archetypes_comment))
|
|
self.assertIn("Anonymous",
|
|
rolesForPermissionOn(permission,
|
|
self.wrapped_dexterity_comment))
|
|
|
|
def test_acquiring_comment_permissions_via_user_nobody(self):
|
|
""" The current implementation uses user_nobody.has_permission to
|
|
check whether anonymous can view comments. This confirms it also
|
|
works. """
|
|
|
|
# Again we want to use a permission that's not managed by any of our
|
|
# content objects so it must be acquired from the portal.
|
|
permission = "Allow sendto"
|
|
|
|
self.assertFalse(
|
|
user_nobody.has_permission(permission,
|
|
self.unwrapped_archetypes_comment))
|
|
|
|
self.assertFalse(
|
|
user_nobody.has_permission(permission,
|
|
self.unwrapped_dexterity_comment))
|
|
|
|
self.assertTrue(
|
|
user_nobody.has_permission(permission,
|
|
self.wrapped_archetypes_comment))
|
|
|
|
self.assertTrue(
|
|
user_nobody.has_permission(permission,
|
|
self.wrapped_dexterity_comment))
|
|
|
|
class AcquiredPermissionTest(unittest.TestCase):
|
|
""" Test methods of a conversation which rely on acquired permissions """
|
|
|
|
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
|
|
|
|
def setUp(self):
|
|
self.portal = self.layer['portal']
|
|
self.request = self.layer['request']
|
|
setRoles(self.portal, TEST_USER_ID, ['Manager'])
|
|
self.wftool = getToolByName(self.portal, 'portal_workflow')
|
|
|
|
# Disable workflow for comments and content.
|
|
self.wftool.setChainForPortalTypes(["Discussion Item"],[])
|
|
self.wftool.setChainForPortalTypes([dexterity_type_name],[])
|
|
|
|
# Create a dexterity item.
|
|
self.portal.invokeFactory(
|
|
id=dexterity_object_id,
|
|
title='Instance Of Dexterity Type',
|
|
type_name=dexterity_type_name,
|
|
)
|
|
|
|
self.content = self.portal.get(dexterity_object_id)
|
|
|
|
# Absolutely make sure that we're replicating the case of an
|
|
# incomplete chain correctly.
|
|
aq_base(self.content).__parent__ = None
|
|
|
|
self.conversation = IConversation(self.content)
|
|
|
|
# Add a comment
|
|
comment = createObject('plone.Comment')
|
|
self.conversation.addComment(comment)
|
|
self.comment = comment
|
|
|
|
def test_view_permission_is_only_available_on_portal(self):
|
|
""" Check that the test setup is correct """
|
|
|
|
content_roles = rolesForPermissionOn("View",aq_base(self.content))
|
|
self.assertNotIn("Anonymous",content_roles)
|
|
|
|
comment_roles = rolesForPermissionOn("View",aq_base(self.comment))
|
|
self.assertNotIn("Anonymous",comment_roles)
|
|
|
|
# This actually acquires view from the app root, but we don't really
|
|
# care, we just need to confirm that something above our content
|
|
# object will give us View.
|
|
portal_roles = rolesForPermissionOn("View",self.portal)
|
|
self.assertIn("Anonymous",portal_roles)
|
|
|
|
# The following tests fail when the conversation uses unwrapped comment
|
|
# objects to determine whether an anonymous user has the view permission.
|
|
|
|
def test_total_comments(self):
|
|
self.assertEqual(self.conversation.total_comments,1)
|
|
|
|
def test_last_comment_date(self):
|
|
self.assertEqual(self.conversation.last_comment_date,
|
|
self.comment.creation_date)
|
|
|
|
def test_public_commentators(self):
|
|
self.assertEqual(self.conversation.public_commentators,
|
|
(self.comment.author_username,))
|
|
|
|
|
|
|
|
def test_suite():
|
|
return unittest.defaultTestLoader.loadTestsFromName(__name__)
|