diff --git a/CHANGES.txt b/CHANGES.txt index f9c53f6..dc04a9f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -5,13 +5,24 @@ Changelog ------------------ - 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) ------------------ -- Check for 'checked' attribute in a way that work also for jQuery 1.7 +- Check for 'checked' attribute in a way that work also for jQuery 1.7 [ichimdav] - Better fix for #13037 by removing submit event trigger altogether diff --git a/plone/app/discussion/browser/moderation.py b/plone/app/discussion/browser/moderation.py index 91e3290..aa7bb91 100644 --- a/plone/app/discussion/browser/moderation.py +++ b/plone/app/discussion/browser/moderation.py @@ -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() diff --git a/plone/app/discussion/catalog.py b/plone/app/discussion/catalog.py index e7d321b..12382df 100644 --- a/plone/app/discussion/catalog.py +++ b/plone/app/discussion/catalog.py @@ -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 diff --git a/plone/app/discussion/conversation.py b/plone/app/discussion/conversation.py index ec2520c..6e529a8 100644 --- a/plone/app/discussion/conversation.py +++ b/plone/app/discussion/conversation.py @@ -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() diff --git a/plone/app/discussion/interfaces.py b/plone/app/discussion/interfaces.py index d305bcb..15c674d 100644 --- a/plone/app/discussion/interfaces.py +++ b/plone/app/discussion/interfaces.py @@ -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 diff --git a/plone/app/discussion/tests/functional_test_comment_review_workflow.txt b/plone/app/discussion/tests/functional_test_comment_review_workflow.txt index 4628341..6e03a4f 100644 --- a/plone/app/discussion/tests/functional_test_comment_review_workflow.txt +++ b/plone/app/discussion/tests/functional_test_comment_review_workflow.txt @@ -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) + [>> '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) + [>> '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) + [