Many updates to handle non public comments properly
This commit is contained in:
parent
6320048b37
commit
05f0e7e4d8
11
CHANGES.txt
11
CHANGES.txt
@ -7,6 +7,17 @@ Changelog
|
||||
- Do not raise an error when no workflow is assigned to the comment type.
|
||||
[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)
|
||||
------------------
|
||||
|
@ -95,6 +95,7 @@ class DeleteComment(BrowserView):
|
||||
conversation = aq_parent(comment)
|
||||
content_object = aq_parent(conversation)
|
||||
del conversation[comment.id]
|
||||
content_object.reindexObject()
|
||||
IStatusMessage(self.context.REQUEST).addStatusMessage(
|
||||
_("Comment deleted."),
|
||||
type="info")
|
||||
@ -201,12 +202,13 @@ class BulkActionsView(BrowserView):
|
||||
context = aq_inner(self.context)
|
||||
for path in self.paths:
|
||||
comment = context.restrictedTraverse(path)
|
||||
content_object = aq_parent(aq_parent(comment))
|
||||
workflowTool = getToolByName(comment, 'portal_workflow')
|
||||
current_state = workflowTool.getInfoFor(comment, 'review_state')
|
||||
if current_state != 'published':
|
||||
workflowTool.doActionFor(comment, 'publish')
|
||||
catalog = getToolByName(comment, 'portal_catalog')
|
||||
catalog.reindexObject(comment)
|
||||
comment.reindexObject()
|
||||
content_object.reindexObject()
|
||||
|
||||
def mark_as_spam(self):
|
||||
raise NotImplementedError
|
||||
@ -223,4 +225,6 @@ class BulkActionsView(BrowserView):
|
||||
for path in self.paths:
|
||||
comment = context.restrictedTraverse(path)
|
||||
conversation = aq_parent(comment)
|
||||
content_object = aq_parent(conversation)
|
||||
del conversation[comment.id]
|
||||
content_object.reindexObject()
|
||||
|
@ -61,7 +61,7 @@ def commentators(object):
|
||||
if object.meta_type != 'Discussion Item':
|
||||
try:
|
||||
conversation = IConversation(object)
|
||||
return tuple(conversation.commentators.keys())
|
||||
return conversation.public_commentators
|
||||
except TypeError: # pragma: no cover
|
||||
# The item is contentish but nobody
|
||||
# implemented an adapter for it
|
||||
|
@ -95,15 +95,28 @@ class Conversation(Traversable, Persistent, Explicit):
|
||||
|
||||
@property
|
||||
def last_comment_date(self):
|
||||
try:
|
||||
return self._comments[self._comments.maxKey()].creation_date
|
||||
except (ValueError, KeyError, AttributeError,):
|
||||
return None
|
||||
# self._comments is an Instance of a btree. The keys
|
||||
# are always ordered
|
||||
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
|
||||
|
||||
@property
|
||||
def commentators(self):
|
||||
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):
|
||||
return self._comments.keys()
|
||||
|
||||
|
@ -31,13 +31,13 @@ class IConversation(IIterableMapping):
|
||||
"""
|
||||
|
||||
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,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
last_comment_date = schema.Date(
|
||||
title=_(u"Date of the most recent comment"),
|
||||
title=_(u"Date of the most recent public comment"),
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
@ -46,6 +46,12 @@ class IConversation(IIterableMapping):
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
public_commentators = schema.Set(
|
||||
title=_(u"The set of unique commentators (usernames) of"
|
||||
" published_comments"),
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
def addComment(comment):
|
||||
"""Adds a new comment to the list of comments, and returns the
|
||||
comment id that was assigned. The comment_id property on the comment
|
||||
|
@ -124,6 +124,11 @@ Anonymous user can not see any posts or comment actions
|
||||
>>> 'form.button.PublishComment' in unprivileged_browser.contents
|
||||
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
|
||||
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
|
||||
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
|
||||
-------------------------------------
|
||||
@ -205,4 +215,12 @@ Make sure the second comment has been deleted.
|
||||
>>> 'Second anonymous comment' in browser.contents
|
||||
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...]
|
||||
|
||||
|
@ -172,7 +172,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
|
||||
self.assertEqual(doc1_brain.commentators, ('Emma', 'Jim'))
|
||||
self.assertEqual(doc1_brain.commentators, ('Jim', 'Emma'))
|
||||
|
||||
# remove one comments
|
||||
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.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):
|
||||
|
||||
|
@ -69,7 +69,7 @@ class ConversationTest(unittest.TestCase):
|
||||
self.assertTrue(isinstance(comment.comment_id, long))
|
||||
self.assertTrue(IComment.providedBy(conversation[new_id]))
|
||||
self.assertEqual(aq_base(conversation[new_id].__parent__),
|
||||
aq_base(conversation))
|
||||
aq_base(conversation))
|
||||
self.assertEqual(new_id, comment.comment_id)
|
||||
self.assertEqual(len(list(conversation.getComments())), 1)
|
||||
self.assertEqual(len(tuple(conversation.getThreads())), 1)
|
||||
@ -77,6 +77,18 @@ class ConversationTest(unittest.TestCase):
|
||||
self.assertTrue(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"
|
||||
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):
|
||||
# Create a conversation. In this case we doesn't assign it to an
|
||||
# object, as we just want to check the Conversation object API.
|
||||
|
Loading…
Reference in New Issue
Block a user