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:
Gaudenz Steinlin 2012-05-07 13:02:07 +02:00
parent 3eab51e1c4
commit a7b3c818f2
8 changed files with 98 additions and 2 deletions

View File

@ -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]

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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();

View File

@ -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.

View File

@ -9,4 +9,9 @@
title="Review comments" title="Review comments"
/> />
<permission
id="plone.app.discussion.DeleteOwnComments"
title="Delete own comments"
/>
</configure> </configure>

View File

@ -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>