Merge pull request #195 from plone/plone-base-overhaul

Plone base overhaul
This commit is contained in:
Jens W. Klein
2022-05-03 15:10:38 +02:00
committed by GitHub
46 changed files with 2374 additions and 2395 deletions
@@ -252,7 +252,7 @@ Now we can post an anonymous comment.
>>> unprivileged_browser.open(urldoc)
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "This is an anonymous comment"
>>> unprivileged_browser.getControl(name='form.widgets.author_name').value = u'John'
>>> unprivileged_browser.getControl(name='form.widgets.author_name').value = 'John'
>>> unprivileged_browser.getControl(name='form.widgets.author_email').value = 'john@acme.com'
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
+156 -163
View File
@@ -1,9 +1,10 @@
# -*- coding: utf-8 -*-
"""Test the plone.app.discussion catalog indexes
"""
from datetime import datetime
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from plone.app.discussion.testing import ( # noqa
PLONE_APP_DISCUSSION_INTEGRATION_TESTING,
)
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from Products.CMFCore.utils import getToolByName
@@ -21,33 +22,29 @@ class CatalogSetupTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
self.portal = self.layer["portal"]
def test_catalog_installed(self):
self.assertTrue(
'total_comments' in
self.portal.portal_catalog.indexes(),
"total_comments" in self.portal.portal_catalog.indexes(),
)
self.assertTrue(
'commentators' in
self.portal.portal_catalog.indexes(),
"commentators" in self.portal.portal_catalog.indexes(),
)
self.assertTrue(
'total_comments' in
self.portal.portal_catalog.schema(),
"total_comments" in self.portal.portal_catalog.schema(),
)
self.assertTrue(
'in_response_to' in
self.portal.portal_catalog.schema(),
"in_response_to" in self.portal.portal_catalog.schema(),
)
def test_collection_criteria_installed(self):
if 'portal_atct' not in self.portal:
if "portal_atct" not in self.portal:
return
try:
self.portal.portal_atct.getIndex('commentators')
self.portal.portal_atct.getIndex('total_comments')
self.portal.portal_atct.getMetadata('total_comments')
self.portal.portal_atct.getIndex("commentators")
self.portal.portal_atct.getIndex("total_comments")
self.portal.portal_atct.getMetadata("total_comments")
except AttributeError:
self.fail()
@@ -57,19 +54,19 @@ class ConversationCatalogTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
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)
comment1 = createObject('plone.Comment')
comment1.title = 'Comment 1'
comment1.text = 'Comment text'
comment1.creator = 'jim'
comment1.author_username = 'Jim'
comment1 = createObject("plone.Comment")
comment1.title = "Comment 1"
comment1.text = "Comment text"
comment1.creator = "jim"
comment1.author_username = "Jim"
comment1.creation_date = datetime(2006, 9, 17, 14, 18, 12)
comment1.modification_date = datetime(2006, 9, 17, 14, 18, 12)
@@ -79,9 +76,9 @@ class ConversationCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
self.conversation = conversation
@@ -91,54 +88,54 @@ class ConversationCatalogTest(unittest.TestCase):
self.new_comment1_id = new_comment1_id
def test_total_comments(self):
self.assertTrue('total_comments' in self.doc1_brain)
self.assertTrue("total_comments" in self.doc1_brain)
self.assertEqual(self.doc1_brain.total_comments, 1)
comment2 = createObject('plone.Comment')
comment2.title = 'Comment 2'
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.title = "Comment 2"
comment2.text = "Comment text"
new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment2_id),
f"++conversation++default/{new_comment2_id}",
)
comment2.reindexObject()
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
self.assertEqual(doc1_brain.total_comments, 2)
def test_last_comment_date(self):
self.assertTrue('last_comment_date' in self.doc1_brain)
self.assertTrue("last_comment_date" in self.doc1_brain)
self.assertEqual(
self.doc1_brain.last_comment_date,
datetime(2006, 9, 17, 14, 18, 12),
)
# Add another comment and check if last comment date is updated.
comment2 = createObject('plone.Comment')
comment2.title = 'Comment 2'
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.title = "Comment 2"
comment2.text = "Comment text"
comment2.creation_date = datetime(2009, 9, 17, 14, 18, 12)
comment2.modification_date = datetime(2009, 9, 17, 14, 18, 12)
new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment2_id),
f"++conversation++default/{new_comment2_id}",
)
comment2.reindexObject()
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
@@ -153,9 +150,9 @@ class ConversationCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
@@ -169,44 +166,44 @@ class ConversationCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
self.assertEqual(doc1_brain.last_comment_date, None)
def test_commentators(self):
self.assertTrue('commentators' in self.doc1_brain)
self.assertEqual(self.doc1_brain.commentators, ('Jim',))
self.assertTrue("commentators" in self.doc1_brain)
self.assertEqual(self.doc1_brain.commentators, ("Jim",))
# add another comment with another author
comment2 = createObject('plone.Comment')
comment2.title = 'Comment 2'
comment2.text = 'Comment text'
comment2.creator = 'emma'
comment2.author_username = 'Emma'
comment2 = createObject("plone.Comment")
comment2.title = "Comment 2"
comment2.text = "Comment text"
comment2.creator = "emma"
comment2.author_username = "Emma"
new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment2_id),
f"++conversation++default/{new_comment2_id}",
)
comment2.reindexObject()
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
self.assertEqual(
sorted(doc1_brain.commentators),
sorted(('Jim', 'Emma')),
sorted(("Jim", "Emma")),
)
# remove one comments
@@ -214,22 +211,22 @@ class ConversationCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
self.assertEqual(doc1_brain.commentators, ('Jim',))
self.assertEqual(doc1_brain.commentators, ("Jim",))
# remove all comments
del self.conversation[self.new_comment1_id]
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
@@ -239,9 +236,9 @@ class ConversationCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Discussion Item',
portal_type="Discussion Item",
),
)
comment1_brain = brains[0]
@@ -250,14 +247,14 @@ class ConversationCatalogTest(unittest.TestCase):
self.assertEqual(comment1_brain.total_comments, None)
def test_dont_index_private_commentators(self):
self.comment1.manage_permission('View', roles=tuple())
self.comment1.manage_permission("View", roles=tuple())
self.portal.doc1.reindexObject()
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
doc1_brain = brains[0]
@@ -269,70 +266,70 @@ class CommentCatalogTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.catalog = getToolByName(self.portal, 'portal_catalog')
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.catalog = getToolByName(self.portal, "portal_catalog")
conversation = IConversation(self.portal.doc1)
self.conversation = conversation
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1.creator = 'jim'
comment1.author_name = 'Jim'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
comment1.creator = "jim"
comment1.author_name = "Jim"
new_comment1_id = conversation.addComment(comment1)
self.comment_id = new_comment1_id
# Comment brain
self.comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id),
f"++conversation++default/{new_comment1_id}",
)
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.comment.getPhysicalPath()),
"query": "/".join(self.comment.getPhysicalPath()),
},
),
)
self.comment_brain = brains[0]
def test_title(self):
self.assertEqual(self.comment_brain.Title, 'Jim on Document 1')
self.assertEqual(self.comment_brain.Title, "Jim on Document 1")
def test_no_name_title(self):
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
cid = self.conversation.addComment(comment)
# Comment brain
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(cid),
f"++conversation++default/{cid}",
)
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(comment.getPhysicalPath()),
"query": "/".join(comment.getPhysicalPath()),
},
),
)
comment_brain = brains[0]
self.assertEqual(comment_brain.Title, 'Anonymous on Document 1')
self.assertEqual(comment_brain.Title, "Anonymous on Document 1")
def test_type(self):
self.assertEqual(self.comment_brain.portal_type, 'Discussion Item')
self.assertEqual(self.comment_brain.Type, 'Comment')
self.assertEqual(self.comment_brain.portal_type, "Discussion Item")
self.assertEqual(self.comment_brain.Type, "Comment")
def test_review_state(self):
self.assertEqual(self.comment_brain.review_state, 'published')
self.assertEqual(self.comment_brain.review_state, "published")
def test_creator(self):
self.assertEqual(self.comment_brain.Creator, 'jim')
self.assertEqual(self.comment_brain.Creator, "jim")
def test_in_response_to(self):
"""Make sure in_response_to returns the title or id of the content
object the comment was added to.
object the comment was added to.
"""
self.assertEqual(self.comment_brain.in_response_to, 'Document 1')
self.assertEqual(self.comment_brain.in_response_to, "Document 1")
def test_add_comment(self):
self.assertTrue(self.comment_brain)
@@ -344,7 +341,7 @@ class CommentCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.comment.getPhysicalPath()),
"query": "/".join(self.comment.getPhysicalPath()),
},
),
)
@@ -352,54 +349,54 @@ class CommentCatalogTest(unittest.TestCase):
def test_reindex_comment(self):
# Make sure a comment is reindexed on the catalog when is modified
self.comment.text = 'Another text'
self.comment.text = "Another text"
notify(ObjectModifiedEvent(self.comment))
brains = self.catalog.searchResults(SearchableText='Another text')
brains = self.catalog.searchResults(SearchableText="Another text")
self.assertEqual(len(brains), 1)
def test_remove_comments_when_content_object_is_removed(self):
"""Make sure all comments are removed from the catalog, if the content
object is removed.
object is removed.
"""
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
brains = self.catalog.searchResults({"portal_type": "Discussion Item"})
self.assertEqual(len(brains), 1)
self.portal.manage_delObjects(['doc1'])
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
self.portal.manage_delObjects(["doc1"])
brains = self.catalog.searchResults({"portal_type": "Discussion Item"})
self.assertEqual(len(brains), 0)
def test_move_comments_when_content_object_is_moved(self):
# Create two folders and a content object with a comment
self.portal.invokeFactory(
id='folder1',
title='Folder 1',
type_name='Folder',
id="folder1",
title="Folder 1",
type_name="Folder",
)
self.portal.invokeFactory(
id='folder2',
title='Folder 2',
type_name='Folder',
id="folder2",
title="Folder 2",
type_name="Folder",
)
self.portal.folder1.invokeFactory(
id='moveme',
title='Move Me',
type_name='Document',
id="moveme",
title="Move Me",
type_name="Document",
)
conversation = IConversation(self.portal.folder1.moveme)
comment = createObject('plone.Comment')
comment = createObject("plone.Comment")
comment_id = conversation.addComment(comment)
# We need to commit here so that _p_jar isn't None and move will work
transaction.savepoint(optimistic=True)
# Move moveme from folder1 to folder2
cp = self.portal.folder1.manage_cutObjects(ids=('moveme',))
cp = self.portal.folder1.manage_cutObjects(ids=("moveme",))
self.portal.folder2.manage_pasteObjects(cp)
# Make sure no old comment brains are
brains = self.catalog.searchResults(
dict(
portal_type='Discussion Item',
portal_type="Discussion Item",
path={
'query': '/'.join(self.portal.folder1.getPhysicalPath()),
"query": "/".join(self.portal.folder1.getPhysicalPath()),
},
),
)
@@ -407,61 +404,60 @@ class CommentCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults(
dict(
portal_type='Discussion Item',
portal_type="Discussion Item",
path={
'query': '/'.join(self.portal.folder2.getPhysicalPath()),
"query": "/".join(self.portal.folder2.getPhysicalPath()),
},
),
)
self.assertEqual(len(brains), 1)
self.assertEqual(
brains[0].getPath(),
'/plone/folder2/moveme/++conversation++default/' +
str(comment_id),
"/plone/folder2/moveme/++conversation++default/" + str(comment_id),
)
def test_move_upper_level_folder(self):
# create a folder with a nested structure
self.portal.invokeFactory(
id='sourcefolder',
title='Source Folder',
type_name='Folder',
id="sourcefolder",
title="Source Folder",
type_name="Folder",
)
self.portal.sourcefolder.invokeFactory(
id='moveme',
title='Move Me',
type_name='Folder',
id="moveme",
title="Move Me",
type_name="Folder",
)
self.portal.sourcefolder.moveme.invokeFactory(
id='mydocument',
title='My Document',
type_name='Folder',
id="mydocument",
title="My Document",
type_name="Folder",
)
self.portal.invokeFactory(
id='targetfolder',
title='Target Folder',
type_name='Folder',
id="targetfolder",
title="Target Folder",
type_name="Folder",
)
# create comment on my-document
conversation = IConversation(
self.portal.sourcefolder.moveme.mydocument,
)
comment = createObject('plone.Comment')
comment = createObject("plone.Comment")
comment_id = conversation.addComment(comment)
# We need to commit here so that _p_jar isn't None and move will work
transaction.savepoint(optimistic=True)
# Move moveme from folder1 to folder2
cp = self.portal.sourcefolder.manage_cutObjects(ids=('moveme',))
cp = self.portal.sourcefolder.manage_cutObjects(ids=("moveme",))
self.portal.targetfolder.manage_pasteObjects(cp)
# Make sure no old comment brains are left
brains = self.catalog.searchResults(
dict(
portal_type='Discussion Item',
path={'query': '/plone/sourcefolder/moveme'},
portal_type="Discussion Item",
path={"query": "/plone/sourcefolder/moveme"},
),
)
self.assertEqual(len(brains), 0)
@@ -469,49 +465,47 @@ class CommentCatalogTest(unittest.TestCase):
# make sure comments are correctly index on the target
brains = self.catalog.searchResults(
dict(
portal_type='Discussion Item',
path={'query': '/plone/targetfolder/moveme'},
portal_type="Discussion Item",
path={"query": "/plone/targetfolder/moveme"},
),
)
self.assertEqual(len(brains), 1)
self.assertEqual(
brains[0].getPath(),
'/plone/targetfolder/moveme/mydocument/++conversation++default/' +
str(comment_id),
"/plone/targetfolder/moveme/mydocument/++conversation++default/"
+ str(comment_id),
)
def test_update_comments_when_content_object_is_renamed(self):
# We need to commit here so that _p_jar isn't None and move will work
transaction.savepoint(optimistic=True)
self.portal.manage_renameObject('doc1', 'doc2')
self.portal.manage_renameObject("doc1", "doc2")
brains = self.catalog.searchResults(
portal_type='Discussion Item',
portal_type="Discussion Item",
)
self.assertEqual(len(brains), 1)
self.assertEqual(
brains[0].getPath(),
'/plone/doc2/++conversation++default/' +
str(self.comment_id),
"/plone/doc2/++conversation++default/" + str(self.comment_id),
)
def test_clear_and_rebuild_catalog(self):
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
brains = self.catalog.searchResults({"portal_type": "Discussion Item"})
self.assertTrue(brains)
# Clear and rebuild catalog
self.catalog.clearFindAndRebuild()
# Check if comment is still there
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
brains = self.catalog.searchResults({"portal_type": "Discussion Item"})
self.assertTrue(brains)
comment_brain = brains[0]
self.assertEqual(comment_brain.Title, u'Jim on Document 1')
self.assertEqual(comment_brain.Title, "Jim on Document 1")
self.assertEqual(
comment_brain.getPath(),
'/plone/doc1/++conversation++default/' +
str(self.comment_id),
"/plone/doc1/++conversation++default/" + str(self.comment_id),
)
def test_clear_and_rebuild_catalog_for_nested_comments(self):
@@ -526,25 +520,25 @@ class CommentCatalogTest(unittest.TestCase):
# +- Comment 2
# +- Comment 2_1
comment1_1 = createObject('plone.Comment')
comment1_1.title = 'Re: Comment 1'
comment1_1.text = 'Comment text'
comment1_1 = createObject("plone.Comment")
comment1_1.title = "Re: Comment 1"
comment1_1.text = "Comment text"
comment1_1_1 = createObject('plone.Comment')
comment1_1_1.title = 'Re: Re: Comment 1'
comment1_1_1.text = 'Comment text'
comment1_1_1 = createObject("plone.Comment")
comment1_1_1.title = "Re: Re: Comment 1"
comment1_1_1.text = "Comment text"
comment1_2 = createObject('plone.Comment')
comment1_2.title = 'Re: Comment 1 (2)'
comment1_2.text = 'Comment text'
comment1_2 = createObject("plone.Comment")
comment1_2.title = "Re: Comment 1 (2)"
comment1_2.text = "Comment text"
comment2 = createObject('plone.Comment')
comment2.title = 'Comment 2'
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.title = "Comment 2"
comment2.text = "Comment text"
comment2_1 = createObject('plone.Comment')
comment2_1.title = 'Re: Comment 2'
comment2_1.text = 'Comment text'
comment2_1 = createObject("plone.Comment")
comment2_1.title = "Re: Comment 2"
comment2_1.text = "Comment text"
# Create the nested comment structure
new_id_1 = self.conversation.addComment(self.comment)
@@ -566,7 +560,7 @@ class CommentCatalogTest(unittest.TestCase):
self.catalog.clearFindAndRebuild()
# Check if comments are still there
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
brains = self.catalog.searchResults({"portal_type": "Discussion Item"})
self.assertTrue(brains)
self.assertEqual(len(brains), 6)
@@ -576,19 +570,19 @@ class NoConversationCatalogTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.catalog = getToolByName(self.portal, 'portal_catalog')
self.catalog = getToolByName(self.portal, "portal_catalog")
conversation = IConversation(self.portal.doc1)
brains = self.catalog.searchResults(
dict(
path={
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
"query": "/".join(self.portal.doc1.getPhysicalPath()),
},
portal_type='Document',
portal_type="Document",
),
)
self.conversation = conversation
@@ -596,11 +590,10 @@ class NoConversationCatalogTest(unittest.TestCase):
self.doc1_brain = brains[0]
def test_total_comments(self):
self.assertTrue('total_comments' in self.doc1_brain)
self.assertTrue("total_comments" in self.doc1_brain)
self.assertEqual(self.doc1_brain.total_comments, 0)
# Make sure no conversation has been created
self.assertTrue(
'plone.app.discussion:conversation' not in
IAnnotations(self.portal.doc1),
"plone.app.discussion:conversation" not in IAnnotations(self.portal.doc1),
)
+160 -165
View File
@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.browser.comment import View
from plone.app.discussion.interfaces import IComment
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IReplies
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from Products.CMFCore.utils import getToolByName
@@ -12,11 +11,10 @@ from zope.component import getMultiAdapter
import datetime
import logging
import six
import unittest
logger = logging.getLogger('plone.app.discussion.tests')
logger = logging.getLogger("plone.app.discussion.tests")
logger.addHandler(logging.StreamHandler())
@@ -25,30 +23,30 @@ class CommentTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
self.request = self.layer['request']
self.portal = self.layer["portal"]
self.request = self.layer["request"]
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
workflow.doActionFor(self.portal.doc1, "publish")
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.catalog = getToolByName(self.portal, 'portal_catalog')
self.document_brain = self.catalog.searchResults(
portal_type='Document')[0]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.catalog = getToolByName(self.portal, "portal_catalog")
self.document_brain = self.catalog.searchResults(portal_type="Document")[0]
def test_factory(self):
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
self.assertTrue(IComment.providedBy(comment1))
def test_UTCDates(self):
utc_to_local_diff = \
datetime.datetime.now() - datetime.datetime.utcnow()
utc_to_local_diff = datetime.datetime.now() - datetime.datetime.utcnow()
utc_to_local_diff = abs(utc_to_local_diff.seconds)
if utc_to_local_diff < 60:
logger.warning('Your computer is living in a timezone where local '
'time equals utc time. Some potential errors can '
'get hidden by that')
comment1 = createObject('plone.Comment')
logger.warning(
"Your computer is living in a timezone where local "
"time equals utc time. Some potential errors can "
"get hidden by that"
)
comment1 = createObject("plone.Comment")
local_utc = datetime.datetime.utcnow()
for date in (comment1.creation_date, comment1.modification_date):
difference = abs(date - local_utc)
@@ -58,171 +56,163 @@ class CommentTest(unittest.TestCase):
self.assertFalse(difference // 10)
def test_id(self):
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
comment1.comment_id = 123
self.assertEqual('123', comment1.id)
self.assertEqual('123', comment1.getId())
self.assertEqual(u'123', comment1.__name__)
self.assertEqual("123", comment1.id)
self.assertEqual("123", comment1.getId())
self.assertEqual("123", comment1.__name__)
def test_uid(self):
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
conversation.addComment(comment1)
comment_brain = self.catalog.searchResults(
portal_type='Discussion Item',
portal_type="Discussion Item",
)[0]
self.assertTrue(comment_brain.UID)
def test_uid_is_unique(self):
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
conversation.addComment(comment1)
comment2 = createObject('plone.Comment')
comment2 = createObject("plone.Comment")
conversation.addComment(comment2)
brains = self.catalog.searchResults(
portal_type='Discussion Item',
portal_type="Discussion Item",
)
self.assertNotEqual(brains[0].UID, brains[1].UID)
def test_comment_uid_differs_from_content_uid(self):
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
conversation.addComment(comment1)
comment_brain = self.catalog.searchResults(
portal_type='Discussion Item',
portal_type="Discussion Item",
)[0]
self.assertNotEqual(self.document_brain.UID, comment_brain.UID)
def test_title(self):
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1.author_name = 'Jim Fulton'
comment1 = createObject("plone.Comment")
comment1.author_name = "Jim Fulton"
conversation.addComment(comment1)
self.assertEqual('Jim Fulton on Document 1', comment1.Title())
self.assertEqual("Jim Fulton on Document 1", comment1.Title())
def test_no_name_title(self):
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
conversation.addComment(comment1)
self.assertEqual('Anonymous on Document 1', comment1.Title())
self.assertEqual("Anonymous on Document 1", comment1.Title())
def test_title_special_characters(self):
self.portal.invokeFactory(
id='doc_sp_chars',
title=u'Document äüö',
type_name='Document',
id="doc_sp_chars",
title="Document äüö",
type_name="Document",
)
conversation = IConversation(self.portal.doc_sp_chars)
comment1 = createObject('plone.Comment')
comment1.author_name = u'Tarek Ziadé'
comment1 = createObject("plone.Comment")
comment1.author_name = "Tarek Ziadé"
conversation.addComment(comment1)
self.assertEqual(u'Tarek Ziadé on Document äüö', comment1.Title())
self.assertEqual("Tarek Ziadé on Document äüö", comment1.Title())
def test_title_special_characters_utf8(self):
self.portal.invokeFactory(
id='doc_sp_chars_utf8',
title='Document ëïû',
type_name='Document',
id="doc_sp_chars_utf8",
title="Document ëïû",
type_name="Document",
)
conversation = IConversation(self.portal.doc_sp_chars_utf8)
comment1 = createObject('plone.Comment')
comment1.author_name = 'Hüüb Bôûmä'
comment1 = createObject("plone.Comment")
comment1.author_name = "Hüüb Bôûmä"
conversation.addComment(comment1)
self.assertEqual(u'Hüüb Bôûmä on Document ëïû', comment1.Title())
self.assertEqual("Hüüb Bôûmä on Document ëïû", comment1.Title())
def test_creator(self):
comment1 = createObject('plone.Comment')
comment1.creator = 'jim'
self.assertEqual('jim', comment1.Creator())
comment1 = createObject("plone.Comment")
comment1.creator = "jim"
self.assertEqual("jim", comment1.Creator())
def test_creator_author_name(self):
comment1 = createObject('plone.Comment')
comment1.author_name = 'joey'
self.assertEqual('joey', comment1.Creator())
comment1 = createObject("plone.Comment")
comment1.author_name = "joey"
self.assertEqual("joey", comment1.Creator())
def test_owner(self):
comment1 = createObject('plone.Comment')
self.assertEqual((['plone', 'acl_users'], TEST_USER_ID),
comment1.getOwnerTuple())
comment1 = createObject("plone.Comment")
self.assertEqual(
(["plone", "acl_users"], TEST_USER_ID), comment1.getOwnerTuple()
)
def test_type(self):
comment1 = createObject('plone.Comment')
self.assertEqual(comment1.Type(), 'Comment')
comment1 = createObject("plone.Comment")
self.assertEqual(comment1.Type(), "Comment")
def test_mime_type(self):
comment1 = createObject('plone.Comment')
self.assertEqual(comment1.mime_type, 'text/plain')
comment1 = createObject("plone.Comment")
self.assertEqual(comment1.mime_type, "text/plain")
def test_getText(self):
comment1 = createObject('plone.Comment')
comment1.text = 'First paragraph\n\nSecond_paragraph'
comment1 = createObject("plone.Comment")
comment1.text = "First paragraph\n\nSecond_paragraph"
self.assertEqual(
''.join(comment1.getText().split()),
'<p>Firstparagraph<br><br>Second_paragraph</p>',
"".join(comment1.getText().split()),
"<p>Firstparagraph<br><br>Second_paragraph</p>",
)
def test_getText_escapes_HTML(self):
comment1 = createObject('plone.Comment')
comment1.text = '<b>Got HTML?</b>'
comment1 = createObject("plone.Comment")
comment1.text = "<b>Got HTML?</b>"
self.assertEqual(
comment1.getText(),
'<p>&lt;b&gt;Got HTML?&lt;/b&gt;</p>',
"<p>&lt;b&gt;Got HTML?&lt;/b&gt;</p>",
)
def test_getText_with_non_ascii_characters(self):
comment1 = createObject('plone.Comment')
comment1.text = u'Umlaute sind ä, ö und ü.'
out = b'<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>'
if six.PY2:
self.assertEqual(
comment1.getText(),
out)
else:
self.assertEqual(
comment1.getText(),
out.decode('utf8'))
comment1 = createObject("plone.Comment")
comment1.text = "Umlaute sind ä, ö und ü."
out = b"<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>"
self.assertEqual(comment1.getText(), out.decode("utf8"))
def test_getText_doesnt_link(self):
comment1 = createObject('plone.Comment')
comment1.text = 'Go to http://www.plone.org'
comment1 = createObject("plone.Comment")
comment1.text = "Go to http://www.plone.org"
self.assertEqual(
comment1.getText(),
'<p>Go to http://www.plone.org</p>',
"<p>Go to http://www.plone.org</p>",
)
def test_getText_uses_comment_mime_type(self):
comment1 = createObject('plone.Comment')
comment1.text = 'Go to http://www.plone.org'
comment1.mime_type = 'text/x-web-intelligent'
comment1 = createObject("plone.Comment")
comment1.text = "Go to http://www.plone.org"
comment1.mime_type = "text/x-web-intelligent"
self.assertEqual(
comment1.getText(),
'Go to <a href="http://www.plone.org" ' +
'rel="nofollow">http://www.plone.org</a>',
'Go to <a href="http://www.plone.org" '
+ 'rel="nofollow">http://www.plone.org</a>',
)
def test_getText_uses_comment_mime_type_html(self):
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
comment1.text = 'Go to <a href="http://www.plone.org">plone.org</a>'
comment1.mime_type = 'text/html'
comment1.mime_type = "text/html"
self.assertEqual(
comment1.getText(),
'Go to <a href="http://www.plone.org">plone.org</a>',
)
def test_getText_w_custom_targetMimetype(self):
comment1 = createObject('plone.Comment')
comment1.text = 'para'
self.assertEqual(comment1.getText(targetMimetype='text/plain'), 'para')
comment1 = createObject("plone.Comment")
comment1.text = "para"
self.assertEqual(comment1.getText(targetMimetype="text/plain"), "para")
def test_getText_invalid_transformation_raises_error(self):
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1.mime_type = 'text/x-html-safe'
comment1.text = 'para'
comment1 = createObject("plone.Comment")
comment1.mime_type = "text/x-html-safe"
comment1.text = "para"
conversation.addComment(comment1)
self.assertEqual(
comment1.getText(targetMimetype='text/html'),
'para')
self.assertEqual(comment1.getText(targetMimetype="text/html"), "para")
def test_traversal(self):
# make sure comments are traversable, have an id, absolute_url and
@@ -230,26 +220,29 @@ class CommentTest(unittest.TestCase):
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
new_comment1_id = conversation.addComment(comment1)
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id),
f"++conversation++default/{new_comment1_id}",
)
self.assertTrue(IComment.providedBy(comment))
self.assertEqual(
(
'', 'plone', 'doc1', '++conversation++default',
"",
"plone",
"doc1",
"++conversation++default",
str(new_comment1_id),
),
comment.getPhysicalPath(),
)
self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' +
str(new_comment1_id), comment.absolute_url(),
"http://nohost/plone/doc1/++conversation++default/" + str(new_comment1_id),
comment.absolute_url(),
)
def test_view_blob_types(self):
@@ -258,68 +251,67 @@ class CommentTest(unittest.TestCase):
version of the url with a /view in it.
"""
self.portal.invokeFactory(
id='image1',
title='Image',
type_name='Image',
id="image1",
title="Image",
type_name="Image",
)
conversation = IConversation(self.portal.image1)
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
new_comment1_id = conversation.addComment(comment1)
comment = self.portal.image1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id),
f"++conversation++default/{new_comment1_id}",
)
view = View(comment, self.request)
View.__call__(view)
response = self.request.response
self.assertIn('/view', response.headers['location'])
self.assertIn("/view", response.headers["location"])
def test_workflow(self):
"""Basic test for the 'comment_review_workflow'
"""
"""Basic test for the 'comment_review_workflow'"""
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
('comment_review_workflow,'),
("Discussion Item",),
("comment_review_workflow,"),
)
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
new_comment1_id = conversation.addComment(comment1)
comment = conversation[new_comment1_id]
# Make sure comments use the 'comment_review_workflow'
chain = self.portal.portal_workflow.getChainFor(comment)
self.assertEqual(('comment_review_workflow',), chain)
self.assertEqual(("comment_review_workflow",), chain)
# Ensure the initial state was entered and recorded
self.assertEqual(
1,
len(comment.workflow_history['comment_review_workflow']),
len(comment.workflow_history["comment_review_workflow"]),
)
self.assertEqual(
None,
comment.workflow_history['comment_review_workflow'][0]['action'],
comment.workflow_history["comment_review_workflow"][0]["action"],
)
self.assertEqual(
'pending',
self.portal.portal_workflow.getInfoFor(comment, 'review_state'),
"pending",
self.portal.portal_workflow.getInfoFor(comment, "review_state"),
)
def test_fti(self):
# test that we can look up an FTI for Discussion Item
self.assertIn(
'Discussion Item',
"Discussion Item",
self.portal.portal_types.objectIds(),
)
comment1 = createObject('plone.Comment')
comment1 = createObject("plone.Comment")
fti = self.portal.portal_types.getTypeInfo(comment1)
self.assertEqual('Discussion Item', fti.getTypeInfo(comment1).getId())
self.assertEqual("Discussion Item", fti.getTypeInfo(comment1).getId())
def test_view(self):
# make sure that the comment view is there and redirects to the right
@@ -330,21 +322,21 @@ class CommentTest(unittest.TestCase):
conversation = IConversation(self.portal.doc1)
# Create a comment
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
# Add comment to the conversation
new_comment1_id = conversation.addComment(comment1)
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id),
f"++conversation++default/{new_comment1_id}",
)
# make sure the view is there
self.assertTrue(
getMultiAdapter(
(comment, self.request),
name='view',
name="view",
),
)
@@ -362,11 +354,11 @@ class RepliesTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
workflow.doActionFor(self.portal.doc1, "publish")
def test_add_comment(self):
# Add comments to a CommentReplies adapter
@@ -378,16 +370,16 @@ class RepliesTest(unittest.TestCase):
# Add a comment to the conversation
replies = IReplies(conversation)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id),
f"++conversation++default/{new_id}",
)
# Add a reply to the CommentReplies adapter of the first comment
re_comment = createObject('plone.Comment')
re_comment.text = 'Comment text'
re_comment = createObject("plone.Comment")
re_comment.text = "Comment text"
replies = IReplies(comment)
@@ -415,16 +407,16 @@ class RepliesTest(unittest.TestCase):
# Add a comment to the conversation
replies = IReplies(conversation)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id),
f"++conversation++default/{new_id}",
)
# Add a reply to the CommentReplies adapter of the first comment
re_comment = createObject('plone.Comment')
re_comment.text = 'Comment text'
re_comment = createObject("plone.Comment")
re_comment.text = "Comment text"
replies = IReplies(comment)
@@ -446,83 +438,86 @@ class RepliesTest(unittest.TestCase):
# physical path
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
conversation.addComment(comment1)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = conversation.addComment(comment)
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id),
f"++conversation++default/{new_id}",
)
# Add a reply to the CommentReplies adapter of the first comment
re_comment = createObject('plone.Comment')
re_comment.text = 'Comment text'
re_comment = createObject("plone.Comment")
re_comment.text = "Comment text"
replies = IReplies(comment)
new_re_id = replies.addComment(re_comment)
re_comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_re_id),
f"++conversation++default/{new_re_id}",
)
# Add a reply to the reply
re_re_comment = createObject('plone.Comment')
re_re_comment.text = 'Comment text'
re_re_comment = createObject("plone.Comment")
re_re_comment.text = "Comment text"
replies = IReplies(re_comment)
new_re_re_id = replies.addComment(re_re_comment)
re_re_comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_re_re_id),
f"++conversation++default/{new_re_re_id}",
)
# Add a reply to the replies reply
re_re_re_comment = createObject('plone.Comment')
re_re_re_comment.text = 'Comment text'
re_re_re_comment = createObject("plone.Comment")
re_re_re_comment.text = "Comment text"
replies = IReplies(re_re_comment)
new_re_re_re_id = replies.addComment(re_re_re_comment)
re_re_re_comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_re_re_re_id),
f"++conversation++default/{new_re_re_re_id}",
)
self.assertEqual(
('', 'plone', 'doc1', '++conversation++default', str(new_id)),
("", "plone", "doc1", "++conversation++default", str(new_id)),
comment.getPhysicalPath(),
)
self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' +
str(new_id), comment.absolute_url(),
"http://nohost/plone/doc1/++conversation++default/" + str(new_id),
comment.absolute_url(),
)
self.assertEqual(
('', 'plone', 'doc1', '++conversation++default', str(new_re_id)),
("", "plone", "doc1", "++conversation++default", str(new_re_id)),
re_comment.getPhysicalPath(),
)
self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' +
str(new_re_id),
"http://nohost/plone/doc1/++conversation++default/" + str(new_re_id),
re_comment.absolute_url(),
)
self.assertEqual(
(
'', 'plone', 'doc1', '++conversation++default',
"",
"plone",
"doc1",
"++conversation++default",
str(new_re_re_id),
),
re_re_comment.getPhysicalPath(),
)
self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' +
str(new_re_re_id),
"http://nohost/plone/doc1/++conversation++default/" + str(new_re_re_id),
re_re_comment.absolute_url(),
)
self.assertEqual(
(
'', 'plone', 'doc1', '++conversation++default',
"",
"plone",
"doc1",
"++conversation++default",
str(new_re_re_re_id),
),
re_re_re_comment.getPhysicalPath(),
)
self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' +
str(new_re_re_re_id),
"http://nohost/plone/doc1/++conversation++default/" + str(new_re_re_re_id),
re_re_re_comment.absolute_url(),
)
@@ -1,14 +1,13 @@
# -*- coding: utf-8 -*-
from .. import interfaces
from ..browser.comment import EditCommentForm
from ..browser.comments import CommentForm
from ..browser.comments import CommentsViewlet
from ..interfaces import IConversation
from ..interfaces import IDiscussionSettings
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from AccessControl import Unauthorized
from datetime import datetime
from OFS.Image import Image
from plone.app.discussion import interfaces
from plone.app.discussion.browser.comment import EditCommentForm
from plone.app.discussion.browser.comments import CommentForm
from plone.app.discussion.browser.comments import CommentsViewlet
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from plone.app.testing import login
from plone.app.testing import logout
from plone.app.testing import setRoles
@@ -16,7 +15,6 @@ from plone.app.testing import TEST_USER_ID
from plone.app.testing import TEST_USER_NAME
from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.tests import dummy
from z3c.form.interfaces import IFormLayer
from zope import interface
from zope.annotation.interfaces import IAttributeAnnotatable
@@ -28,33 +26,67 @@ from zope.interface import alsoProvides
from zope.interface import Interface
from zope.publisher.browser import TestRequest
from zope.publisher.interfaces.browser import IBrowserRequest
from ZPublisher.HTTPRequest import FileUpload
import io
import time
import unittest
TEXT = b"file data"
class DummyFile(FileUpload):
"""Dummy upload object
Used to fake uploaded files.
"""
__allow_access_to_unprotected_subobjects__ = 1
filename = "dummy.txt"
data = TEXT
headers = {}
def __init__(self, filename=None, data=None, headers=None):
if filename is not None:
self.filename = filename
if data is not None:
self.data = data
if headers is not None:
self.headers = headers
self.file = io.BytesIO(self.data)
def seek(self, *args):
pass
def tell(self, *args):
return 1
def read(self, *args):
return self.data
class TestCommentForm(unittest.TestCase):
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.portal.invokeFactory('Folder', 'test-folder')
self.folder = self.portal['test-folder']
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.portal.invokeFactory("Folder", "test-folder")
self.folder = self.portal["test-folder"]
interface.alsoProvides(
self.portal.REQUEST,
interfaces.IDiscussionLayer,
)
wftool = getToolByName(self.portal, 'portal_workflow')
wftool.doActionFor(self.portal.doc1, action='publish')
wftool = getToolByName(self.portal, "portal_workflow")
wftool.doActionFor(self.portal.doc1, action="publish")
self.portal.doc1.allow_discussion = True
self.membershipTool = getToolByName(self.folder, 'portal_membership')
self.membershipTool = getToolByName(self.folder, "portal_membership")
self.memberdata = self.portal.portal_memberdata
self.context = getattr(self.portal, 'doc1')
self.context = getattr(self.portal, "doc1")
# Allow discussion
registry = queryUtility(IRegistry)
@@ -62,8 +94,7 @@ class TestCommentForm(unittest.TestCase):
settings.globally_enabled = True
def test_add_comment(self):
"""Post a comment as logged-in user.
"""
"""Post a comment as logged-in user."""
# Allow discussion
self.portal.doc1.allow_discussion = True
@@ -80,7 +111,7 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u'comment-form',
name="comment-form",
)
# The form should return an error if the comment text field is empty
@@ -88,46 +119,45 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter(
(self.context, request),
name=u'comment-form',
name="comment-form",
)
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
self.assertEqual(len(errors), 1)
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
# The form is submitted successfully, if the required text field is
# filled out
request = make_request(form={'form.widgets.text': u'bar'})
request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter(
(self.context, request),
name=u'comment-form',
name="comment-form",
)
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
self.assertEqual(len(errors), 0)
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
comments = IConversation(commentForm.context).getComments()
comments = [comment for comment in comments] # consume iterator
self.assertEqual(len(comments), 1)
for comment in comments:
self.assertEqual(comment.text, u'bar')
self.assertEqual(comment.creator, 'test_user_1_')
self.assertEqual(comment.getOwner().getUserName(), 'test-user')
self.assertEqual(comment.text, "bar")
self.assertEqual(comment.creator, "test_user_1_")
self.assertEqual(comment.getOwner().getUserName(), "test-user")
local_roles = comment.get_local_roles()
self.assertEqual(len(local_roles), 1)
userid, roles = local_roles[0]
self.assertEqual(userid, 'test_user_1_')
self.assertEqual(userid, "test_user_1_")
self.assertEqual(len(roles), 1)
self.assertEqual(roles[0], 'Owner')
self.assertEqual(roles[0], "Owner")
def test_edit_comment(self):
"""Edit a comment as logged-in user.
"""
"""Edit a comment as logged-in user."""
# Allow discussion
self.portal.doc1.allow_discussion = True
@@ -144,65 +174,64 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u'comment-form',
name="comment-form",
)
provideAdapter(
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=EditCommentForm,
name=u'edit-comment-form',
name="edit-comment-form",
)
# The form is submitted successfully, if the required text field is
# filled out
request = make_request(form={'form.widgets.text': u'bar'})
request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter(
(self.context, request),
name=u'comment-form',
name="comment-form",
)
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
self.assertEqual(len(errors), 0)
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
# Edit the last comment
conversation = IConversation(self.context)
comment = [x for x in conversation.getComments()][-1]
request = make_request(form={'form.widgets.text': u'foobar'})
request = make_request(form={"form.widgets.text": "foobar"})
editForm = getMultiAdapter(
(comment, request),
name=u'edit-comment-form',
name="edit-comment-form",
)
editForm.update()
data, errors = editForm.extractData() # pylint: disable-msg=W0612
self.assertEqual(len(errors), 0)
self.assertFalse(editForm.handleComment(editForm, 'foo'))
self.assertFalse(editForm.handleComment(editForm, "foo"))
comment = [x for x in conversation.getComments()][-1]
self.assertEqual(comment.text, u'foobar')
self.assertEqual(comment.text, "foobar")
comments = IConversation(commentForm.context).getComments()
comments = [c for c in comments] # consume iterator
self.assertEqual(len(comments), 1)
for comment in comments:
self.assertEqual(comment.text, u'foobar')
self.assertEqual(comment.creator, 'test_user_1_')
self.assertEqual(comment.text, "foobar")
self.assertEqual(comment.creator, "test_user_1_")
self.assertEqual(comment.getOwner().getUserName(), 'test-user')
self.assertEqual(comment.getOwner().getUserName(), "test-user")
local_roles = comment.get_local_roles()
self.assertEqual(len(local_roles), 1)
userid, roles = local_roles[0]
self.assertEqual(userid, 'test_user_1_')
self.assertEqual(userid, "test_user_1_")
self.assertEqual(len(roles), 1)
self.assertEqual(roles[0], 'Owner')
self.assertEqual(roles[0], "Owner")
def test_delete_comment(self):
"""Delete a comment as logged-in user.
"""
"""Delete a comment as logged-in user."""
# Allow discussion
self.portal.doc1.allow_discussion = True
@@ -219,48 +248,47 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u'comment-form',
name="comment-form",
)
# The form is submitted successfully, if the required text field is
# filled out
form_request = make_request(form={'form.widgets.text': u'bar'})
form_request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter(
(self.context, form_request),
name=u'comment-form',
name="comment-form",
)
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
self.assertEqual(len(errors), 0)
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
# Delete the last comment
conversation = IConversation(self.context)
comment = [x for x in conversation.getComments()][-1]
deleteView = getMultiAdapter(
(comment, self.request),
name=u'moderate-delete-comment',
name="moderate-delete-comment",
)
# try to delete last comment without 'Delete comments' permission
setRoles(self.portal, TEST_USER_ID, ['Member'])
setRoles(self.portal, TEST_USER_ID, ["Member"])
self.assertRaises(
Unauthorized,
comment.restrictedTraverse,
'@@moderate-delete-comment',
"@@moderate-delete-comment",
)
deleteView()
self.assertEqual(1, len([x for x in conversation.getComments()]))
# try to delete last comment with 'Delete comments' permission
setRoles(self.portal, TEST_USER_ID, ['Reviewer'])
setRoles(self.portal, TEST_USER_ID, ["Reviewer"])
deleteView()
self.assertEqual(0, len([x for x in conversation.getComments()]))
setRoles(self.portal, TEST_USER_ID, ['Manager'])
setRoles(self.portal, TEST_USER_ID, ["Manager"])
def test_delete_own_comment(self):
"""Delete own comment as logged-in user.
"""
"""Delete own comment as logged-in user."""
# Allow discussion
self.portal.doc1.allow_discussion = True
@@ -277,42 +305,42 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u'comment-form',
name="comment-form",
)
# The form is submitted successfully, if the required text field is
# filled out
form_request = make_request(form={'form.widgets.text': u'bar'})
form_request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter(
(self.context, form_request),
name=u'comment-form',
name="comment-form",
)
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
self.assertEqual(len(errors), 0)
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
# Delete the last comment
conversation = IConversation(self.context)
comment = [x for x in conversation.getComments()][-1]
deleteView = getMultiAdapter(
(comment, self.request),
name=u'delete-own-comment',
name="delete-own-comment",
)
# try to delete last comment with johndoe
setRoles(self.portal, 'johndoe', ['Member'])
login(self.portal, 'johndoe')
setRoles(self.portal, "johndoe", ["Member"])
login(self.portal, "johndoe")
self.assertRaises(
Unauthorized,
comment.restrictedTraverse,
'@@delete-own-comment',
"@@delete-own-comment",
)
self.assertEqual(1, len([x for x in conversation.getComments()]))
# try to delete last comment with the same user that created it
login(self.portal, TEST_USER_NAME)
setRoles(self.portal, TEST_USER_ID, ['Member'])
setRoles(self.portal, TEST_USER_ID, ["Member"])
deleteView()
self.assertEqual(0, len([x for x in conversation.getComments()]))
@@ -335,40 +363,43 @@ class TestCommentForm(unittest.TestCase):
alsoProvides(request, IAttributeAnnotatable)
return request
provideAdapter(adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u'comment-form')
provideAdapter(
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name="comment-form",
)
# Post an anonymous comment and provide a name
request = make_request(form={
'form.widgets.name': u'john doe',
'form.widgets.text': u'bar',
})
request = make_request(
form={
"form.widgets.name": "john doe",
"form.widgets.text": "bar",
}
)
commentForm = getMultiAdapter(
(self.context, request),
name=u'comment-form',
name="comment-form",
)
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
self.assertEqual(len(errors), 0)
self.assertFalse(commentForm.handleComment(commentForm, 'action'))
self.assertFalse(commentForm.handleComment(commentForm, "action"))
comments = IConversation(commentForm.context).getComments()
comments = [comment for comment in comments] # consume itertor
self.assertEqual(len(comments), 1)
for comment in IConversation(commentForm.context).getComments():
self.assertEqual(comment.text, u'bar')
self.assertEqual(comment.text, "bar")
self.assertIsNone(comment.creator)
roles = comment.get_local_roles()
self.assertEqual(len(roles), 0)
def test_can_not_add_comments_if_discussion_is_not_allowed(self):
"""Make sure that comments can't be posted if discussion is disabled.
"""
"""Make sure that comments can't be posted if discussion is disabled."""
# Disable discussion
registry = queryUtility(IRegistry)
@@ -382,16 +413,18 @@ class TestCommentForm(unittest.TestCase):
alsoProvides(request, IAttributeAnnotatable)
return request
provideAdapter(adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u'comment-form')
provideAdapter(
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name="comment-form",
)
request = make_request(form={'form.widgets.text': u'bar'})
request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter(
(self.context, request),
name=u'comment-form',
name="comment-form",
)
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@@ -400,14 +433,11 @@ class TestCommentForm(unittest.TestCase):
# allowed
self.assertEqual(len(errors), 0)
self.assertRaises(Unauthorized,
commentForm.handleComment,
commentForm,
'foo')
self.assertRaises(Unauthorized, commentForm.handleComment, commentForm, "foo")
def test_anonymous_can_not_add_comments_if_discussion_is_not_allowed(self):
"""Make sure that anonymous users can't post comments if anonymous
comments are disabled.
comments are disabled.
"""
# Anonymous comments are disabled by default
@@ -421,15 +451,16 @@ class TestCommentForm(unittest.TestCase):
alsoProvides(request, IAttributeAnnotatable)
return request
provideAdapter(adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u'comment-form')
provideAdapter(
adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name="comment-form",
)
request = make_request(form={'form.widgets.text': u'bar'})
request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter((self.context, request),
name=u'comment-form')
commentForm = getMultiAdapter((self.context, request), name="comment-form")
commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@@ -438,7 +469,7 @@ class TestCommentForm(unittest.TestCase):
Unauthorized,
commentForm.handleComment,
commentForm,
'foo',
"foo",
)
@@ -447,22 +478,22 @@ class TestCommentsViewlet(unittest.TestCase):
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.portal.invokeFactory('Folder', 'test-folder')
self.folder = self.portal['test-folder']
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.portal.invokeFactory("Folder", "test-folder")
self.folder = self.portal["test-folder"]
interface.alsoProvides(
self.request,
interfaces.IDiscussionLayer,
)
self.workflowTool = getToolByName(self.portal, 'portal_workflow')
self.workflowTool.setDefaultChain('comment_one_state_workflow')
self.workflowTool = getToolByName(self.portal, "portal_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
context = getattr(self.portal, 'doc1')
context = getattr(self.portal, "doc1")
self.viewlet = CommentsViewlet(context, self.request, None, None)
# Allow discussion
@@ -484,15 +515,14 @@ class TestCommentsViewlet(unittest.TestCase):
# Anonymous has no 'can review' permission
self.assertFalse(self.viewlet.can_review())
# The reviewer role has the 'Review comments' permission
self.portal.acl_users._doAddUser(
'reviewer', 'secret', ['Reviewer'], [])
login(self.portal, 'reviewer')
self.portal.acl_users._doAddUser("reviewer", "secret", ["Reviewer"], [])
login(self.portal, "reviewer")
self.assertTrue(self.viewlet.can_review())
def test_can_manage(self):
"""We keep this method for backward compatibility. This method has been
removed in version 1.0b9 and added again in 1.0b11 because we don't
do API changes in beta releases.
removed in version 1.0b9 and added again in 1.0b11 because we don't
do API changes in beta releases.
"""
# Portal owner has 'can review' permission
self.assertTrue(self.viewlet.can_manage())
@@ -500,9 +530,8 @@ class TestCommentsViewlet(unittest.TestCase):
# Anonymous has no 'can review' permission
self.assertFalse(self.viewlet.can_manage())
# The reviewer role has the 'Review comments' permission
self.portal.acl_users._doAddUser(
'reviewer', 'secret', ['Reviewer'], [])
login(self.portal, 'reviewer')
self.portal.acl_users._doAddUser("reviewer", "secret", ["Reviewer"], [])
login(self.portal, "reviewer")
self.assertTrue(self.viewlet.can_manage())
def test_is_discussion_allowed(self):
@@ -519,46 +548,48 @@ class TestCommentsViewlet(unittest.TestCase):
self.assertTrue(self.viewlet.comment_transform_message())
self.assertEqual(
self.viewlet.comment_transform_message(),
'You can add a comment by filling out the form below. Plain ' +
'text formatting.')
"You can add a comment by filling out the form below. Plain "
+ "text formatting.",
)
# Set text transform to intelligent text
registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings, check=False)
settings.text_transform = 'text/x-web-intelligent'
settings.text_transform = "text/x-web-intelligent"
# Make sure the comment description changes accordingly
self.assertEqual(
self.viewlet.comment_transform_message(),
'You can add a comment by filling out the form below. ' +
'Plain text formatting. Web and email addresses are transformed ' +
'into clickable links.',
"You can add a comment by filling out the form below. "
+ "Plain text formatting. Web and email addresses are transformed "
+ "into clickable links.",
)
# Enable moderation workflow
self.workflowTool.setChainForPortalTypes(
('Discussion Item',),
('comment_review_workflow,'))
("Discussion Item",), ("comment_review_workflow,")
)
# Make sure the comment description shows that comments are moderated
self.assertEqual(
self.viewlet.comment_transform_message(),
'You can add a comment by filling out the form below. ' +
'Plain text formatting. Web and email addresses are transformed ' +
'into clickable links. Comments are moderated.')
"You can add a comment by filling out the form below. "
+ "Plain text formatting. Web and email addresses are transformed "
+ "into clickable links. Comments are moderated.",
)
def test_has_replies(self):
self.assertEqual(self.viewlet.has_replies(), False)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
conversation = IConversation(self.portal.doc1)
conversation.addComment(comment)
self.assertEqual(self.viewlet.has_replies(), True)
def test_get_replies(self):
self.assertFalse(self.viewlet.get_replies())
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
conversation = IConversation(self.portal.doc1)
conversation.addComment(comment)
conversation.addComment(comment)
@@ -571,7 +602,7 @@ class TestCommentsViewlet(unittest.TestCase):
next(replies)
def test_get_replies_on_non_annotatable_object(self):
context = self.portal.MailHost # the mail host is not annotatable
context = self.portal.MailHost # the mail host is not annotatable
viewlet = CommentsViewlet(context, self.request, None, None)
replies = viewlet.get_replies()
self.assertEqual(len(tuple(replies)), 0)
@@ -581,8 +612,8 @@ class TestCommentsViewlet(unittest.TestCase):
def test_get_replies_with_workflow_actions(self):
self.assertFalse(self.viewlet.get_replies(workflow_actions=True))
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
conversation = IConversation(self.portal.doc1)
c1 = conversation.addComment(comment)
self.assertEqual(
@@ -591,32 +622,34 @@ class TestCommentsViewlet(unittest.TestCase):
)
# Enable moderation workflow
self.workflowTool.setChainForPortalTypes(
('Discussion Item',),
('comment_review_workflow,'),
("Discussion Item",),
("comment_review_workflow,"),
)
# Check if workflow actions are available
reply = next(self.viewlet.get_replies(workflow_actions=True))
self.assertTrue('actions' in reply)
self.assertTrue("actions" in reply)
self.assertEqual(
reply['actions'][0]['id'],
'mark_as_spam',
reply["actions"][0]["id"],
"mark_as_spam",
)
expected_url = (
"http://nohost/plone/doc1/++conversation++default/{0}"
"/content_status_modify?workflow_action=mark_as_spam"
)
expected_url = 'http://nohost/plone/doc1/++conversation++default/{0}' \
'/content_status_modify?workflow_action=mark_as_spam'
self.assertEqual(
reply['actions'][0]['url'],
reply["actions"][0]["url"],
expected_url.format(int(c1)),
)
def test_get_commenter_home_url(self):
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
IConversation(self.portal.doc1)
portal_membership = getToolByName(self.portal, 'portal_membership')
portal_membership = getToolByName(self.portal, "portal_membership")
m = portal_membership.getAuthenticatedMember()
self.assertEqual(
self.viewlet.get_commenter_home_url(m.getUserName()),
'http://nohost/plone/author/test-user',
"http://nohost/plone/author/test-user",
)
def test_get_commenter_home_url_is_none(self):
@@ -625,72 +658,77 @@ class TestCommentsViewlet(unittest.TestCase):
def test_get_commenter_portrait(self):
# Add a user with a member image
self.membershipTool.addMember('jim', 'Jim', ['Member'], [])
self.memberdata._setPortrait(Image(
id='jim',
file=dummy.File(),
title='',
), 'jim')
self.assertEqual(
self.memberdata._getPortrait('jim').getId(),
'jim',
self.membershipTool.addMember("jim", "Jim", ["Member"], [])
self.memberdata._setPortrait(
Image(
id="jim",
file=DummyFile(),
title="",
),
"jim",
)
self.assertEqual(
self.memberdata._getPortrait('jim').meta_type,
'Image',
self.memberdata._getPortrait("jim").getId(),
"jim",
)
self.assertEqual(
self.memberdata._getPortrait("jim").meta_type,
"Image",
)
# Add a conversation with a comment
conversation = IConversation(self.portal.doc1)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment.Creator = 'Jim'
comment.author_username = 'jim'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.Creator = "Jim"
comment.author_username = "jim"
conversation.addComment(comment)
# Call get_commenter_portrait method of the viewlet
self.viewlet.update()
portrait_url = self.viewlet.get_commenter_portrait('jim')
portrait_url = self.viewlet.get_commenter_portrait("jim")
# Check if the correct member image URL is returned
self.assertEqual(
portrait_url,
'http://nohost/plone/portal_memberdata/portraits/jim',
"http://nohost/plone/portal_memberdata/portraits/jim",
)
def test_get_commenter_portrait_is_none(self):
self.assertTrue(
self.viewlet.get_commenter_portrait() in (
'defaultUser.png',
'defaultUser.gif',
self.viewlet.get_commenter_portrait()
in (
"defaultUser.png",
"defaultUser.gif",
),
)
def test_get_commenter_portrait_without_userimage(self):
# Create a user without a user image
self.membershipTool.addMember('jim', 'Jim', ['Member'], [])
self.membershipTool.addMember("jim", "Jim", ["Member"], [])
# Add a conversation with a comment
conversation = IConversation(self.portal.doc1)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment.Creator = 'Jim'
comment.author_username = 'jim'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.Creator = "Jim"
comment.author_username = "jim"
conversation.addComment(comment)
# Call get_commenter_portrait method of the viewlet
self.viewlet.update()
portrait_url = self.viewlet.get_commenter_portrait('jim')
portrait_url = self.viewlet.get_commenter_portrait("jim")
# Check if the correct default member image URL is returned.
# Note that Products.PlonePAS 4.0.5 and later have .png and
# earlier versions have .gif.
self.assertTrue(
portrait_url in (
'http://nohost/plone/defaultUser.png',
'http://nohost/plone/defaultUser.gif',
portrait_url
in (
"http://nohost/plone/defaultUser.png",
"http://nohost/plone/defaultUser.gif",
),
)
@@ -700,8 +738,8 @@ class TestCommentsViewlet(unittest.TestCase):
# Allow anonymous discussion
registry = queryUtility(IRegistry)
registry[
'plone.app.discussion.interfaces.IDiscussionSettings.' +
'anonymous_comments'
"plone.app.discussion.interfaces.IDiscussionSettings."
+ "anonymous_comments"
] = True
# Test if anonymous discussion is allowed for the viewlet
self.assertTrue(self.viewlet.anonymous_discussion_allowed())
@@ -710,8 +748,8 @@ class TestCommentsViewlet(unittest.TestCase):
self.assertTrue(self.viewlet.show_commenter_image())
registry = queryUtility(IRegistry)
registry[
'plone.app.discussion.interfaces.IDiscussionSettings.' +
'show_commenter_image'
"plone.app.discussion.interfaces.IDiscussionSettings."
+ "show_commenter_image"
] = False
self.assertFalse(self.viewlet.show_commenter_image())
@@ -724,7 +762,7 @@ class TestCommentsViewlet(unittest.TestCase):
self.viewlet.update()
self.assertEqual(
self.viewlet.login_action(),
'http://nohost/plone/login_form?came_from=http%3A//nohost',
"http://nohost/plone/login_form?came_from=http%3A//nohost",
)
def test_format_time(self):
@@ -737,9 +775,8 @@ class TestCommentsViewlet(unittest.TestCase):
# a correct utc time that can be used to make datetime set the utc
# time of the local time given above. That way, the time for the
# example below is correct within each time zone, independent of DST
python_time = datetime(
*time.gmtime(time.mktime(python_time.timetuple()))[:7])
python_time = datetime(*time.gmtime(time.mktime(python_time.timetuple()))[:7])
localized_time = self.viewlet.format_time(python_time)
self.assertTrue(
localized_time in ['Feb 01, 2009 11:32 PM', '2009-02-01 23:32'],
localized_time in ["Feb 01, 2009 11:32 PM", "2009-02-01 23:32"],
)
+60 -54
View File
@@ -1,11 +1,12 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import ICommentAddedEvent
from plone.app.discussion.interfaces import ICommentRemovedEvent
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IReplies
from plone.app.discussion.interfaces import IReplyAddedEvent
from plone.app.discussion.interfaces import IReplyRemovedEvent
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from plone.app.discussion.testing import ( # noqa
PLONE_APP_DISCUSSION_INTEGRATION_TESTING,
)
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.contentrules.rule.interfaces import IRuleEventType
@@ -17,31 +18,33 @@ import unittest
class CommentContentRulesTest(unittest.TestCase):
""" Test custom comments events
"""
"""Test custom comments events"""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
# Setup sandbox
self.portal = self.layer['portal']
self.request = self.layer['request']
self.portal = self.layer["portal"]
self.request = self.layer["request"]
# Setup current user properties
member = self.portal.portal_membership.getMemberById(TEST_USER_ID)
member.setMemberProperties({
'fullname': 'X Manager',
'email': 'xmanager@example.com',
})
member.setMemberProperties(
{
"fullname": "X Manager",
"email": "xmanager@example.com",
}
)
setRoles(self.portal, TEST_USER_ID, ['Manager'])
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.document = self.portal['doc1']
self.document = self.portal["doc1"]
comment = createObject('plone.Comment')
comment.text = 'This is a comment'
comment.author_username = 'jim'
comment.author_name = 'Jim'
comment.author_email = 'jim@example.com'
comment = createObject("plone.Comment")
comment.text = "This is a comment"
comment.author_username = "jim"
comment.author_name = "Jim"
comment.author_email = "jim@example.com"
conversation = IConversation(self.document)
conversation.addComment(comment)
@@ -52,58 +55,61 @@ class CommentContentRulesTest(unittest.TestCase):
self.assertTrue(IRuleEventType.providedBy(IReplyRemovedEvent))
def testCommentIdStringSubstitution(self):
comment_id = getAdapter(self.document, IStringSubstitution,
name=u'comment_id')
comment_id = getAdapter(self.document, IStringSubstitution, name="comment_id")
self.assertIsInstance(comment_id(), int)
def testCommentTextStringSubstitution(self):
comment_text = getAdapter(self.document, IStringSubstitution,
name=u'comment_text')
self.assertEqual(comment_text(), u'This is a comment')
comment_text = getAdapter(
self.document, IStringSubstitution, name="comment_text"
)
self.assertEqual(comment_text(), "This is a comment")
def testCommentUserIdStringSubstitution(self):
comment_user_id = getAdapter(self.document, IStringSubstitution,
name=u'comment_user_id')
self.assertEqual(comment_user_id(), u'jim')
comment_user_id = getAdapter(
self.document, IStringSubstitution, name="comment_user_id"
)
self.assertEqual(comment_user_id(), "jim")
def testCommentUserFullNameStringSubstitution(self):
comment_user_fullname = getAdapter(self.document, IStringSubstitution,
name=u'comment_user_fullname')
self.assertEqual(comment_user_fullname(), u'Jim')
comment_user_fullname = getAdapter(
self.document, IStringSubstitution, name="comment_user_fullname"
)
self.assertEqual(comment_user_fullname(), "Jim")
def testCommentUserEmailStringSubstitution(self):
comment_user_email = getAdapter(self.document, IStringSubstitution,
name=u'comment_user_email')
self.assertEqual(comment_user_email(), u'jim@example.com')
comment_user_email = getAdapter(
self.document, IStringSubstitution, name="comment_user_email"
)
self.assertEqual(comment_user_email(), "jim@example.com")
class ReplyContentRulesTest(unittest.TestCase):
""" Test custom comments events
"""
"""Test custom comments events"""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
# Setup sandbox
self.portal = self.layer['portal']
self.request = self.layer['request']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.document = self.portal['doc1']
self.document = self.portal["doc1"]
conversation = IConversation(self.document)
replies = IReplies(conversation)
comment = createObject('plone.Comment')
comment.text = 'This is a comment'
comment = createObject("plone.Comment")
comment.text = "This is a comment"
new_id = replies.addComment(comment)
comment = self.document.restrictedTraverse(
'++conversation++default/{0}'.format(new_id),
f"++conversation++default/{new_id}",
)
re_comment = createObject('plone.Comment')
re_comment.text = 'This is a reply'
re_comment.author_username = 'julia'
re_comment.author_name = 'Juliana'
re_comment.author_email = 'julia@example.com'
re_comment = createObject("plone.Comment")
re_comment.text = "This is a reply"
re_comment.author_username = "julia"
re_comment.author_name = "Juliana"
re_comment.author_email = "julia@example.com"
replies = IReplies(comment)
replies.addComment(re_comment)
@@ -112,7 +118,7 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_id = getAdapter(
self.document,
IStringSubstitution,
name=u'comment_id',
name="comment_id",
)
self.assertIsInstance(reply_id(), int)
@@ -120,30 +126,30 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_text = getAdapter(
self.document,
IStringSubstitution,
name=u'comment_text',
name="comment_text",
)
self.assertEqual(reply_text(), u'This is a reply')
self.assertEqual(reply_text(), "This is a reply")
def testReplyUserIdStringSubstitution(self):
reply_user_id = getAdapter(
self.document,
IStringSubstitution,
name=u'comment_user_id',
name="comment_user_id",
)
self.assertEqual(reply_user_id(), u'julia')
self.assertEqual(reply_user_id(), "julia")
def testReplyUserFullNameStringSubstitution(self):
reply_user_fullname = getAdapter(
self.document,
IStringSubstitution,
name=u'comment_user_fullname',
name="comment_user_fullname",
)
self.assertEqual(reply_user_fullname(), u'Juliana')
self.assertEqual(reply_user_fullname(), "Juliana")
def testReplyUserEmailStringSubstitution(self):
reply_user_email = getAdapter(
self.document,
IStringSubstitution,
name=u'comment_user_email',
name="comment_user_email",
)
self.assertEqual(reply_user_email(), u'julia@example.com')
self.assertEqual(reply_user_email(), "julia@example.com")
+59 -57
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from plone.app.discussion.testing import ( # noqa
PLONE_APP_DISCUSSION_INTEGRATION_TESTING,
)
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.registry import Registry
@@ -17,8 +18,8 @@ class RegistryTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.registry = Registry()
self.registry.registerInterface(IDiscussionSettings)
@@ -29,99 +30,100 @@ class RegistryTest(unittest.TestCase):
def test_discussion_controlpanel_view(self):
view = getMultiAdapter(
(self.portal, self.portal.REQUEST),
name='discussion-controlpanel',
name="discussion-controlpanel",
)
self.assertTrue(view())
def test_discussion_in_controlpanel(self):
# Check if discussion is in the control panel
self.controlpanel = getToolByName(self.portal, 'portal_controlpanel')
self.controlpanel = getToolByName(self.portal, "portal_controlpanel")
self.assertTrue(
'discussion' in [
a.getAction(self)['id']
for a in self.controlpanel.listActions()
],
"discussion"
in [a.getAction(self)["id"] for a in self.controlpanel.listActions()],
)
def test_globally_enabled(self):
# Check globally_enabled record
self.assertTrue('globally_enabled' in IDiscussionSettings)
self.assertTrue("globally_enabled" in IDiscussionSettings)
self.assertEqual(
self.registry[
'plone.app.discussion.interfaces.' +
'IDiscussionSettings.globally_enabled'
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.globally_enabled"
],
False,
)
def test_anonymous_comments(self):
# Check anonymous_comments record
self.assertTrue('anonymous_comments' in IDiscussionSettings)
self.assertTrue("anonymous_comments" in IDiscussionSettings)
self.assertEqual(
self.registry[
'plone.app.discussion.interfaces.' +
'IDiscussionSettings.anonymous_comments'
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.anonymous_comments"
],
False,
)
def test_moderation_enabled(self):
# Check globally_enabled record
self.assertTrue('moderation_enabled' in IDiscussionSettings)
self.assertTrue("moderation_enabled" in IDiscussionSettings)
self.assertEqual(
self.registry[
'plone.app.discussion.interfaces.' +
'IDiscussionSettings.moderation_enabled'
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.moderation_enabled"
],
False,
)
def test_edit_comment_enabled(self):
# Check edit_comment_enabled record
self.assertTrue('edit_comment_enabled' in IDiscussionSettings)
self.assertTrue("edit_comment_enabled" in IDiscussionSettings)
self.assertEqual(
self.registry['plone.app.discussion.interfaces.' +
'IDiscussionSettings.edit_comment_enabled'],
self.registry[
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.edit_comment_enabled"
],
False,
)
def test_delete_own_comment_enabled(self):
# Check delete_own_comment_enabled record
self.assertTrue('delete_own_comment_enabled' in IDiscussionSettings)
self.assertTrue("delete_own_comment_enabled" in IDiscussionSettings)
self.assertEqual(
self.registry['plone.app.discussion.interfaces.' +
'IDiscussionSettings.delete_own_comment_enabled'],
self.registry[
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.delete_own_comment_enabled"
],
False,
)
def test_text_transform(self):
self.assertTrue('text_transform' in IDiscussionSettings)
self.assertTrue("text_transform" in IDiscussionSettings)
self.assertEqual(
self.registry[
'plone.app.discussion.interfaces.' +
'IDiscussionSettings.text_transform'
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.text_transform"
],
'text/plain',
"text/plain",
)
def test_captcha(self):
# Check globally_enabled record
self.assertTrue('captcha' in IDiscussionSettings)
self.assertTrue("captcha" in IDiscussionSettings)
self.assertEqual(
self.registry[
'plone.app.discussion.interfaces.' +
'IDiscussionSettings.captcha'
"plone.app.discussion.interfaces." + "IDiscussionSettings.captcha"
],
'disabled',
"disabled",
)
def test_show_commenter_image(self):
# Check show_commenter_image record
self.assertTrue('show_commenter_image' in IDiscussionSettings)
self.assertTrue("show_commenter_image" in IDiscussionSettings)
self.assertEqual(
self.registry[
'plone.app.discussion.interfaces.' +
'IDiscussionSettings.show_commenter_image'
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.show_commenter_image"
],
True,
)
@@ -129,12 +131,12 @@ class RegistryTest(unittest.TestCase):
def test_moderator_notification_enabled(self):
# Check show_commenter_image record
self.assertTrue(
'moderator_notification_enabled' in IDiscussionSettings,
"moderator_notification_enabled" in IDiscussionSettings,
)
self.assertEqual(
self.registry[
'plone.app.discussion.interfaces.' +
'IDiscussionSettings.moderator_notification_enabled'
"plone.app.discussion.interfaces."
+ "IDiscussionSettings.moderator_notification_enabled"
],
False,
)
@@ -154,22 +156,22 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
registry = queryUtility(IRegistry)
self.settings = registry.forInterface(IDiscussionSettings, check=False)
def test_moderation_enabled_in_discussion_control_panel_changed(self):
"""Make sure the 'Discussion Item' workflow is changed properly, when
the 'comment_moderation' setting in the discussion control panel
changes.
the 'comment_moderation' setting in the discussion control panel
changes.
"""
# By default the comment_one_state_workflow without moderation is
# enabled
self.assertEqual(
('comment_one_state_workflow',),
("comment_one_state_workflow",),
self.portal.portal_workflow.getChainForPortalType(
'Discussion Item',
"Discussion Item",
),
)
@@ -179,32 +181,32 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
# Make sure the comment_review_workflow with moderation enabled is
# enabled
self.assertEqual(
('comment_review_workflow',),
("comment_review_workflow",),
self.portal.portal_workflow.getChainForPortalType(
'Discussion Item',
"Discussion Item",
),
)
# And back
self.settings.moderation_enabled = False
self.assertEqual(
('comment_one_state_workflow',),
("comment_one_state_workflow",),
self.portal.portal_workflow.getChainForPortalType(
'Discussion Item',
"Discussion Item",
),
)
def test_change_workflow_in_types_control_panel(self):
"""Make sure the setting in the discussion control panel is changed
accordingly, when the workflow for the 'Discussion Item' changed in
the types control panel.
accordingly, when the workflow for the 'Discussion Item' changed in
the types control panel.
"""
# By default, moderation is disabled
self.settings.moderation_enabled = False
# Enable the 'comment_review_workflow' with moderation enabled
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
('comment_review_workflow',),
("Discussion Item",),
("comment_review_workflow",),
)
# Make sure the moderation_enabled settings has changed
@@ -212,15 +214,15 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
# Enable the 'comment_review_workflow' with moderation enabled
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
('comment_one_state_workflow',),
("Discussion Item",),
("comment_one_state_workflow",),
)
self.settings.moderation_enabled = True
# Enable a 'custom' discussion workflow
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
('intranet_workflow',),
("Discussion Item",),
("intranet_workflow",),
)
# Setting has not changed. A Custom workflow disables the
+201 -213
View File
@@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
from ..interfaces import IComment
from ..interfaces import IConversation
from ..interfaces import IDiscussionLayer
from ..interfaces import IDiscussionSettings
from ..interfaces import IReplies
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from Acquisition import aq_base
from Acquisition import aq_parent
from datetime import datetime
from datetime import timedelta
from plone.app.discussion import interfaces
from plone.app.discussion.interfaces import IComment
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.interfaces import IReplies
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.app.vocabularies.types import BAD_TYPES
from plone.dexterity.interfaces import IDexterityContent
from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName
from zope import interface
@@ -19,31 +19,22 @@ from zope.annotation.interfaces import IAnnotations
from zope.component import createObject
from zope.component import queryUtility
import six
import unittest
try:
from plone.dexterity.interfaces import IDexterityContent
DEXTERITY = True
except ImportError:
DEXTERITY = False
class ConversationTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
interface.alsoProvides(
self.portal.REQUEST, interfaces.IDiscussionLayer)
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
interface.alsoProvides(self.portal.REQUEST, IDiscussionLayer)
self.typetool = self.portal.portal_types
self.portal_discussion = getToolByName(
self.portal,
'portal_discussion',
"portal_discussion",
None,
)
# Allow discussion
@@ -52,7 +43,7 @@ class ConversationTest(unittest.TestCase):
settings.globally_enabled = True
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
workflow.doActionFor(self.portal.doc1, "publish")
def test_add_comment(self):
# Create a conversation. In this case we doesn't assign it to an
@@ -62,8 +53,8 @@ class ConversationTest(unittest.TestCase):
# Add a comment. Note: in real life, we always create comments via the
# factory to allow different factories to be swapped in
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = conversation.addComment(comment)
@@ -79,20 +70,19 @@ class ConversationTest(unittest.TestCase):
self.assertEqual(len(tuple(conversation.getThreads())), 1)
self.assertEqual(conversation.total_comments(), 1)
self.assertTrue(
conversation.last_comment_date - datetime.utcnow() <
timedelta(seconds=1),
conversation.last_comment_date - datetime.utcnow() < timedelta(seconds=1),
)
def test_private_comment(self):
conversation = IConversation(self.portal.doc1)
comment = createObject('plone.Comment')
comment.author_username = 'nobody'
comment = createObject("plone.Comment")
comment.author_username = "nobody"
conversation.addComment(comment)
comment.manage_permission('View', roles=tuple())
comment.manage_permission("View", roles=tuple())
self.assertEqual(0, conversation.total_comments())
self.assertEqual(None, conversation.last_comment_date)
self.assertEqual(['nobody'], list(conversation.commentators))
self.assertEqual(["nobody"], list(conversation.commentators))
self.assertEqual([], list(conversation.public_commentators))
def test_delete_comment(self):
@@ -103,8 +93,8 @@ class ConversationTest(unittest.TestCase):
# Add a comment. Note: in real life, we always create comments via the
# factory to allow different factories to be swapped in
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = conversation.addComment(comment)
@@ -139,23 +129,23 @@ class ConversationTest(unittest.TestCase):
# +- Comment 2_1
# Create all comments
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
comment1_1 = createObject('plone.Comment')
comment1_1.text = 'Comment text'
comment1_1 = createObject("plone.Comment")
comment1_1.text = "Comment text"
comment1_1_1 = createObject('plone.Comment')
comment1_1_1.text = 'Comment text'
comment1_1_1 = createObject("plone.Comment")
comment1_1_1.text = "Comment text"
comment1_2 = createObject('plone.Comment')
comment1_2.text = 'Comment text'
comment1_2 = createObject("plone.Comment")
comment1_2.text = "Comment text"
comment2 = createObject('plone.Comment')
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.text = "Comment text"
comment2_1 = createObject('plone.Comment')
comment2_1.text = 'Comment text'
comment2_1 = createObject("plone.Comment")
comment2_1.text = "Comment text"
# Create the nested comment structure
new_id_1 = conversation.addComment(comment1)
@@ -175,21 +165,24 @@ class ConversationTest(unittest.TestCase):
del conversation[new_id_1]
self.assertEqual([
{'comment': comment2, 'depth': 0, 'id': new_id_2},
{'comment': comment2_1, 'depth': 1, 'id': new_id_2_1},
], list(conversation.getThreads()))
self.assertEqual(
[
{"comment": comment2, "depth": 0, "id": new_id_2},
{"comment": comment2_1, "depth": 1, "id": new_id_2_1},
],
list(conversation.getThreads()),
)
def test_delete_comment_when_content_object_is_deleted(self):
# Make sure all comments of a content object are deleted when the
# object itself is deleted.
conversation = IConversation(self.portal.doc1)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
conversation.addComment(comment)
# Delete the content object
self.portal.manage_delObjects(['doc1'])
self.portal.manage_delObjects(["doc1"])
# Make sure the comment has been deleted as well
self.assertEqual(len(list(conversation.getComments())), 0)
@@ -198,8 +191,8 @@ class ConversationTest(unittest.TestCase):
def test_comments_enabled_on_doc_in_subfolder(self):
typetool = self.portal.portal_types
typetool.constructContent('Folder', self.portal, 'folder1')
typetool.constructContent('Document', self.portal.folder1, 'doc2')
typetool.constructContent("Folder", self.portal, "folder1")
typetool.constructContent("Document", self.portal.folder1, "doc2")
folder = self.portal.folder1
@@ -209,13 +202,13 @@ class ConversationTest(unittest.TestCase):
self.assertFalse(aq_base(folder).allow_discussion)
doc = self.portal.folder1.doc2
conversation = doc.restrictedTraverse('@@conversation_view')
conversation = doc.restrictedTraverse("@@conversation_view")
self.assertEqual(conversation.enabled(), False)
# We have to allow discussion on Document content type, since
# otherwise allow_discussion will always return False
portal_types = getToolByName(self.portal, 'portal_types')
document_fti = getattr(portal_types, 'Document')
portal_types = getToolByName(self.portal, "portal_types")
document_fti = getattr(portal_types, "Document")
document_fti.manage_changeProperties(allow_discussion=True)
self.assertEqual(conversation.enabled(), True)
@@ -223,13 +216,12 @@ class ConversationTest(unittest.TestCase):
def test_disable_commenting_globally(self):
# Create a conversation.
conversation = self.portal.doc1.restrictedTraverse(
'@@conversation_view')
conversation = self.portal.doc1.restrictedTraverse("@@conversation_view")
# We have to allow discussion on Document content type, since
# otherwise allow_discussion will always return False
portal_types = getToolByName(self.portal, 'portal_types')
document_fti = getattr(portal_types, 'Document')
portal_types = getToolByName(self.portal, "portal_types")
document_fti = getattr(portal_types, "Document")
document_fti.manage_changeProperties(allow_discussion=True)
# Check if conversation is enabled now
@@ -249,14 +241,14 @@ class ConversationTest(unittest.TestCase):
def test_allow_discussion_for_news_items(self):
self.typetool.constructContent('News Item', self.portal, 'newsitem')
self.typetool.constructContent("News Item", self.portal, "newsitem")
newsitem = self.portal.newsitem
conversation = newsitem.restrictedTraverse('@@conversation_view')
conversation = newsitem.restrictedTraverse("@@conversation_view")
# We have to allow discussion on Document content type, since
# otherwise allow_discussion will always return False
portal_types = getToolByName(self.portal, 'portal_types')
document_fti = getattr(portal_types, 'News Item')
portal_types = getToolByName(self.portal, "portal_types")
document_fti = getattr(portal_types, "News Item")
document_fti.manage_changeProperties(allow_discussion=True)
# Check if conversation is enabled now
@@ -278,23 +270,23 @@ class ConversationTest(unittest.TestCase):
# Create a conversation.
conversation = self.portal.doc1.restrictedTraverse(
'@@conversation_view',
"@@conversation_view",
)
# The Document content type is disabled by default
self.assertEqual(conversation.enabled(), False)
# Allow discussion on Document content type
portal_types = getToolByName(self.portal, 'portal_types')
document_fti = getattr(portal_types, 'Document')
portal_types = getToolByName(self.portal, "portal_types")
document_fti = getattr(portal_types, "Document")
document_fti.manage_changeProperties(allow_discussion=True)
# Check if conversation is enabled now
self.assertEqual(conversation.enabled(), True)
# Disallow discussion on Document content type
portal_types = getToolByName(self.portal, 'portal_types')
document_fti = getattr(portal_types, 'Document')
portal_types = getToolByName(self.portal, "portal_types")
document_fti = getattr(portal_types, "Document")
document_fti.manage_changeProperties(allow_discussion=False)
# Check if conversation is enabled now
@@ -306,17 +298,17 @@ class ConversationTest(unittest.TestCase):
# plone.app.contenttypes does not have this restriction any longer.
# Create a folder
self.typetool.constructContent('Folder', self.portal, 'f1')
self.typetool.constructContent("Folder", self.portal, "f1")
# Usually we don't create a conversation on a folder
conversation = self.portal.f1.restrictedTraverse('@@conversation_view')
conversation = self.portal.f1.restrictedTraverse("@@conversation_view")
# Allow discussion for the folder
self.portal.f1.allow_discussion = True
# Allow discussion on Folder content type
portal_types = getToolByName(self.portal, 'portal_types')
document_fti = getattr(portal_types, 'Folder')
portal_types = getToolByName(self.portal, "portal_types")
document_fti = getattr(portal_types, "Folder")
document_fti.manage_changeProperties(allow_discussion=True)
self.assertTrue(conversation.enabled())
@@ -326,7 +318,7 @@ class ConversationTest(unittest.TestCase):
# Create a conversation.
conversation = self.portal.doc1.restrictedTraverse(
'@@conversation_view',
"@@conversation_view",
)
# Discussion is disallowed by default
@@ -351,13 +343,13 @@ class ConversationTest(unittest.TestCase):
# Add a comment. Note: in real life, we always create comments via the
# factory to allow different factories to be swapped in
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
new_id1 = conversation.addComment(comment1)
comment2 = createObject('plone.Comment')
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.text = "Comment text"
new_id2 = conversation.addComment(comment2)
@@ -384,17 +376,17 @@ class ConversationTest(unittest.TestCase):
self.assertTrue(comment2 in conversation.values())
# check if comment ids are in iterkeys
self.assertTrue(new_id1 in six.iterkeys(conversation))
self.assertTrue(new_id2 in six.iterkeys(conversation))
self.assertFalse(123 in six.iterkeys(conversation))
self.assertTrue(new_id1 in conversation.keys())
self.assertTrue(new_id2 in conversation.keys())
self.assertFalse(123 in conversation.keys())
# check if comment objects are in itervalues
self.assertTrue(comment1 in six.itervalues(conversation))
self.assertTrue(comment2 in six.itervalues(conversation))
self.assertTrue(comment1 in conversation.values())
self.assertTrue(comment2 in conversation.values())
# check if iteritems returns (key, comment object) pairs
self.assertTrue((new_id1, comment1) in six.iteritems(conversation))
self.assertTrue((new_id2, comment2) in six.iteritems(conversation))
self.assertTrue((new_id1, comment1) in conversation.items())
self.assertTrue((new_id2, comment2) in conversation.items())
# TODO test acquisition wrapping # noqa T000
# self.assertTrue(aq_base(aq_parent(comment1)) is conversation)
@@ -408,14 +400,14 @@ class ConversationTest(unittest.TestCase):
# comments via the factory to allow different factories to be
# swapped in
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
comment2 = createObject('plone.Comment')
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.text = "Comment text"
comment3 = createObject('plone.Comment')
comment3.text = 'Comment text'
comment3 = createObject("plone.Comment")
comment3.text = "Comment text"
conversation.addComment(comment1)
conversation.addComment(comment2)
@@ -437,49 +429,49 @@ class ConversationTest(unittest.TestCase):
# Note: in real life, we always create
# comments via the factory to allow different factories to be
# swapped in
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1.author_username = 'Jim'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
comment1.author_username = "Jim"
conversation.addComment(comment1)
comment2 = createObject('plone.Comment')
comment2.text = 'Comment text'
comment2.author_username = 'Joe'
comment2 = createObject("plone.Comment")
comment2.text = "Comment text"
comment2.author_username = "Joe"
conversation.addComment(comment2)
comment3 = createObject('plone.Comment')
comment3.text = 'Comment text'
comment3.author_username = 'Jack'
comment3 = createObject("plone.Comment")
comment3.text = "Comment text"
comment3.author_username = "Jack"
new_comment3_id = conversation.addComment(comment3)
comment4 = createObject('plone.Comment')
comment4.text = 'Comment text'
comment4.author_username = 'Jack'
comment4 = createObject("plone.Comment")
comment4.text = "Comment text"
comment4.author_username = "Jack"
new_comment4_id = conversation.addComment(comment4)
# check if all commentators are in the commentators list
self.assertEqual(conversation.total_comments(), 4)
self.assertTrue('Jim' in conversation.commentators)
self.assertTrue('Joe' in conversation.commentators)
self.assertTrue('Jack' in conversation.commentators)
self.assertTrue("Jim" in conversation.commentators)
self.assertTrue("Joe" in conversation.commentators)
self.assertTrue("Jack" in conversation.commentators)
# remove the comment from Jack
del conversation[new_comment3_id]
# check if Jack is still in the commentators list (since
# he had added two comments)
self.assertTrue('Jim' in conversation.commentators)
self.assertTrue('Joe' in conversation.commentators)
self.assertTrue('Jack' in conversation.commentators)
self.assertTrue("Jim" in conversation.commentators)
self.assertTrue("Joe" in conversation.commentators)
self.assertTrue("Jack" in conversation.commentators)
self.assertEqual(conversation.total_comments(), 3)
# remove the second comment from Jack
del conversation[new_comment4_id]
# check if Jack has been removed from the commentators list
self.assertTrue('Jim' in conversation.commentators)
self.assertTrue('Joe' in conversation.commentators)
self.assertFalse('Jack' in conversation.commentators)
self.assertTrue("Jim" in conversation.commentators)
self.assertTrue("Joe" in conversation.commentators)
self.assertFalse("Jack" in conversation.commentators)
self.assertEqual(conversation.total_comments(), 2)
def test_last_comment_date(self):
@@ -494,29 +486,29 @@ class ConversationTest(unittest.TestCase):
# Note: in real life, we always create
# comments via the factory to allow different factories to be
# swapped in
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
comment1.creation_date = datetime.utcnow() - timedelta(4)
conversation.addComment(comment1)
comment2 = createObject('plone.Comment')
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.text = "Comment text"
comment2.creation_date = datetime.utcnow() - timedelta(2)
new_comment2_id = conversation.addComment(comment2)
comment3 = createObject('plone.Comment')
comment3.text = 'Comment text'
comment3 = createObject("plone.Comment")
comment3.text = "Comment text"
comment3.creation_date = datetime.utcnow() - timedelta(1)
new_comment3_id = conversation.addComment(comment3)
# check if the latest comment is exactly one day old
self.assertTrue(
conversation.last_comment_date < datetime.utcnow() -
timedelta(hours=23, minutes=59, seconds=59),
conversation.last_comment_date
< datetime.utcnow() - timedelta(hours=23, minutes=59, seconds=59),
)
self.assertTrue(
conversation.last_comment_date >
datetime.utcnow() - timedelta(days=1, seconds=1),
conversation.last_comment_date
> datetime.utcnow() - timedelta(days=1, seconds=1),
)
# remove the latest comment
@@ -525,12 +517,12 @@ class ConversationTest(unittest.TestCase):
# check if the latest comment has been updated
# the latest comment should be exactly two days old
self.assertTrue(
conversation.last_comment_date < datetime.utcnow() -
timedelta(days=1, hours=23, minutes=59, seconds=59),
conversation.last_comment_date
< datetime.utcnow() - timedelta(days=1, hours=23, minutes=59, seconds=59),
)
self.assertTrue(
conversation.last_comment_date > datetime.utcnow() -
timedelta(days=2, seconds=1),
conversation.last_comment_date
> datetime.utcnow() - timedelta(days=2, seconds=1),
)
# remove the latest comment again
@@ -539,12 +531,12 @@ class ConversationTest(unittest.TestCase):
# check if the latest comment has been updated
# the latest comment should be exactly four days old
self.assertTrue(
conversation.last_comment_date < datetime.utcnow() -
timedelta(days=3, hours=23, minutes=59, seconds=59),
conversation.last_comment_date
< datetime.utcnow() - timedelta(days=3, hours=23, minutes=59, seconds=59),
)
self.assertTrue(
conversation.last_comment_date > datetime.utcnow() -
timedelta(days=4, seconds=2),
conversation.last_comment_date
> datetime.utcnow() - timedelta(days=4, seconds=2),
)
def test_get_comments_full(self):
@@ -572,23 +564,23 @@ class ConversationTest(unittest.TestCase):
# +- Comment 2_1
# Create all comments
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
comment1_1 = createObject('plone.Comment')
comment1_1.text = 'Comment text'
comment1_1 = createObject("plone.Comment")
comment1_1.text = "Comment text"
comment1_1_1 = createObject('plone.Comment')
comment1_1_1.text = 'Comment text'
comment1_1_1 = createObject("plone.Comment")
comment1_1_1.text = "Comment text"
comment1_2 = createObject('plone.Comment')
comment1_2.text = 'Comment text'
comment1_2 = createObject("plone.Comment")
comment1_2.text = "Comment text"
comment2 = createObject('plone.Comment')
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.text = "Comment text"
comment2_1 = createObject('plone.Comment')
comment2_1.text = 'Comment text'
comment2_1 = createObject("plone.Comment")
comment2_1.text = "Comment text"
# Create the nested comment structure
new_id_1 = conversation.addComment(comment1)
@@ -608,14 +600,17 @@ class ConversationTest(unittest.TestCase):
# Get threads
self.assertEqual([
{'comment': comment1, 'depth': 0, 'id': new_id_1},
{'comment': comment1_1, 'depth': 1, 'id': new_id_1_1},
{'comment': comment1_1_1, 'depth': 2, 'id': new_id_1_1_1},
{'comment': comment1_2, 'depth': 1, 'id': new_id_1_2},
{'comment': comment2, 'depth': 0, 'id': new_id_2},
{'comment': comment2_1, 'depth': 1, 'id': new_id_2_1},
], list(conversation.getThreads()))
self.assertEqual(
[
{"comment": comment1, "depth": 0, "id": new_id_1},
{"comment": comment1_1, "depth": 1, "id": new_id_1_1},
{"comment": comment1_1_1, "depth": 2, "id": new_id_1_1_1},
{"comment": comment1_2, "depth": 1, "id": new_id_1_2},
{"comment": comment2, "depth": 0, "id": new_id_2},
{"comment": comment2_1, "depth": 1, "id": new_id_2_1},
],
list(conversation.getThreads()),
)
def test_get_threads_batched(self):
# TODO: test start, size, root and depth arguments to getThreads() # noqa T000
@@ -626,16 +621,16 @@ class ConversationTest(unittest.TestCase):
# make sure we can traverse to conversations and get a URL and path
conversation = self.portal.doc1.restrictedTraverse(
'++conversation++default',
"++conversation++default",
)
self.assertTrue(IConversation.providedBy(conversation))
self.assertEqual(
('', 'plone', 'doc1', '++conversation++default'),
("", "plone", "doc1", "++conversation++default"),
conversation.getPhysicalPath(),
)
self.assertEqual(
'http://nohost/plone/doc1/++conversation++default',
"http://nohost/plone/doc1/++conversation++default",
conversation.absolute_url(),
)
@@ -644,7 +639,7 @@ class ConversationTest(unittest.TestCase):
# can't be converted to int
conversation = self.portal.doc1.restrictedTraverse(
'++conversation++default/ThisCantBeRight',
"++conversation++default/ThisCantBeRight",
)
self.assertEqual(conversation, None)
@@ -658,17 +653,16 @@ class ConversationTest(unittest.TestCase):
self.assertTrue(conversation.__parent__)
self.assertTrue(aq_parent(conversation))
self.assertEqual(conversation.__parent__.getId(), 'doc1')
self.assertEqual(conversation.__parent__.getId(), "doc1")
def test_discussion_item_not_in_bad_types(self):
self.assertFalse('Discussion Item' in BAD_TYPES)
self.assertFalse("Discussion Item" in BAD_TYPES)
def test_no_comment(self):
IConversation(self.portal.doc1)
# Make sure no conversation has been created
self.assertTrue(
'plone.app.discussion:conversation' not in
IAnnotations(self.portal.doc1),
"plone.app.discussion:conversation" not in IAnnotations(self.portal.doc1),
)
@@ -677,21 +671,20 @@ class ConversationEnabledForDexterityTypesTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
interface.alsoProvides(
self.portal.REQUEST,
interfaces.IDiscussionLayer,
IDiscussionLayer,
)
if DEXTERITY:
interface.alsoProvides(
self.portal.doc1,
IDexterityContent,
)
interface.alsoProvides(
self.portal.doc1,
IDexterityContent,
)
def _makeOne(self, *args, **kw):
return self.portal.doc1.restrictedTraverse('@@conversation_view')
return self.portal.doc1.restrictedTraverse("@@conversation_view")
def _globally_enable_discussion(self, value):
registry = queryUtility(IRegistry)
@@ -699,43 +692,38 @@ class ConversationEnabledForDexterityTypesTest(unittest.TestCase):
settings.globally_enabled = value
def _enable_discussion_on_portal_type(self, portal_type, allow_discussion):
portal_types = getToolByName(self.portal, 'portal_types')
portal_types = getToolByName(self.portal, "portal_types")
document_fti = getattr(portal_types, portal_type)
document_fti.manage_changeProperties(allow_discussion=allow_discussion)
def test_conversation_is_not_enabled_by_default(self):
if DEXTERITY:
conversation = self._makeOne(self.portal.doc1)
self.assertFalse(conversation.enabled())
conversation = self._makeOne(self.portal.doc1)
self.assertFalse(conversation.enabled())
def test_conversation_is_not_enabled_by_default_on_portal_type(self):
if DEXTERITY:
self._globally_enable_discussion(True)
conversation = self._makeOne(self.portal.doc1)
self.assertFalse(conversation.enabled())
self._globally_enable_discussion(True)
conversation = self._makeOne(self.portal.doc1)
self.assertFalse(conversation.enabled())
def test_conversation_needs_to_be_enabled_globally_and_for_type(self):
if DEXTERITY:
self._globally_enable_discussion(True)
self._enable_discussion_on_portal_type('Document', True)
conversation = self._makeOne(self.portal.doc1)
self.assertTrue(conversation.enabled())
self._globally_enable_discussion(True)
self._enable_discussion_on_portal_type("Document", True)
conversation = self._makeOne(self.portal.doc1)
self.assertTrue(conversation.enabled())
def test_disable_discussion(self):
if DEXTERITY:
self._globally_enable_discussion(True)
self._enable_discussion_on_portal_type('Document', True)
self.portal.doc1.allow_discussion = False
conversation = self._makeOne(self.portal.doc1)
self.assertFalse(conversation.enabled())
self._globally_enable_discussion(True)
self._enable_discussion_on_portal_type("Document", True)
self.portal.doc1.allow_discussion = False
conversation = self._makeOne(self.portal.doc1)
self.assertFalse(conversation.enabled())
def test_enable_discussion(self):
if DEXTERITY:
self._globally_enable_discussion(True)
self._enable_discussion_on_portal_type('Document', True)
self.portal.doc1.allow_discussion = True
conversation = self._makeOne(self.portal.doc1)
self.assertTrue(conversation.enabled())
self._globally_enable_discussion(True)
self._enable_discussion_on_portal_type("Document", True)
self.portal.doc1.allow_discussion = True
conversation = self._makeOne(self.portal.doc1)
self.assertTrue(conversation.enabled())
class RepliesTest(unittest.TestCase):
@@ -745,11 +733,11 @@ class RepliesTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
workflow.doActionFor(self.portal.doc1, "publish")
def test_add_comment(self):
# Add comments to a ConversationReplies adapter
@@ -760,8 +748,8 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(conversation)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = replies.addComment(comment)
@@ -787,8 +775,8 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(conversation)
# Add a comment.
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = replies.addComment(comment)
@@ -826,39 +814,39 @@ class RepliesTest(unittest.TestCase):
# +- Comment 2_1
# Create all comments
comment1 = createObject('plone.Comment')
comment1.text = 'Comment text'
comment1 = createObject("plone.Comment")
comment1.text = "Comment text"
comment1_1 = createObject('plone.Comment')
comment1_1.text = 'Comment text'
comment1_1 = createObject("plone.Comment")
comment1_1.text = "Comment text"
comment1_1_1 = createObject('plone.Comment')
comment1_1_1.text = 'Comment text'
comment1_1_1 = createObject("plone.Comment")
comment1_1_1.text = "Comment text"
comment1_2 = createObject('plone.Comment')
comment1_2.text = 'Comment text'
comment1_2 = createObject("plone.Comment")
comment1_2.text = "Comment text"
comment2 = createObject('plone.Comment')
comment2.text = 'Comment text'
comment2 = createObject("plone.Comment")
comment2.text = "Comment text"
comment2_1 = createObject('plone.Comment')
comment2_1.text = 'Comment text'
comment2_1 = createObject("plone.Comment")
comment2_1.text = "Comment text"
# Create the nested comment structure
new_id_1 = replies.addComment(comment1)
comment1 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_1),
f"++conversation++default/{new_id_1}",
)
replies_to_comment1 = IReplies(comment1)
new_id_2 = replies.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_2),
f"++conversation++default/{new_id_2}",
)
replies_to_comment2 = IReplies(comment2)
new_id_1_1 = replies_to_comment1.addComment(comment1_1)
comment1_1 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_1_1),
f"++conversation++default/{new_id_1_1}",
)
replies_to_comment1_1 = IReplies(comment1_1)
replies_to_comment1_1.addComment(comment1_1_1)
+40 -40
View File
@@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IReplies
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from ..interfaces import IConversation
from ..interfaces import IReplies
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from Zope2.App import zcml
@@ -18,9 +17,9 @@ import unittest
#
class EventsRegistry(object):
""" Fake registry to be used while testing discussion events
"""
class EventsRegistry:
"""Fake registry to be used while testing discussion events"""
commentAdded = False
commentModified = False
commentRemoved = False
@@ -28,6 +27,7 @@ class EventsRegistry(object):
replyModified = False
replyRemoved = False
#
# Fake event handlers
#
@@ -63,19 +63,19 @@ def reply_removed(doc, evt):
class CommentEventsTest(unittest.TestCase):
""" Test custom comments events
"""
"""Test custom comments events"""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
# Setup sandbox
self.portal = self.layer['portal']
self.request = self.layer['request']
self.portal = self.layer["portal"]
self.request = self.layer["request"]
self.registry = EventsRegistry
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.document = self.portal['doc1']
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.document = self.portal["doc1"]
#
# Subscribers
@@ -104,23 +104,23 @@ class CommentEventsTest(unittest.TestCase):
</configure>
"""
zcml.load_config('configure.zcml', Products.Five)
zcml.load_config("configure.zcml", Products.Five)
zcml.load_string(configure)
def test_addEvent(self):
self.assertFalse(self.registry.commentAdded)
comment = createObject('plone.Comment')
comment = createObject("plone.Comment")
conversation = IConversation(self.document)
conversation.addComment(comment)
self.assertTrue(self.registry.commentAdded)
def test_modifyEvent(self):
self.assertFalse(self.registry.commentModified)
comment = createObject('plone.Comment')
comment = createObject("plone.Comment")
conversation = IConversation(self.document)
new_id = conversation.addComment(comment)
comment = self.document.restrictedTraverse(
'++conversation++default/{0}'.format(new_id),
f"++conversation++default/{new_id}",
)
comment.text = "foo"
notify(ObjectModifiedEvent(comment))
@@ -128,7 +128,7 @@ class CommentEventsTest(unittest.TestCase):
def test_removedEvent(self):
self.assertFalse(self.registry.commentRemoved)
comment = createObject('plone.Comment')
comment = createObject("plone.Comment")
conversation = IConversation(self.document)
cid = conversation.addComment(comment)
del conversation[cid]
@@ -136,17 +136,17 @@ class CommentEventsTest(unittest.TestCase):
class RepliesEventsTest(unittest.TestCase):
""" Test custom replies events
"""
"""Test custom replies events"""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
self.request = self.layer['request']
self.portal = self.layer["portal"]
self.request = self.layer["request"]
self.registry = EventsRegistry
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.document = self.portal['doc1']
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.document = self.portal["doc1"]
#
# Subscribers
@@ -175,7 +175,7 @@ class RepliesEventsTest(unittest.TestCase):
</configure>
"""
zcml.load_config('configure.zcml', Products.Five)
zcml.load_config("configure.zcml", Products.Five)
zcml.load_string(configure)
def test_addEvent(self):
@@ -184,15 +184,15 @@ class RepliesEventsTest(unittest.TestCase):
conversation = IConversation(self.document)
replies = IReplies(conversation)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = replies.addComment(comment)
comment = self.document.restrictedTraverse(
'++conversation++default/{0}'.format(new_id),
f"++conversation++default/{new_id}",
)
re_comment = createObject('plone.Comment')
re_comment.text = 'Comment text'
re_comment = createObject("plone.Comment")
re_comment.text = "Comment text"
replies = IReplies(comment)
replies.addComment(re_comment)
@@ -204,14 +204,14 @@ class RepliesEventsTest(unittest.TestCase):
conversation = IConversation(self.document)
replies = IReplies(conversation)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment_id = replies.addComment(comment)
comment = self.document.restrictedTraverse(
'++conversation++default/{0}'.format(comment_id),
f"++conversation++default/{comment_id}",
)
re_comment = createObject('plone.Comment')
re_comment.text = 'Comment text'
re_comment = createObject("plone.Comment")
re_comment.text = "Comment text"
replies = IReplies(comment)
new_id = replies.addComment(re_comment)
reply = replies[new_id]
@@ -225,15 +225,15 @@ class RepliesEventsTest(unittest.TestCase):
conversation = IConversation(self.portal.doc1)
replies = IReplies(conversation)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id),
f"++conversation++default/{new_id}",
)
re_comment = createObject('plone.Comment')
re_comment.text = 'Comment text'
re_comment = createObject("plone.Comment")
re_comment.text = "Comment text"
replies = IReplies(comment)
new_re_id = replies.addComment(re_comment)
+19 -20
View File
@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*-
"""Functional Doctests for plone.app.discussion.
These test are only triggered when Plone 4 (and plone.testing) is installed.
"""
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING # noqa
from ..testing import PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING # noqa
from plone.testing import layered
import doctest
@@ -12,29 +11,29 @@ import unittest
optionflags = (
doctest.ELLIPSIS |
doctest.NORMALIZE_WHITESPACE |
doctest.REPORT_ONLY_FIRST_FAILURE
doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE | doctest.REPORT_ONLY_FIRST_FAILURE
)
normal_testfiles = [
'functional_test_comments.txt',
'functional_test_comment_review_workflow.txt',
"functional_test_comments.txt",
"functional_test_comment_review_workflow.txt",
]
def test_suite():
suite = unittest.TestSuite()
suite.addTests([
layered(
doctest.DocFileSuite(
test,
optionflags=optionflags,
globs={
'pprint': pprint.pprint,
}
),
layer=PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING,
)
for test in normal_testfiles
])
suite.addTests(
[
layered(
doctest.DocFileSuite(
test,
optionflags=optionflags,
globs={
"pprint": pprint.pprint,
},
),
layer=PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING,
)
for test in normal_testfiles
]
)
return suite
+56 -53
View File
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
"""Test for the plone.app.discussion indexers
"""
from DateTime import DateTime
from .. import catalog
from ..interfaces import IConversation
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from datetime import datetime
from plone.app.discussion import catalog
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from DateTime import DateTime
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.indexer.delegate import DelegatingIndexerFactory
@@ -26,41 +25,40 @@ sed diam voluptua. At [...]"""
class ConversationIndexersTest(unittest.TestCase):
"""Conversation Indexer Tests
"""
"""Conversation Indexer Tests"""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
workflow = self.portal.portal_workflow
workflow.doActionFor(self.portal.doc1, 'publish')
workflow.doActionFor(self.portal.doc1, "publish")
# Create a conversation.
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1.text = 'Comment Text'
comment1.creator = 'jim'
comment1.author_username = 'Jim'
comment1 = createObject("plone.Comment")
comment1.text = "Comment Text"
comment1.creator = "jim"
comment1.author_username = "Jim"
comment1.creation_date = datetime(2006, 9, 17, 14, 18, 12)
comment1.modification_date = datetime(2006, 9, 17, 14, 18, 12)
self.new_id1 = conversation.addComment(comment1)
comment2 = createObject('plone.Comment')
comment2.text = 'Comment Text'
comment2.creator = 'emma'
comment2.author_username = 'Emma'
comment2 = createObject("plone.Comment")
comment2.text = "Comment Text"
comment2.creator = "emma"
comment2.author_username = "Emma"
comment2.creation_date = datetime(2007, 12, 13, 4, 18, 12)
comment2.modification_date = datetime(2007, 12, 13, 4, 18, 12)
self.new_id2 = conversation.addComment(comment2)
comment3 = createObject('plone.Comment')
comment3.text = 'Comment Text'
comment3.creator = 'lukas'
comment3.author_username = 'Lukas'
comment3 = createObject("plone.Comment")
comment3.text = "Comment Text"
comment3.creator = "lukas"
comment3.author_username = "Lukas"
comment3.creation_date = datetime(2009, 4, 12, 11, 12, 12)
comment3.modification_date = datetime(2009, 4, 12, 11, 12, 12)
self.new_id3 = conversation.addComment(comment3)
@@ -68,10 +66,12 @@ class ConversationIndexersTest(unittest.TestCase):
self.conversation = conversation
def test_conversation_total_comments(self):
self.assertTrue(isinstance(
catalog.total_comments,
DelegatingIndexerFactory,
))
self.assertTrue(
isinstance(
catalog.total_comments,
DelegatingIndexerFactory,
)
)
self.assertEqual(catalog.total_comments(self.portal.doc1)(), 3)
del self.conversation[self.new_id1]
self.assertEqual(catalog.total_comments(self.portal.doc1)(), 2)
@@ -80,10 +80,12 @@ class ConversationIndexersTest(unittest.TestCase):
self.assertEqual(catalog.total_comments(self.portal.doc1)(), 0)
def test_conversation_last_comment_date(self):
self.assertTrue(isinstance(
catalog.last_comment_date,
DelegatingIndexerFactory,
))
self.assertTrue(
isinstance(
catalog.last_comment_date,
DelegatingIndexerFactory,
)
)
self.assertEqual(
catalog.last_comment_date(self.portal.doc1)(),
datetime(2009, 4, 12, 11, 12, 12),
@@ -110,8 +112,8 @@ class CommentIndexersTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
# Create a conversation. In this case we doesn't assign it to an
# object, as we just want to check the Conversation object API.
@@ -120,10 +122,10 @@ class CommentIndexersTest(unittest.TestCase):
# Add a comment. Note: in real life, we always create comments via the
# factory to allow different factories to be swapped in
comment = createObject('plone.Comment')
comment.text = 'Lorem ipsum dolor sit amet.'
comment.creator = 'jim'
comment.author_name = 'Jim'
comment = createObject("plone.Comment")
comment.text = "Lorem ipsum dolor sit amet."
comment.creator = "jim"
comment.author_name = "Jim"
comment.creation_date = datetime(2006, 9, 17, 14, 18, 12)
comment.modification_date = datetime(2008, 3, 12, 7, 32, 52)
@@ -132,60 +134,61 @@ class CommentIndexersTest(unittest.TestCase):
self.conversation = conversation
def test_title(self):
self.assertEqual(catalog.title(self.comment)(), 'Jim on Document 1')
self.assertEqual(catalog.title(self.comment)(), "Jim on Document 1")
self.assertTrue(isinstance(catalog.title, DelegatingIndexerFactory))
def test_description(self):
self.assertEqual(
catalog.description(self.comment)(),
'Lorem ipsum dolor sit amet.',
"Lorem ipsum dolor sit amet.",
)
self.assertTrue(
isinstance(catalog.description, DelegatingIndexerFactory))
self.assertTrue(isinstance(catalog.description, DelegatingIndexerFactory))
def test_description_long(self):
# Create a 50 word comment and make sure the description returns
# only the first 25 words
comment_long = createObject('plone.Comment')
comment_long.title = 'Long Comment'
comment_long = createObject("plone.Comment")
comment_long.title = "Long Comment"
comment_long.text = LONG_TEXT
self.conversation.addComment(comment_long)
self.assertEqual(
catalog.description(comment_long)(),
LONG_TEXT_CUT.replace('\n', ' '),
LONG_TEXT_CUT.replace("\n", " "),
)
def test_dates(self):
# Test if created, modified, effective etc. are set correctly
self.assertEqual(
catalog.created(self.comment)(),
DateTime(2006, 9, 17, 14, 18, 12, 'GMT'),
DateTime(2006, 9, 17, 14, 18, 12, "GMT"),
)
self.assertEqual(
catalog.effective(self.comment)(),
DateTime(2006, 9, 17, 14, 18, 12, 'GMT'),
DateTime(2006, 9, 17, 14, 18, 12, "GMT"),
)
self.assertEqual(
catalog.modified(self.comment)(),
DateTime(2008, 3, 12, 7, 32, 52, 'GMT'),
DateTime(2008, 3, 12, 7, 32, 52, "GMT"),
)
def test_searchable_text(self):
# Test if searchable text is a concatenation of title and comment text
self.assertEqual(
catalog.searchable_text(self.comment)(),
('Lorem ipsum dolor sit amet.'),
("Lorem ipsum dolor sit amet."),
)
self.assertTrue(
isinstance(
catalog.searchable_text,
DelegatingIndexerFactory,
)
)
self.assertTrue(isinstance(
catalog.searchable_text,
DelegatingIndexerFactory,
))
def test_creator(self):
self.assertEqual(catalog.creator(self.comment)(), ('jim'))
self.assertEqual(catalog.creator(self.comment)(), ("jim"))
def test_in_response_to(self):
# make sure in_response_to returns the title or id of the content
# object the comment was added to
self.assertEqual(catalog.in_response_to(self.comment)(), 'Document 1')
self.assertEqual(catalog.in_response_to(self.comment)(), "Document 1")
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.browser.moderation import BulkActionsView
from plone.app.discussion.browser.moderation import DeleteComment
from plone.app.discussion.browser.moderation import CommentTransition
from plone.app.discussion.browser.moderation import View
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from ..browser.moderation import BulkActionsView
from ..browser.moderation import CommentTransition
from ..browser.moderation import DeleteComment
from ..browser.moderation import View
from ..interfaces import IConversation
from ..interfaces import IDiscussionSettings
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.registry.interfaces import IRegistry
@@ -21,59 +20,57 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.app = self.layer['app']
self.portal = self.layer['portal']
self.request = self.layer['request']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.wf = getToolByName(self.portal,
'portal_workflow',
None)
self.app = self.layer["app"]
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.wf = getToolByName(self.portal, "portal_workflow", None)
self.context = self.portal
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
'comment_review_workflow',
("Discussion Item",),
"comment_review_workflow",
)
self.wf_tool = self.portal.portal_workflow
# Add a conversation with three comments
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1.title = 'Comment 1'
comment1.text = 'Comment text'
comment1.Creator = 'Jim'
comment1 = createObject("plone.Comment")
comment1.title = "Comment 1"
comment1.text = "Comment text"
comment1.Creator = "Jim"
new_id_1 = conversation.addComment(comment1)
self.comment1 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_1),
f"++conversation++default/{new_id_1}",
)
comment2 = createObject('plone.Comment')
comment2.title = 'Comment 2'
comment2.text = 'Comment text'
comment2.Creator = 'Joe'
comment2 = createObject("plone.Comment")
comment2.title = "Comment 2"
comment2.text = "Comment text"
comment2.Creator = "Joe"
new_id_2 = conversation.addComment(comment2)
self.comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_2),
f"++conversation++default/{new_id_2}",
)
comment3 = createObject('plone.Comment')
comment3.title = 'Comment 3'
comment3.text = 'Comment text'
comment3.Creator = 'Emma'
comment3 = createObject("plone.Comment")
comment3.title = "Comment 3"
comment3.text = "Comment text"
comment3.Creator = "Emma"
new_id_3 = conversation.addComment(comment3)
self.comment3 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_3),
f"++conversation++default/{new_id_3}",
)
self.conversation = conversation
def test_default_bulkaction(self):
# Make sure no error is raised when no bulk actions has been supplied
self.request.set('form.select.BulkAction', '-1')
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
self.request.set("form.select.BulkAction", "-1")
self.request.set("paths", ["/".join(self.comment1.getPhysicalPath())])
view = BulkActionsView(self.portal, self.request)
self.assertFalse(view())
def test_publish(self):
self.request.set('form.select.BulkAction', 'publish')
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
self.request.set("form.select.BulkAction", "publish")
self.request.set("paths", ["/".join(self.comment1.getPhysicalPath())])
view = BulkActionsView(self.portal, self.request)
view()
@@ -81,16 +78,16 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
# Count published comments
published_comments = 0
for r in self.conversation.getThreads():
comment_obj = r['comment']
workflow_status = self.wf.getInfoFor(comment_obj, 'review_state')
if workflow_status == 'published':
comment_obj = r["comment"]
workflow_status = self.wf.getInfoFor(comment_obj, "review_state")
if workflow_status == "published":
published_comments += 1
# Make sure the comment has been published
self.assertEqual(published_comments, 1)
def test_mark_as_spam(self):
self.request.set('form.select.BulkAction', 'mark_as_spam')
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
self.request.set("form.select.BulkAction", "mark_as_spam")
self.request.set("paths", ["/".join(self.comment1.getPhysicalPath())])
view = BulkActionsView(self.portal, self.request)
@@ -99,9 +96,9 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
# Count spam comments
spam_comments = 0
for r in self.conversation.getThreads():
comment_obj = r['comment']
workflow_status = self.wf.getInfoFor(comment_obj, 'review_state')
if workflow_status == 'spam':
comment_obj = r["comment"]
workflow_status = self.wf.getInfoFor(comment_obj, "review_state")
if workflow_status == "spam":
spam_comments += 1
# Make sure the comment has been marked as spam
self.assertEqual(spam_comments, 1)
@@ -110,9 +107,14 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
# Initially we have three comments
self.assertEqual(len(self.conversation.objectIds()), 3)
# Delete two comments with bulk actions
self.request.set('form.select.BulkAction', 'delete')
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath()),
'/'.join(self.comment3.getPhysicalPath())])
self.request.set("form.select.BulkAction", "delete")
self.request.set(
"paths",
[
"/".join(self.comment1.getPhysicalPath()),
"/".join(self.comment3.getPhysicalPath()),
],
)
view = BulkActionsView(self.app, self.request)
view()
@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.browser.moderation import BulkActionsView
from plone.app.discussion.browser.moderation import DeleteComment
from plone.app.discussion.browser.moderation import CommentTransition
from plone.app.discussion.browser.moderation import View
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from ..browser.moderation import BulkActionsView
from ..browser.moderation import CommentTransition
from ..browser.moderation import DeleteComment
from ..browser.moderation import View
from ..interfaces import IConversation
from ..interfaces import IDiscussionSettings
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.registry.interfaces import IRegistry
@@ -21,37 +20,37 @@ class ModerationViewTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.app = self.layer['app']
self.portal = self.layer['portal']
self.request = self.layer['request']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal_discussion = getToolByName(self.portal,
'portal_discussion',
None)
self.membership_tool = getToolByName(self.portal,
'portal_membership')
self.app = self.layer["app"]
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.portal_discussion = getToolByName(self.portal, "portal_discussion", None)
self.membership_tool = getToolByName(self.portal, "portal_membership")
self.memberdata = self.portal.portal_memberdata
request = self.app.REQUEST
context = getattr(self.portal, 'doc1')
context = getattr(self.portal, "doc1")
self.view = View(context, request)
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), 'comment_review_workflow')
("Discussion Item",), "comment_review_workflow"
)
self.wf_tool = self.portal.portal_workflow
def test_moderation_enabled(self):
"""Make sure that moderation_enabled returns true if the comment
workflow implements a 'pending' state.
workflow implements a 'pending' state.
"""
# 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)
# The comment_one_state_workflow does not have a 'pending' state
self.wf_tool.setChainForPortalTypes(('Discussion Item',),
('comment_one_state_workflow,'))
self.wf_tool.setChainForPortalTypes(
("Discussion Item",), ("comment_one_state_workflow,")
)
self.assertEqual(self.view.moderation_enabled(), False)
# The comment_review_workflow does have a 'pending' state
self.wf_tool.setChainForPortalTypes(('Discussion Item',),
('comment_review_workflow,'))
self.wf_tool.setChainForPortalTypes(
("Discussion Item",), ("comment_review_workflow,")
)
self.assertEqual(self.view.moderation_enabled(), True)
@@ -60,59 +59,57 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.app = self.layer['app']
self.portal = self.layer['portal']
self.request = self.layer['request']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.wf = getToolByName(self.portal,
'portal_workflow',
None)
self.app = self.layer["app"]
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.wf = getToolByName(self.portal, "portal_workflow", None)
self.context = self.portal
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
'comment_review_workflow',
("Discussion Item",),
"comment_review_workflow",
)
self.wf_tool = self.portal.portal_workflow
# Add a conversation with three comments
conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment')
comment1.title = 'Comment 1'
comment1.text = 'Comment text'
comment1.Creator = 'Jim'
comment1 = createObject("plone.Comment")
comment1.title = "Comment 1"
comment1.text = "Comment text"
comment1.Creator = "Jim"
new_id_1 = conversation.addComment(comment1)
self.comment1 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_1),
f"++conversation++default/{new_id_1}",
)
comment2 = createObject('plone.Comment')
comment2.title = 'Comment 2'
comment2.text = 'Comment text'
comment2.Creator = 'Joe'
comment2 = createObject("plone.Comment")
comment2.title = "Comment 2"
comment2.text = "Comment text"
comment2.Creator = "Joe"
new_id_2 = conversation.addComment(comment2)
self.comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_2),
f"++conversation++default/{new_id_2}",
)
comment3 = createObject('plone.Comment')
comment3.title = 'Comment 3'
comment3.text = 'Comment text'
comment3.Creator = 'Emma'
comment3 = createObject("plone.Comment")
comment3.title = "Comment 3"
comment3.text = "Comment text"
comment3.Creator = "Emma"
new_id_3 = conversation.addComment(comment3)
self.comment3 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_3),
f"++conversation++default/{new_id_3}",
)
self.conversation = conversation
def test_default_bulkaction(self):
# Make sure no error is raised when no bulk actions has been supplied
self.request.set('form.select.BulkAction', '-1')
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
self.request.set("form.select.BulkAction", "-1")
self.request.set("paths", ["/".join(self.comment1.getPhysicalPath())])
view = BulkActionsView(self.portal, self.request)
self.assertFalse(view())
def test_publish(self):
self.request.set('form.select.BulkAction', 'publish')
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath())])
self.request.set("form.select.BulkAction", "publish")
self.request.set("paths", ["/".join(self.comment1.getPhysicalPath())])
view = BulkActionsView(self.portal, self.request)
view()
@@ -120,9 +117,9 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
# Count published comments
published_comments = 0
for r in self.conversation.getThreads():
comment_obj = r['comment']
workflow_status = self.wf.getInfoFor(comment_obj, 'review_state')
if workflow_status == 'published':
comment_obj = r["comment"]
workflow_status = self.wf.getInfoFor(comment_obj, "review_state")
if workflow_status == "published":
published_comments += 1
# Make sure the comment has been published
self.assertEqual(published_comments, 1)
@@ -131,9 +128,14 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
# Initially we have three comments
self.assertEqual(len(self.conversation.objectIds()), 3)
# Delete two comments with bulk actions
self.request.set('form.select.BulkAction', 'delete')
self.request.set('paths', ['/'.join(self.comment1.getPhysicalPath()),
'/'.join(self.comment3.getPhysicalPath())])
self.request.set("form.select.BulkAction", "delete")
self.request.set(
"paths",
[
"/".join(self.comment1.getPhysicalPath()),
"/".join(self.comment3.getPhysicalPath()),
],
)
view = BulkActionsView(self.app, self.request)
view()
@@ -151,41 +153,41 @@ class RedirectionTest(unittest.TestCase):
def setUp(self):
# Update settings.
self.portal = self.layer['portal']
self.request = self.layer['request']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
self.request = self.layer["request"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
# applyProfile(self.portal, 'plone.app.discussion:default')
registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings)
settings.globally_enabled = True
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
('comment_review_workflow',),
("Discussion Item",),
("comment_review_workflow",),
)
# Create page plus comment.
self.portal.invokeFactory(
id='page',
title='Page 1',
type_name='Document',
id="page",
title="Page 1",
type_name="Document",
)
self.page = self.portal.page
self.conversation = IConversation(self.page)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
self.comment_id = self.conversation.addComment(comment)
self.comment = list(self.conversation.getComments())[0]
def test_regression(self):
page_url = self.page.absolute_url()
self.request['HTTP_REFERER'] = page_url
self.request["HTTP_REFERER"] = page_url
for Klass in (DeleteComment, CommentTransition):
view = Klass(self.comment, self.request)
view.__parent__ = self.comment
self.assertEqual(page_url, view())
def test_valid_next_url(self):
self.request['HTTP_REFERER'] = 'http://attacker.com'
self.request["HTTP_REFERER"] = "http://attacker.com"
for Klass in (DeleteComment, CommentTransition):
view = Klass(self.comment, self.request)
view.__parent__ = self.comment
self.assertNotEqual('http://attacker.com', view())
self.assertNotEqual("http://attacker.com", view())
+127 -111
View File
@@ -1,13 +1,14 @@
# -*- coding: utf-8 -*-
from ..interfaces import IConversation
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from Acquisition import aq_base
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from persistent.list import PersistentList
from plone.app.testing import setRoles
from plone.app.testing import TEST_USER_ID
from plone.base.interfaces import IMailSchema
from plone.registry.interfaces import IRegistry
from Products.CMFPlone.interfaces import IMailSchema
from Products.CMFPlone.tests.utils import MockMailHost
from Products.MailHost.interfaces import IMailHost
from Products.MailHost.MailHost import _mungeHeaders
from Products.MailHost.MailHost import MailBase
from zope.component import createObject
from zope.component import getSiteManager
from zope.component import getUtility
@@ -16,50 +17,85 @@ from zope.component import queryUtility
import unittest
class MockMailHost(MailBase):
"""A MailHost that collects messages instead of sending them."""
def __init__(self, id):
self.reset()
def reset(self):
self.messages = PersistentList()
def _send(self, mfrom, mto, messageText, immediate=False):
"""Send the message"""
self.messages.append(messageText)
def send(
self,
messageText,
mto=None,
mfrom=None,
subject=None,
encode=None,
immediate=False,
charset=None,
msg_type=None,
):
"""send *messageText* modified by the other parameters.
*messageText* can either be an ``email.message.Message``
or a string.
Note that Products.MailHost 4.10 had changes here.
"""
msg, mto, mfrom = _mungeHeaders(
messageText, mto, mfrom, subject, charset, msg_type, encode
)
self.messages.append(msg)
class TestUserNotificationUnit(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
# Set up a mock mailhost
self.portal._original_MailHost = self.portal.MailHost
self.portal.MailHost = mailhost = MockMailHost('MailHost')
self.portal.MailHost = mailhost = MockMailHost("MailHost")
sm = getSiteManager(context=self.portal)
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(mailhost, provided=IMailHost)
# We need to fake a valid mail setup
registry = getUtility(IRegistry)
mail_settings = registry.forInterface(IMailSchema, prefix='plone')
mail_settings.email_from_address = 'portal@plone.test'
mail_settings = registry.forInterface(IMailSchema, prefix="plone")
mail_settings.email_from_address = "portal@plone.test"
self.mailhost = self.portal.MailHost
# Enable user notification setting
registry = queryUtility(IRegistry)
registry['plone.app.discussion.interfaces.IDiscussionSettings' +
'.user_notification_enabled'] = True
# Archetypes content types store data as utf-8 encoded strings
# The missing u in front of a string is therefor not missing
self.portal.doc1.title = 'Kölle Alaaf' # What is 'Fasching'?
registry[
"plone.app.discussion.interfaces.IDiscussionSettings"
+ ".user_notification_enabled"
] = True
self.portal.doc1.title = "Kölle Alaaf" # What is 'Fasching'?
self.conversation = IConversation(self.portal.doc1)
def beforeTearDown(self):
self.portal.MailHost = self.portal._original_MailHost
sm = getSiteManager(context=self.portal)
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(aq_base(self.portal._original_MailHost),
provided=IMailHost)
sm.registerUtility(aq_base(self.portal._original_MailHost), provided=IMailHost)
def test_notify_user(self):
# Add a comment with user notification enabled. Add another comment
# and make sure an email is send to the user of the first comment.
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.user_notification = True
comment.author_email = 'john@plone.test'
comment.author_email = "john@plone.test"
self.conversation.addComment(comment)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment_id = self.conversation.addComment(comment)
@@ -67,52 +103,46 @@ class TestUserNotificationUnit(unittest.TestCase):
self.assertTrue(self.mailhost.messages[0])
msg = self.mailhost.messages[0]
msg = msg.decode("utf-8")
self.assertIn('To: john@plone.test', msg)
self.assertIn('From: portal@plone.test', msg)
self.assertIn("To: john@plone.test", msg)
self.assertIn("From: portal@plone.test", msg)
# We expect the headers to be properly header encoded (7-bit):
self.assertIn(
'Subject: =?utf-8?q?A_comment_has_been_posted=2E?=',
msg)
self.assertIn("Subject: =?utf-8?q?A_comment_has_been_posted=2E?=", msg)
# The output should be encoded in a reasonable manner
# (in this case quoted-printable).
# Depending on which Python version and which Products.MailHost version,
# you may get lines separated by '\n' or '\r\n' in here.
msg = msg.replace('\r\n', '\n')
self.assertIn(
'A comment on "K=C3=B6lle Alaaf" has been posted here:',
msg)
self.assertIn(
'http://nohost/plone/d=\noc1/view#{0}'.format(comment_id),
msg)
self.assertIn('Comment text', msg)
self.assertNotIn('Approve comment', msg)
self.assertNotIn('Delete comment', msg)
msg = msg.replace("\r\n", "\n")
self.assertIn('A comment on "K=C3=B6lle Alaaf" has been posted here:', msg)
self.assertIn(f"http://nohost/plone/d=\noc1/view#{comment_id}", msg)
self.assertIn("Comment text", msg)
self.assertNotIn("Approve comment", msg)
self.assertNotIn("Delete comment", msg)
def test_do_not_notify_user_when_notification_is_disabled(self):
registry = queryUtility(IRegistry)
registry[
'plone.app.discussion.interfaces.IDiscussionSettings.' +
'user_notification_enabled'
"plone.app.discussion.interfaces.IDiscussionSettings."
+ "user_notification_enabled"
] = False
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.user_notification = True
comment.author_email = 'john@plone.test'
comment.author_email = "john@plone.test"
self.conversation.addComment(comment)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
self.conversation.addComment(comment)
self.assertEqual(len(self.mailhost.messages), 0)
def test_do_not_notify_user_when_email_address_is_given(self):
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.user_notification = True
self.conversation.addComment(comment)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
self.conversation.addComment(comment)
@@ -122,15 +152,15 @@ class TestUserNotificationUnit(unittest.TestCase):
# Set sender mail address to none and make sure no email is send to
# the moderator.
registry = getUtility(IRegistry)
mail_settings = registry.forInterface(IMailSchema, prefix='plone')
mail_settings = registry.forInterface(IMailSchema, prefix="plone")
mail_settings.email_from_address = None
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.user_notification = True
comment.author_email = 'john@plone.test'
comment.author_email = "john@plone.test"
self.conversation.addComment(comment)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
self.conversation.addComment(comment)
self.assertEqual(len(self.mailhost.messages), 0)
@@ -139,15 +169,15 @@ class TestUserNotificationUnit(unittest.TestCase):
# When a user has added two comments in a conversation and has
# both times requested email notification, do not send him two
# emails when another comment has been added.
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.user_notification = True
comment.author_email = 'john@plone.test'
comment.author_email = "john@plone.test"
self.conversation.addComment(comment)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.user_notification = True
comment.author_email = 'john@plone.test'
comment.author_email = "john@plone.test"
self.conversation.addComment(comment)
@@ -163,48 +193,45 @@ class TestModeratorNotificationUnit(unittest.TestCase):
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
# Set up a mock mailhost
self.portal._original_MailHost = self.portal.MailHost
self.portal.MailHost = mailhost = MockMailHost('MailHost')
self.portal.MailHost = mailhost = MockMailHost("MailHost")
sm = getSiteManager(context=self.portal)
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(mailhost, provided=IMailHost)
# We need to fake a valid mail setup
registry = getUtility(IRegistry)
mail_settings = registry.forInterface(IMailSchema, prefix='plone')
mail_settings.email_from_address = 'portal@plone.test'
mail_settings = registry.forInterface(IMailSchema, prefix="plone")
mail_settings.email_from_address = "portal@plone.test"
self.mailhost = self.portal.MailHost
# Enable comment moderation
self.portal.portal_types['Document'].allow_discussion = True
self.portal.portal_types["Document"].allow_discussion = True
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
('comment_review_workflow',),
("Discussion Item",),
("comment_review_workflow",),
)
# Enable moderator notification setting
registry = queryUtility(IRegistry)
registry[
'plone.app.discussion.interfaces.IDiscussionSettings.' +
'moderator_notification_enabled'
"plone.app.discussion.interfaces.IDiscussionSettings."
+ "moderator_notification_enabled"
] = True
# Archetypes content types store data as utf-8 encoded strings
# The missing u in front of a string is therefor not missing
self.portal.doc1.title = 'Kölle Alaaf' # What is 'Fasching'?
self.portal.doc1.title = "Kölle Alaaf" # What is 'Fasching'?
self.conversation = IConversation(self.portal.doc1)
def beforeTearDown(self):
self.portal.MailHost = self.portal._original_MailHost
sm = getSiteManager(context=self.portal)
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(aq_base(self.portal._original_MailHost),
provided=IMailHost)
sm.registerUtility(aq_base(self.portal._original_MailHost), provided=IMailHost)
def test_notify_moderator(self):
"""Add a comment and make sure an email is send to the moderator."""
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment.author_email = 'john@plone.test'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment.author_email = "john@plone.test"
comment_id = self.conversation.addComment(comment)
@@ -212,54 +239,41 @@ class TestModeratorNotificationUnit(unittest.TestCase):
self.assertTrue(self.mailhost.messages[0])
msg = self.mailhost.messages[0]
msg = msg.decode("utf-8")
self.assertTrue('To: portal@plone.test' in msg)
self.assertTrue('From: portal@plone.test' in msg)
self.assertTrue("To: portal@plone.test" in msg)
self.assertTrue("From: portal@plone.test" in msg)
# We expect the headers to be properly header encoded (7-bit):
self.assertTrue(
'Subject: =?utf-8?q?A_comment_has_been_posted=2E?='
in msg)
self.assertTrue("Subject: =?utf-8?q?A_comment_has_been_posted=2E?=" in msg)
# The output should be encoded in a reasonable manner
# (in this case quoted-printable):
self.assertTrue(
'A comment on "K=C3=B6lle Alaaf" has been posted'
in msg
)
self.assertIn(
'http://nohost/plone/doc1/view#{0}'.format(comment_id),
msg
)
self.assertIn(
comment.author_email,
msg
)
self.assertIn(
comment.text,
msg
)
self.assertTrue('A comment on "K=C3=B6lle Alaaf" has been posted' in msg)
self.assertIn(f"http://nohost/plone/doc1/view#{comment_id}", msg)
self.assertIn(comment.author_email, msg)
self.assertIn(comment.text, msg)
def test_notify_moderator_specific_address(self):
# A moderator email address can be specified in the control panel.
registry = queryUtility(IRegistry)
registry['plone.app.discussion.interfaces.IDiscussionSettings' +
'.moderator_email'] = 'test@example.com'
comment = createObject('plone.Comment')
comment.text = 'Comment text'
registry[
"plone.app.discussion.interfaces.IDiscussionSettings" + ".moderator_email"
] = "test@example.com"
comment = createObject("plone.Comment")
comment.text = "Comment text"
self.conversation.addComment(comment)
self.assertEqual(len(self.mailhost.messages), 1)
msg = self.mailhost.messages[0]
msg = msg.decode("utf-8")
self.assertTrue('To: test@example.com' in msg)
self.assertTrue("To: test@example.com" in msg)
def test_do_not_notify_moderator_when_no_sender_is_available(self):
# Set sender mail address to nonw and make sure no email is send to the
# moderator.
registry = getUtility(IRegistry)
mail_settings = registry.forInterface(IMailSchema, prefix='plone')
mail_settings = registry.forInterface(IMailSchema, prefix="plone")
mail_settings.email_from_address = None
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
self.conversation.addComment(comment)
@@ -269,10 +283,12 @@ class TestModeratorNotificationUnit(unittest.TestCase):
# Disable moderator notification setting and make sure no email is send
# to the moderator.
registry = queryUtility(IRegistry)
registry['plone.app.discussion.interfaces.IDiscussionSettings.' +
'moderator_notification_enabled'] = False
comment = createObject('plone.Comment')
comment.text = 'Comment text'
registry[
"plone.app.discussion.interfaces.IDiscussionSettings."
+ "moderator_notification_enabled"
] = False
comment = createObject("plone.Comment")
comment.text = "Comment text"
self.conversation.addComment(comment)
+13 -12
View File
@@ -1,5 +1,4 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_ROBOT_TESTING
from ..testing import PLONE_APP_DISCUSSION_ROBOT_TESTING
from plone.app.testing import ROBOT_TEST_LEVEL
from plone.testing import layered
@@ -11,19 +10,21 @@ import unittest
def test_suite():
suite = unittest.TestSuite()
current_dir = os.path.abspath(os.path.dirname(__file__))
robot_dir = os.path.join(current_dir, 'robot')
robot_dir = os.path.join(current_dir, "robot")
robot_tests = [
os.path.join('robot', doc) for doc in
os.listdir(robot_dir) if doc.endswith('.robot') and
doc.startswith('test_')
os.path.join("robot", doc)
for doc in os.listdir(robot_dir)
if doc.endswith(".robot") and doc.startswith("test_")
]
for robot_test in robot_tests:
robottestsuite = robotsuite.RobotTestSuite(robot_test)
robottestsuite.level = ROBOT_TEST_LEVEL
suite.addTests([
layered(
robottestsuite,
layer=PLONE_APP_DISCUSSION_ROBOT_TESTING,
),
])
suite.addTests(
[
layered(
robottestsuite,
layer=PLONE_APP_DISCUSSION_ROBOT_TESTING,
),
]
)
return suite
+105 -105
View File
@@ -1,10 +1,9 @@
# -*- coding: utf-8 -*-
"""Test plone.app.discussion workflow and permissions.
"""
from ..interfaces import IConversation
from ..interfaces import IDiscussionLayer
from ..testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING
from AccessControl import Unauthorized
from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IDiscussionLayer
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
from plone.app.testing import login
from plone.app.testing import logout
from plone.app.testing import setRoles
@@ -19,48 +18,51 @@ import unittest
class WorkflowSetupTest(unittest.TestCase):
"""Make sure the workflows are set up properly.
"""
"""Make sure the workflows are set up properly."""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal.invokeFactory('Folder', 'test-folder')
self.folder = self.portal['test-folder']
self.portal.portal_types['Document'].allow_discussion = True
self.folder.invokeFactory('Document', 'doc1')
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.portal.invokeFactory("Folder", "test-folder")
self.folder = self.portal["test-folder"]
self.portal.portal_types["Document"].allow_discussion = True
self.folder.invokeFactory("Document", "doc1")
self.doc = self.folder.doc1
def test_workflows_installed(self):
"""Make sure both comment workflows have been installed properly.
"""
self.assertTrue('comment_one_state_workflow' in
self.portal.portal_workflow.objectIds())
self.assertTrue('comment_review_workflow' in
self.portal.portal_workflow.objectIds())
"""Make sure both comment workflows have been installed properly."""
self.assertTrue(
"comment_one_state_workflow" in self.portal.portal_workflow.objectIds()
)
self.assertTrue(
"comment_review_workflow" in self.portal.portal_workflow.objectIds()
)
def test_default_workflow(self):
"""Make sure one_state_workflow is the default workflow.
"""
"""Make sure one_state_workflow is the default workflow."""
self.assertEqual(
('comment_one_state_workflow',),
("comment_one_state_workflow",),
self.portal.portal_workflow.getChainForPortalType(
'Discussion Item',
"Discussion Item",
),
)
def test_review_comments_permission(self):
# 'Review comments' in self.portal.permissionsOfRole('Admin')
setRoles(self.portal, TEST_USER_ID, ['Reviewer'])
self.assertTrue(self.portal.portal_membership.checkPermission(
'Review comments', self.folder), self.folder)
setRoles(self.portal, TEST_USER_ID, ['Member'])
setRoles(self.portal, TEST_USER_ID, ["Reviewer"])
self.assertTrue(
self.portal.portal_membership.checkPermission(
"Review comments", self.folder
),
self.folder,
)
setRoles(self.portal, TEST_USER_ID, ["Member"])
self.assertFalse(
self.portal.portal_membership.checkPermission(
'Review comments',
"Review comments",
self.folder,
),
self.folder,
@@ -71,31 +73,30 @@ class WorkflowSetupTest(unittest.TestCase):
class PermissionsSetupTest(unittest.TestCase):
"""Make sure the permissions are set up properly.
"""
"""Make sure the permissions are set up properly."""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
mtool = self.portal.portal_membership
self.checkPermission = mtool.checkPermission
def test_reply_to_item_permission_assigned(self):
"""Make sure the 'Reply to item' permission is properly assigned.
By default this permission is assigned to 'Member' and 'Manager'.
plone.app.discussion assigns this permission to 'Authenticated' as
well to emulate the behavior of the old commenting system.
By default this permission is assigned to 'Member' and 'Manager'.
plone.app.discussion assigns this permission to 'Authenticated' as
well to emulate the behavior of the old commenting system.
"""
ReplyToItemPerm = 'Reply to item'
ReplyToItemPerm = "Reply to item"
# should be allowed as Member
self.assertTrue(self.checkPermission(ReplyToItemPerm, self.portal))
# should be allowed as Authenticated
setRoles(self.portal, TEST_USER_ID, ['Authenticated'])
setRoles(self.portal, TEST_USER_ID, ["Authenticated"])
self.assertTrue(self.checkPermission(ReplyToItemPerm, self.portal))
# should be allowed as Manager
setRoles(self.portal, TEST_USER_ID, ['Manager'])
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.assertTrue(self.checkPermission(ReplyToItemPerm, self.portal))
# should not be allowed as anonymous
logout()
@@ -103,70 +104,66 @@ class PermissionsSetupTest(unittest.TestCase):
class CommentOneStateWorkflowTest(unittest.TestCase):
"""Test the comment_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
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal.invokeFactory('Folder', 'test-folder')
self.folder = self.portal['test-folder']
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.portal.invokeFactory("Folder", "test-folder")
self.folder = self.portal["test-folder"]
self.catalog = self.portal.portal_catalog
self.workflow = self.portal.portal_workflow
self.folder.invokeFactory('Document', 'doc1')
self.folder.invokeFactory("Document", "doc1")
self.doc = self.folder.doc1
# Add a comment
conversation = IConversation(self.folder.doc1)
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
cid = conversation.addComment(comment)
self.comment = self.folder.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(cid),
f"++conversation++default/{cid}",
)
self.portal.acl_users._doAddUser('member', 'secret', ['Member'], [])
self.portal.acl_users._doAddUser(
'reviewer', 'secret', ['Reviewer'], [])
self.portal.acl_users._doAddUser('manager', 'secret', ['Manager'], [])
self.portal.acl_users._doAddUser('editor', ' secret', ['Editor'], [])
self.portal.acl_users._doAddUser('reader', 'secret', ['Reader'], [])
self.portal.acl_users._doAddUser("member", "secret", ["Member"], [])
self.portal.acl_users._doAddUser("reviewer", "secret", ["Reviewer"], [])
self.portal.acl_users._doAddUser("manager", "secret", ["Manager"], [])
self.portal.acl_users._doAddUser("editor", " secret", ["Editor"], [])
self.portal.acl_users._doAddUser("reader", "secret", ["Reader"], [])
def test_initial_workflow_state(self):
"""Make sure the initial workflow state of a comment is 'private'.
"""
"""Make sure the initial workflow state of a comment is 'private'."""
self.assertEqual(
self.workflow.getInfoFor(self.doc, 'review_state'),
'private',
self.workflow.getInfoFor(self.doc, "review_state"),
"private",
)
def test_view_comments(self):
"""Make sure published comments can be viewed by everyone.
"""
"""Make sure published comments can be viewed by everyone."""
# Owner is allowed
# self.login(default_user)
# self.assertTrue(checkPerm(View, self.doc))
# Member is allowed
login(self.portal, TEST_USER_NAME)
workflow = self.portal.portal_workflow
workflow.doActionFor(self.doc, 'publish')
workflow.doActionFor(self.doc, "publish")
login(self.portal, 'member')
login(self.portal, "member")
self.assertTrue(checkPerm(View, self.comment))
# Reviewer is allowed
login(self.portal, 'reviewer')
login(self.portal, "reviewer")
self.assertTrue(checkPerm(View, self.comment))
# Anonymous is allowed
logout()
self.assertTrue(checkPerm(View, self.comment))
# Editor is allowed
login(self.portal, 'editor')
login(self.portal, "editor")
self.assertTrue(checkPerm(View, self.comment))
# Reader is allowed
login(self.portal, 'reader')
login(self.portal, "reader")
self.assertTrue(checkPerm(View, self.comment))
def test_comment_on_private_content_not_visible_to_world(self):
@@ -175,8 +172,9 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
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',)
self.comment._View_Permission = ("Anonymous",)
# Anonymous can see the comment.
logout()
self.assertTrue(checkPerm(View, self.comment))
@@ -185,8 +183,8 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
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',),
self.portal.portal_workflow.getChainFor("Discussion Item"),
("comment_one_state_workflow",),
)
# A Manager can still see the comment.
self.assertTrue(checkPerm(View, self.comment))
@@ -196,112 +194,112 @@ class CommentOneStateWorkflowTest(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."""
layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING
def setUp(self):
self.portal = self.layer['portal']
setRoles(self.portal, TEST_USER_ID, ['Manager'])
self.portal.invokeFactory('Folder', 'test-folder')
self.folder = self.portal['test-folder']
self.portal = self.layer["portal"]
setRoles(self.portal, TEST_USER_ID, ["Manager"])
self.portal.invokeFactory("Folder", "test-folder")
self.folder = self.portal["test-folder"]
# Allow discussion on the Document content type
self.portal.portal_types['Document'].allow_discussion = True
self.portal.portal_types["Document"].allow_discussion = True
# Set workflow for Discussion item to review workflow
self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',),
('comment_review_workflow',),
("Discussion Item",),
("comment_review_workflow",),
)
# Create a conversation for this Document
conversation = IConversation(self.portal.doc1)
# Add a comment.
comment = createObject('plone.Comment')
comment.text = 'Comment text'
comment = createObject("plone.Comment")
comment.text = "Comment text"
comment_id = conversation.addComment(comment)
comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(comment_id),
f"++conversation++default/{comment_id}",
)
self.conversation = conversation
self.comment_id = comment_id
self.comment = comment
setRoles(self.portal, TEST_USER_ID, ['Reviewer'])
setRoles(self.portal, TEST_USER_ID, ["Reviewer"])
alsoProvides(self.portal.REQUEST, IDiscussionLayer)
def test_delete(self):
self.portal.REQUEST.form['comment_id'] = self.comment_id
view = self.comment.restrictedTraverse('@@moderate-delete-comment')
self.portal.REQUEST.form["comment_id"] = self.comment_id
view = self.comment.restrictedTraverse("@@moderate-delete-comment")
view()
self.assertFalse(self.comment_id in self.conversation.objectIds())
def test_delete_as_anonymous(self):
# Make sure that anonymous users can not delete comments
logout()
self.portal.REQUEST.form['comment_id'] = self.comment_id
self.portal.REQUEST.form["comment_id"] = self.comment_id
self.assertRaises(
Unauthorized,
self.comment.restrictedTraverse,
'@@moderate-delete-comment',
"@@moderate-delete-comment",
)
self.assertTrue(self.comment_id in self.conversation.objectIds())
def test_delete_as_user(self):
# Make sure that members can not delete comments
logout()
setRoles(self.portal, TEST_USER_ID, ['Member'])
self.portal.REQUEST.form['comment_id'] = self.comment_id
setRoles(self.portal, TEST_USER_ID, ["Member"])
self.portal.REQUEST.form["comment_id"] = self.comment_id
self.assertRaises(
Unauthorized,
self.comment.restrictedTraverse,
'@@moderate-delete-comment',
"@@moderate-delete-comment",
)
self.assertTrue(self.comment_id in self.conversation.objectIds())
def test_publish(self):
self.portal.REQUEST.form['comment_id'] = self.comment_id
self.portal.REQUEST.form['workflow_action'] = 'publish'
self.portal.REQUEST.form["comment_id"] = self.comment_id
self.portal.REQUEST.form["workflow_action"] = "publish"
self.assertEqual(
'pending',
"pending",
self.portal.portal_workflow.getInfoFor(
self.comment,
'review_state',
"review_state",
),
)
view = self.comment.restrictedTraverse('@@transmit-comment')
view = self.comment.restrictedTraverse("@@transmit-comment")
view()
self.assertEqual(
'published',
"published",
self.portal.portal_workflow.getInfoFor(
self.comment,
'review_state',
"review_state",
),
)
def test_publish_as_anonymous(self):
logout()
self.portal.REQUEST.form['comment_id'] = self.comment_id
self.portal.REQUEST.form['workflow_action'] = 'publish'
self.portal.REQUEST.form["comment_id"] = self.comment_id
self.portal.REQUEST.form["workflow_action"] = "publish"
self.assertEqual(
'pending', self.portal.portal_workflow.getInfoFor(
"pending",
self.portal.portal_workflow.getInfoFor(
self.comment,
'review_state',
"review_state",
),
)
self.assertRaises(
Unauthorized,
self.comment.restrictedTraverse,
'@@transmit-comment',
"@@transmit-comment",
)
self.assertEqual(
'pending',
"pending",
self.portal.portal_workflow.getInfoFor(
self.comment,
'review_state',
"review_state",
),
)
@@ -312,15 +310,16 @@ class CommentReviewWorkflowTest(unittest.TestCase):
# publish comment and check again
login(self.portal, TEST_USER_NAME)
workflow = self.portal.portal_workflow
workflow.doActionFor(self.comment, 'publish')
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',)
self.comment._View_Permission = ("Anonymous",)
# Anonymous can see the comment.
logout()
self.assertTrue(checkPerm(View, self.comment))
@@ -329,8 +328,9 @@ class CommentReviewWorkflowTest(unittest.TestCase):
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',))
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.