Many updates to handle non public comments properly

This commit is contained in:
Patrick Gerken 2013-03-28 14:28:22 +01:00
parent 6320048b37
commit 05f0e7e4d8
8 changed files with 87 additions and 13 deletions

View File

@ -7,6 +7,17 @@ Changelog
- Do not raise an error when no workflow is assigned to the comment type. - Do not raise an error when no workflow is assigned to the comment type.
[timo] [timo]
- Add a conversation property public_commentators that only lists
commentators of comments that are public.
The commentators indexer indexes this field now.
The behavior of the conversation property commentators is
unchanged.
[do3cc]
- The last comment date now only returns the date of the newest
published comment.
[do3cc]
2.2.4 (2013-03-05) 2.2.4 (2013-03-05)
------------------ ------------------

View File

@ -95,6 +95,7 @@ class DeleteComment(BrowserView):
conversation = aq_parent(comment) conversation = aq_parent(comment)
content_object = aq_parent(conversation) content_object = aq_parent(conversation)
del conversation[comment.id] del conversation[comment.id]
content_object.reindexObject()
IStatusMessage(self.context.REQUEST).addStatusMessage( IStatusMessage(self.context.REQUEST).addStatusMessage(
_("Comment deleted."), _("Comment deleted."),
type="info") type="info")
@ -201,12 +202,13 @@ class BulkActionsView(BrowserView):
context = aq_inner(self.context) context = aq_inner(self.context)
for path in self.paths: for path in self.paths:
comment = context.restrictedTraverse(path) comment = context.restrictedTraverse(path)
content_object = aq_parent(aq_parent(comment))
workflowTool = getToolByName(comment, 'portal_workflow') workflowTool = getToolByName(comment, 'portal_workflow')
current_state = workflowTool.getInfoFor(comment, 'review_state') current_state = workflowTool.getInfoFor(comment, 'review_state')
if current_state != 'published': if current_state != 'published':
workflowTool.doActionFor(comment, 'publish') workflowTool.doActionFor(comment, 'publish')
catalog = getToolByName(comment, 'portal_catalog') comment.reindexObject()
catalog.reindexObject(comment) content_object.reindexObject()
def mark_as_spam(self): def mark_as_spam(self):
raise NotImplementedError raise NotImplementedError
@ -223,4 +225,6 @@ class BulkActionsView(BrowserView):
for path in self.paths: for path in self.paths:
comment = context.restrictedTraverse(path) comment = context.restrictedTraverse(path)
conversation = aq_parent(comment) conversation = aq_parent(comment)
content_object = aq_parent(conversation)
del conversation[comment.id] del conversation[comment.id]
content_object.reindexObject()

View File

@ -61,7 +61,7 @@ def commentators(object):
if object.meta_type != 'Discussion Item': if object.meta_type != 'Discussion Item':
try: try:
conversation = IConversation(object) conversation = IConversation(object)
return tuple(conversation.commentators.keys()) return conversation.public_commentators
except TypeError: # pragma: no cover except TypeError: # pragma: no cover
# The item is contentish but nobody # The item is contentish but nobody
# implemented an adapter for it # implemented an adapter for it

View File

@ -95,15 +95,28 @@ class Conversation(Traversable, Persistent, Explicit):
@property @property
def last_comment_date(self): def last_comment_date(self):
try: # self._comments is an Instance of a btree. The keys
return self._comments[self._comments.maxKey()].creation_date # are always ordered
except (ValueError, KeyError, AttributeError,): comment_keys = self._comments.keys()
for comment_key in reversed(comment_keys):
comment = self._comments[comment_key]
if user_nobody.has_permission('View', comment):
return comment.creation_date
return None return None
@property @property
def commentators(self): def commentators(self):
return self._commentators return self._commentators
@property
def public_commentators(self):
retval = set()
for comment in self._comments.values():
if not user_nobody.has_permission('View', comment):
continue
retval.add(comment.author_username)
return tuple(retval)
def objectIds(self): def objectIds(self):
return self._comments.keys() return self._comments.keys()

View File

@ -31,13 +31,13 @@ class IConversation(IIterableMapping):
""" """
total_comments = schema.Int( total_comments = schema.Int(
title=_(u"Total number of comments on this item"), title=_(u"Total number of public comments on this item"),
min=0, min=0,
readonly=True, readonly=True,
) )
last_comment_date = schema.Date( last_comment_date = schema.Date(
title=_(u"Date of the most recent comment"), title=_(u"Date of the most recent public comment"),
readonly=True, readonly=True,
) )
@ -46,6 +46,12 @@ class IConversation(IIterableMapping):
readonly=True, readonly=True,
) )
public_commentators = schema.Set(
title=_(u"The set of unique commentators (usernames) of"
" published_comments"),
readonly=True,
)
def addComment(comment): def addComment(comment):
"""Adds a new comment to the list of comments, and returns the """Adds a new comment to the list of comments, and returns the
comment id that was assigned. The comment_id property on the comment comment id that was assigned. The comment_id property on the comment

View File

@ -124,6 +124,11 @@ Anonymous user can not see any posts or comment actions
>>> 'form.button.PublishComment' in unprivileged_browser.contents >>> 'form.button.PublishComment' in unprivileged_browser.contents
False False
The catalog does not list the comments yet:
>>> portal.portal_catalog.searchResults(id='doc', total_comments=0)
[<Products...]
Users with 'Review comment' permission can see unapproved comments and comment Users with 'Review comment' permission can see unapproved comments and comment
actions. actions.
@ -176,6 +181,11 @@ Make sure anonyous users see the approved comment, but not the unapproved ones.
>>> 'First anonymous comment' in unprivileged_browser.contents >>> 'First anonymous comment' in unprivileged_browser.contents
True True
Make sure the catalog only lists the public comments.
>>> portal.portal_catalog.searchResults(id='doc', total_comments=1)
[<Products...]
Delete a comment in the comments view Delete a comment in the comments view
------------------------------------- -------------------------------------
@ -205,4 +215,12 @@ Make sure the second comment has been deleted.
>>> 'Second anonymous comment' in browser.contents >>> 'Second anonymous comment' in browser.contents
False False
Delete the first, published comment.
>>> browser.open(urldoc)
>>> browser.getControl('Delete', index=0).click()
Make sure the catalog has been updated properly.
>>> portal.portal_catalog.searchResults(id='doc', total_comments=0)
[<Products...]

View File

@ -172,7 +172,7 @@ class ConversationCatalogTest(unittest.TestCase):
)) ))
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual(doc1_brain.commentators, ('Emma', 'Jim')) self.assertEqual(doc1_brain.commentators, ('Jim', 'Emma'))
# remove one comments # remove one comments
del self.conversation[new_comment2_id] del self.conversation[new_comment2_id]
@ -205,6 +205,16 @@ class ConversationCatalogTest(unittest.TestCase):
self.assertEqual(comment1_brain.last_comment_date, None) self.assertEqual(comment1_brain.last_comment_date, None)
self.assertEqual(comment1_brain.total_comments, None) self.assertEqual(comment1_brain.total_comments, None)
def test_dont_index_private_commentators(self):
self.comment1.manage_permission("View", roles=tuple())
self.portal.doc1.reindexObject()
brains = self.catalog.searchResults(dict(
path={'query':
'/'.join(self.portal.doc1.getPhysicalPath())},
portal_type="Document"
))
doc1_brain = brains[0]
self.assertEqual(doc1_brain.commentators, ())
class CommentCatalogTest(unittest.TestCase): class CommentCatalogTest(unittest.TestCase):

View File

@ -77,6 +77,18 @@ class ConversationTest(unittest.TestCase):
self.assertTrue(conversation.last_comment_date - datetime.utcnow() < self.assertTrue(conversation.last_comment_date - datetime.utcnow() <
timedelta(seconds=1)) timedelta(seconds=1))
def test_private_comment(self):
conversation = IConversation(self.portal.doc1)
comment = createObject('plone.Comment')
comment.author_username = "nobody"
conversation.addComment(comment)
comment.manage_permission("View", roles=tuple())
self.assertEquals(0, conversation.total_comments)
self.assertEquals(None, conversation.last_comment_date)
self.assertEquals(["nobody"], list(conversation.commentators))
self.assertEquals([], list(conversation.public_commentators))
def test_delete_comment(self): def test_delete_comment(self):
# Create a conversation. In this case we doesn't assign it to an # Create a conversation. In this case we doesn't assign it to an
# object, as we just want to check the Conversation object API. # object, as we just want to check the Conversation object API.