From 53428fe5f65842ec48af62d54653160275420975 Mon Sep 17 00:00:00 2001 From: Paul J Stevens Date: Wed, 13 Jun 2012 11:17:22 +0000 Subject: [PATCH] total_comments only counts published comments Also migrate workflow state during migration. --- CHANGES.txt | 10 +++++ plone/app/discussion/browser/comments.py | 3 +- plone/app/discussion/browser/migration.py | 39 ++++++++++++++++++- plone/app/discussion/conversation.py | 6 ++- plone/app/discussion/tests/test_migration.py | 21 ++++++++++ .../discussion/tests/test_moderation_view.py | 4 +- 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 05d6de4..822495e 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -6,12 +6,22 @@ Changelog - Prune duplicated test code. [pjstevns] + - Update version in buildout.cfg to allow development. [pjstevns] +- Conversation.total_comments only counts published comments. + Fixes bug #11591. + [pjstevns] + +- Set workflow status of comments during migration based on + the state of the Discussion Item. + [pjstevns] + 2.1.6 (2012-05-30) ------------------ + - Add Site Administrator role to Review comments permission. [gaudenz] diff --git a/plone/app/discussion/browser/comments.py b/plone/app/discussion/browser/comments.py index cae1887..cacb7c2 100644 --- a/plone/app/discussion/browser/comments.py +++ b/plone/app/discussion/browser/comments.py @@ -38,7 +38,6 @@ from plone.app.discussion.interfaces import ICaptcha from plone.app.discussion.browser.validator import CaptchaValidator from plone.z3cform import z2 -from plone.z3cform.widget import SingleCheckBoxWidget from plone.z3cform.fieldsets import extensible @@ -372,7 +371,7 @@ class CommentsViewlet(ViewletBase): yield r # Return all direct replies - if conversation.total_comments > 0: + if len(conversation.objectIds()): if workflow_actions: return replies_with_workflow_actions() else: diff --git a/plone/app/discussion/browser/migration.py b/plone/app/discussion/browser/migration.py index e7ed98d..8e478ba 100644 --- a/plone/app/discussion/browser/migration.py +++ b/plone/app/discussion/browser/migration.py @@ -14,6 +14,9 @@ from plone.app.discussion.comment import CommentFactory from plone.app.discussion.interfaces import IConversation, IReplies, IComment +from types import TupleType +from DateTime import DateTime + def DT2dt(DT): """Convert a Zope DateTime (with timezone) into a Python datetime (GMT).""" @@ -64,8 +67,14 @@ class View(BrowserView): if len(replies) == 0: return True - for reply in replies: + workflow = context.portal_workflow + oldchain = workflow.getChainForPortalType('Discussion Item') + new_workflow = workflow.comment_review_workflow + if type(oldchain) == TupleType and len(oldchain) > 0: + oldchain = oldchain[0] + + for reply in replies: # log indent = " " for i in range(depth): @@ -80,7 +89,8 @@ class View(BrowserView): new_in_reply_to = None if should_migrate: - # create a reply object + + # create a reply object comment = CommentFactory() comment.title = reply.Title() comment.text = reply.cooked_text @@ -105,6 +115,31 @@ class View(BrowserView): replies = IReplies(comment_to_reply_to) new_in_reply_to = replies.addComment(comment) + # migrate the review state + old_status = workflow.getStatusOf(oldchain, reply) + new_status = { + 'action': None, + 'actor': None, + 'comment': 'Migrated workflow state', + 'review_state': old_status.get( + 'review_state', + new_workflow.initial_state), + 'time': DateTime() + } + workflow.setStatusOf('comment_review_workflow', + comment, + new_status) + + auto_transition = new_workflow._findAutomaticTransition( + comment, + new_workflow._getWorkflowStateOf(comment)) + if auto_transition is not None: + new_workflow._changeStateOf(comment, auto_transition) + else: + new_workflow.updateRoleMappingsFor(comment) + comment.reindexObject(idxs=['allowedRolesAndUsers', + 'review_state']) + self.total_comments_migrated += 1 # migrate all talkbacks of the reply diff --git a/plone/app/discussion/conversation.py b/plone/app/discussion/conversation.py index e9f5a29..505f6b5 100644 --- a/plone/app/discussion/conversation.py +++ b/plone/app/discussion/conversation.py @@ -46,6 +46,8 @@ from plone.app.discussion.interfaces import IConversation from plone.app.discussion.interfaces import IReplies from plone.app.discussion.comment import Comment +from AccessControl.SpecialUsers import nobody as user_nobody + ANNOTATION_KEY = 'plone.app.discussion:conversation' @@ -85,7 +87,9 @@ class Conversation(Traversable, Persistent, Explicit): @property def total_comments(self): - return len(self._comments) + public_comments = [x for x in self._comments.values() if \ + user_nobody.has_permission('View', x)] + return len(public_comments) @property def last_comment_date(self): diff --git a/plone/app/discussion/tests/test_migration.py b/plone/app/discussion/tests/test_migration.py index 89949d7..3d86bb0 100644 --- a/plone/app/discussion/tests/test_migration.py +++ b/plone/app/discussion/tests/test_migration.py @@ -21,6 +21,14 @@ class MigrationTest(unittest.TestCase): layer = PLONE_APP_DISCUSSION_INTEGRATION_TESTING + def _publish(self, reply): + # publish the reply + status = self.portal.portal_workflow.getStatusOf( + 'comment_review_workflow', reply).copy() + status['review_state'] = 'published' + self.portal.portal_workflow.setStatusOf( + 'comment_review_workflow', reply, status) + def setUp(self): self.portal = self.layer['portal'] self.request = self.layer['request'] @@ -53,6 +61,8 @@ class MigrationTest(unittest.TestCase): reply.setReplyTo(self.doc) reply.creation_date = DateTime(2003, 3, 11, 9, 28, 6, 'GMT') reply.modification_date = DateTime(2009, 7, 12, 19, 38, 7, 'GMT') + + self._publish(reply) self.assertEqual(reply.Title(), 'My Title') self.assertEqual(reply.EditableBody(), 'My Text') self.assertTrue('Jim' in reply.listCreators()) @@ -104,12 +114,16 @@ class MigrationTest(unittest.TestCase): talkback.createReply(title='First comment', text='This is my first comment.') comment1 = talkback.getReplies()[0] + self._publish(comment1) + talkback_comment1 = self.discussion.getDiscussionFor(comment1) # Re: First comment talkback_comment1.createReply(title='Re: First comment', text='This is my first reply.') comment1_1 = talkback_comment1.getReplies()[0] + self._publish(comment1_1) + talkback_comment1_1 = self.discussion.getDiscussionFor(comment1_1) self.assertEqual(len(talkback.getReplies()), 1) @@ -120,27 +134,34 @@ class MigrationTest(unittest.TestCase): talkback_comment1_1.createReply(title='Re: Re: First comment', text='This is my first re-reply.') comment1_1_1 = talkback_comment1_1.getReplies()[0] + self._publish(comment1_1_1) + talkback_comment1_1_1 = self.discussion.getDiscussionFor(comment1_1_1) # Re: Re: Re: First comment talkback_comment1_1_1.createReply(title='Re: Re: Re: First comment', text='This is my first re-re-reply.') + self._publish(talkback_comment1_1_1.getReplies()[0]) # Re: First comment (2) talkback_comment1.createReply(title='Re: First comment (2)', text='This is my first reply (2).') + self._publish(talkback_comment1.getReplies()[1]) # Re: First comment (3) talkback_comment1.createReply(title='Re: First comment (3)', text='This is my first reply (3).') + self._publish(talkback_comment1.getReplies()[2]) # Re: First comment (4) talkback_comment1.createReply(title='Re: First comment (4)', text='This is my first reply (4).') + self._publish(talkback_comment1.getReplies()[3]) # Second comment talkback.createReply(title='Second comment', text='This is my second comment.') + self._publish(talkback.getReplies()[1]) # Call migration script self.view() diff --git a/plone/app/discussion/tests/test_moderation_view.py b/plone/app/discussion/tests/test_moderation_view.py index 01d7057..bf09ea0 100644 --- a/plone/app/discussion/tests/test_moderation_view.py +++ b/plone/app/discussion/tests/test_moderation_view.py @@ -171,7 +171,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase): def test_delete(self): # Initially we have three comments - self.assertEqual(self.conversation.total_comments, 3) + 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()), @@ -181,7 +181,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase): view() # Make sure that the two comments have been deleted - self.assertEqual(self.conversation.total_comments, 1) + self.assertEqual(len(self.conversation.objectIds()), 1) comment = self.conversation.getComments().next() self.assertTrue(comment) self.assertEqual(comment, self.comment2)