Merge pull request #195 from plone/plone-base-overhaul
Plone base overhaul
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
@@ -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><b>Got HTML?</b></p>',
|
||||
"<p><b>Got HTML?</b></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"],
|
||||
)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user