Delete own comments
Add permission to allow comment authors to delete their own comments if there are no replies yet.
This commit is contained in:
		
							parent
							
								
									3eab51e1c4
								
							
						
					
					
						commit
						a7b3c818f2
					
				@ -3,9 +3,17 @@ Changelog
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
2.1.6 (unreleased)
 | 
					2.1.6 (unreleased)
 | 
				
			||||||
------------------
 | 
					------------------
 | 
				
			||||||
 | 
					- Add permission to allow comment authors to delete their own comments if 
 | 
				
			||||||
 | 
					  there are no replies yet.
 | 
				
			||||||
 | 
					  [gaudenz]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Add Site Administrator role to Review comments permission.
 | 
					- Add Site Administrator role to Review comments permission.
 | 
				
			||||||
  [gaudenz]
 | 
					  [gaudenz]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Add permission to allow comment authors to delete their own comments if 
 | 
				
			||||||
 | 
					  there are no replies yet.
 | 
				
			||||||
 | 
					  [gaudenz]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Fix excessive JS comment deletion.
 | 
					- Fix excessive JS comment deletion.
 | 
				
			||||||
  [gaudenz]
 | 
					  [gaudenz]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -83,6 +83,19 @@
 | 
				
			|||||||
                    <span tal:replace="structure reply/getText" />
 | 
					                    <span tal:replace="structure reply/getText" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <div class="commentActions">
 | 
					                    <div class="commentActions">
 | 
				
			||||||
 | 
					                        <form name="delete"
 | 
				
			||||||
 | 
					                              action=""
 | 
				
			||||||
 | 
					                              method="post"
 | 
				
			||||||
 | 
								      tal:condition="python: not view.can_review() and view.could_delete_own(reply)"
 | 
				
			||||||
 | 
					                              tal:attributes="action string:${reply/absolute_url}/@@delete-own-comment;
 | 
				
			||||||
 | 
								                      style python:view.can_delete_own(reply) and 'display: inline' or 'display: none'">
 | 
				
			||||||
 | 
					                            <input name="form.button.DeleteComment"
 | 
				
			||||||
 | 
					                                   class="destructive"
 | 
				
			||||||
 | 
					                                   type="submit"
 | 
				
			||||||
 | 
					                                   value="Delete"
 | 
				
			||||||
 | 
					                                   i18n:attributes="value label_delete;"
 | 
				
			||||||
 | 
					                                   />
 | 
				
			||||||
 | 
					                        </form>
 | 
				
			||||||
                        <form name="delete"
 | 
					                        <form name="delete"
 | 
				
			||||||
                              action=""
 | 
					                              action=""
 | 
				
			||||||
                              method="post"
 | 
					                              method="post"
 | 
				
			||||||
 | 
				
			|||||||
@ -190,6 +190,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
 | 
				
			|||||||
            # Member
 | 
					            # Member
 | 
				
			||||||
            member = portal_membership.getAuthenticatedMember()
 | 
					            member = portal_membership.getAuthenticatedMember()
 | 
				
			||||||
            username = member.getUserName()
 | 
					            username = member.getUserName()
 | 
				
			||||||
 | 
					            userid = member.getUserId()
 | 
				
			||||||
            email = member.getProperty('email')
 | 
					            email = member.getProperty('email')
 | 
				
			||||||
            fullname = member.getProperty('fullname')
 | 
					            fullname = member.getProperty('fullname')
 | 
				
			||||||
            if not fullname or fullname == '':
 | 
					            if not fullname or fullname == '':
 | 
				
			||||||
@ -206,6 +207,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
 | 
				
			|||||||
            comment.user_notification = user_notification
 | 
					            comment.user_notification = user_notification
 | 
				
			||||||
            comment.creation_date = datetime.utcnow()
 | 
					            comment.creation_date = datetime.utcnow()
 | 
				
			||||||
            comment.modification_date = datetime.utcnow()
 | 
					            comment.modification_date = datetime.utcnow()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # add local "Owner" role for current user
 | 
				
			||||||
 | 
					            comment.manage_setLocalRoles(userid, ['Owner'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        else:  # pragma: no cover
 | 
					        else:  # pragma: no cover
 | 
				
			||||||
            raise Unauthorized("Anonymous user tries to post a comment, but "
 | 
					            raise Unauthorized("Anonymous user tries to post a comment, but "
 | 
				
			||||||
                "anonymous commenting is disabled. Or user does not have the "
 | 
					                "anonymous commenting is disabled. Or user does not have the "
 | 
				
			||||||
@ -283,6 +288,24 @@ class CommentsViewlet(ViewletBase):
 | 
				
			|||||||
        return getSecurityManager().checkPermission('Review comments',
 | 
					        return getSecurityManager().checkPermission('Review comments',
 | 
				
			||||||
                                                    aq_inner(self.context))
 | 
					                                                    aq_inner(self.context))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def can_delete_own(self, comment):
 | 
				
			||||||
 | 
					        """Returns true if the current user can delete the comment. Only
 | 
				
			||||||
 | 
					        comments without replies can be deleted.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return comment.restrictedTraverse('@@delete-own-comment').can_delete()
 | 
				
			||||||
 | 
					        except Unauthorized:
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def could_delete_own(self, comment):
 | 
				
			||||||
 | 
					        """Returns true if the current user could delete the comment if it had no
 | 
				
			||||||
 | 
					        replies. This is used to prepare hidden form buttons for JS.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return comment.restrictedTraverse('@@delete-own-comment').could_delete()
 | 
				
			||||||
 | 
					        except Unauthorized:
 | 
				
			||||||
 | 
					            return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def is_discussion_allowed(self):
 | 
					    def is_discussion_allowed(self):
 | 
				
			||||||
        context = aq_inner(self.context)
 | 
					        context = aq_inner(self.context)
 | 
				
			||||||
        return context.restrictedTraverse('@@conversation_view').enabled()
 | 
					        return context.restrictedTraverse('@@conversation_view').enabled()
 | 
				
			||||||
@ -346,7 +369,6 @@ class CommentsViewlet(ViewletBase):
 | 
				
			|||||||
        conversation = IConversation(context)
 | 
					        conversation = IConversation(context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        wf = getToolByName(context, 'portal_workflow')
 | 
					        wf = getToolByName(context, 'portal_workflow')
 | 
				
			||||||
 | 
					 | 
				
			||||||
        # workflow_actions is only true when user
 | 
					        # workflow_actions is only true when user
 | 
				
			||||||
        # has 'Manage portal' permission
 | 
					        # has 'Manage portal' permission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -71,7 +71,7 @@
 | 
				
			|||||||
        permission="zope2.View"
 | 
					        permission="zope2.View"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- Delete comment view -->
 | 
					    <!-- Delete comment views -->
 | 
				
			||||||
    <browser:page
 | 
					    <browser:page
 | 
				
			||||||
        for="plone.app.discussion.interfaces.IComment"
 | 
					        for="plone.app.discussion.interfaces.IComment"
 | 
				
			||||||
        name="moderate-delete-comment"
 | 
					        name="moderate-delete-comment"
 | 
				
			||||||
@ -80,6 +80,14 @@
 | 
				
			|||||||
        permission="plone.app.discussion.ReviewComments"
 | 
					        permission="plone.app.discussion.ReviewComments"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <browser:page
 | 
				
			||||||
 | 
					        for="plone.app.discussion.interfaces.IComment"
 | 
				
			||||||
 | 
					        name="delete-own-comment"
 | 
				
			||||||
 | 
					        layer="..interfaces.IDiscussionLayer"
 | 
				
			||||||
 | 
					        class=".moderation.DeleteOwnComment"
 | 
				
			||||||
 | 
					        permission="plone.app.discussion.DeleteOwnComments"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <!-- Publish comment view -->
 | 
					    <!-- Publish comment view -->
 | 
				
			||||||
    <browser:page
 | 
					    <browser:page
 | 
				
			||||||
        for="plone.app.discussion.interfaces.IComment"
 | 
					        for="plone.app.discussion.interfaces.IComment"
 | 
				
			||||||
 | 
				
			|||||||
@ -193,6 +193,9 @@
 | 
				
			|||||||
                            $(this).remove();
 | 
					                            $(this).remove();
 | 
				
			||||||
                        });
 | 
					                        });
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
 | 
					                    // Add delete button to the parent
 | 
				
			||||||
 | 
					                    var parent = comment.prev('[class*="replyTreeLevel' + (treelevel - 1) + '"]');
 | 
				
			||||||
 | 
					                    parent.find('form[name="delete"]').css('display', 'inline');
 | 
				
			||||||
                    // remove comment
 | 
					                    // remove comment
 | 
				
			||||||
                    $(this).fadeOut('fast', function () {
 | 
					                    $(this).fadeOut('fast', function () {
 | 
				
			||||||
                        $(this).remove();
 | 
					                        $(this).remove();
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
# -*- coding: utf-8 -*-
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
from Acquisition import aq_inner, aq_parent
 | 
					from Acquisition import aq_inner, aq_parent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from AccessControl import Unauthorized, getSecurityManager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from Products.Five.browser import BrowserView
 | 
					from Products.Five.browser import BrowserView
 | 
				
			||||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 | 
					from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -10,6 +12,7 @@ from Products.statusmessages.interfaces import IStatusMessage
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
from plone.app.discussion.interfaces import _
 | 
					from plone.app.discussion.interfaces import _
 | 
				
			||||||
from plone.app.discussion.interfaces import IComment
 | 
					from plone.app.discussion.interfaces import IComment
 | 
				
			||||||
 | 
					from plone.app.discussion.interfaces import IReplies
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class View(BrowserView):
 | 
					class View(BrowserView):
 | 
				
			||||||
@ -104,6 +107,34 @@ class DeleteComment(BrowserView):
 | 
				
			|||||||
        return self.context.REQUEST.RESPONSE.redirect(came_from)
 | 
					        return self.context.REQUEST.RESPONSE.redirect(came_from)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DeleteOwnComment(DeleteComment):
 | 
				
			||||||
 | 
					    """Delete an own comment if it has no replies. Following conditions have to be true
 | 
				
			||||||
 | 
					    for a user to be able to delete his comments:
 | 
				
			||||||
 | 
					    * "Delete own comments" permission
 | 
				
			||||||
 | 
					    * no replies to the comment
 | 
				
			||||||
 | 
					    * Owner role directly assigned on the comment object
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def could_delete(self):
 | 
				
			||||||
 | 
					        """returns true if the comment could be deleted if it had no replies."""
 | 
				
			||||||
 | 
					        sm = getSecurityManager()
 | 
				
			||||||
 | 
					        context = aq_inner(self.context)
 | 
				
			||||||
 | 
					        userid = sm.getUser().getId()
 | 
				
			||||||
 | 
					        return (sm.checkPermission('Delete own comments',
 | 
				
			||||||
 | 
					                                   context)
 | 
				
			||||||
 | 
					                and 'Owner' in context.get_local_roles_for_userid(userid))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def can_delete(self):
 | 
				
			||||||
 | 
					        return (len(IReplies(aq_inner(self.context))) == 0
 | 
				
			||||||
 | 
					                and self.could_delete())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __call__(self):
 | 
				
			||||||
 | 
					        if self.can_delete():
 | 
				
			||||||
 | 
					            super(DeleteOwnComment, self).__call__()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            raise Unauthorized("Your not allowed to delete this comment.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PublishComment(BrowserView):
 | 
					class PublishComment(BrowserView):
 | 
				
			||||||
    """Publish a comment.
 | 
					    """Publish a comment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,4 +9,9 @@
 | 
				
			|||||||
        title="Review comments"
 | 
					        title="Review comments"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <permission
 | 
				
			||||||
 | 
					        id="plone.app.discussion.DeleteOwnComments"
 | 
				
			||||||
 | 
					        title="Delete own comments"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</configure>
 | 
					</configure>
 | 
				
			||||||
 | 
				
			|||||||
@ -9,5 +9,11 @@
 | 
				
			|||||||
        <permission name="Reply to item" acquire="False">
 | 
					        <permission name="Reply to item" acquire="False">
 | 
				
			||||||
            <role name="Authenticated"/>
 | 
					            <role name="Authenticated"/>
 | 
				
			||||||
        </permission>
 | 
					        </permission>
 | 
				
			||||||
 | 
					        <permission name="Delete own comments" acquire="False">
 | 
				
			||||||
 | 
					            <role name="Manager"/>
 | 
				
			||||||
 | 
						    <role name="Site Administrator"/>
 | 
				
			||||||
 | 
					            <role name="Reviewer"/>
 | 
				
			||||||
 | 
					            <role name="Owner"/>
 | 
				
			||||||
 | 
					        </permission>
 | 
				
			||||||
    </permissions>
 | 
					    </permissions>
 | 
				
			||||||
</rolemap>
 | 
					</rolemap>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user