Raise an unauthorized error when authenticated users try to post a comment on a content object that has discussion disabled. Thanks to vincentfrentin for reporting this!

svn path=/plone.app.discussion/trunk/; revision=39627
This commit is contained in:
Timo Stollenwerk 2010-09-03 20:40:27 +00:00
parent a410c72333
commit ea13020498
3 changed files with 117 additions and 20 deletions

View File

@ -4,6 +4,11 @@ Changelog
1.0b7 (unreleased)
------------------
* Raise an unauthorized error when authenticated users try to post a comment
on a content object that has discussion disabled. Thanks to vincentfrentin
for reporting this.
[timo]
* Czech translation added.
[naro]

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from Acquisition import aq_inner
from AccessControl import Unauthorized
from AccessControl import getSecurityManager
from datetime import datetime
@ -108,11 +109,13 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
author_email = u""
#author_notification = None
# Captcha check for anonymous users (if Captcha is enabled)
# Captcha check for anonymous users (if Captcha is enabled and
# anonymous commenting is allowed)
registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings)
portal_membership = getToolByName(self.context, 'portal_membership')
if settings.captcha != 'disabled' and \
settings.anonymous_comments and \
portal_membership.isAnonymousUser():
if not 'captcha' in data:
data['captcha'] = u""
@ -123,13 +126,13 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
None)
captcha.validate(data['captcha'])
# Fetch data from request
if 'title' in data:
title = data['title']
if 'text' in data:
text = data['text']
if 'author_name' in data:
author_name = data['author_name']
if 'author_email' in data:
author_email = data['author_email']
#if 'author_notification' in data:
@ -138,6 +141,11 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
# The add-comment view is called on the conversation object
conversation = IConversation(self.__parent__)
# Check if conversation is enabled on this content object
if not conversation.enabled():
raise Unauthorized, "Discussion is not enabled for this content\
object."
if data['in_reply_to']:
# Fetch the comment we want to reply to
conversation_to_reply_to = conversation.get(data['in_reply_to'])
@ -150,13 +158,14 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
portal_membership = getToolByName(self.context, 'portal_membership')
if portal_membership.isAnonymousUser():
if portal_membership.isAnonymousUser() and \
settings.anonymous_comments:
comment.creator = None
comment.author_name = author_name
comment.author_email = author_email
#comment.author_notification = author_notification
comment.creation_date = comment.modification_date = datetime.now()
else:
elif not portal_membership.isAnonymousUser():
member = portal_membership.getAuthenticatedMember()
comment.creator = member.id
comment.author_username = member.getUserName()
@ -164,6 +173,9 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
comment.author_email = member.getProperty('email')
#comment.author_notification = comment.author_notification
comment.creation_date = comment.modification_date = datetime.now()
else:
raise Unauthorized, "Anonymous user tries to post a comment, but \
anonymous commenting is disabled."
# Check if the added comment is a reply to an existing comment
# or just a regular reply to the content object.

View File

@ -2,6 +2,8 @@
import unittest
from datetime import datetime
from AccessControl import Unauthorized
from Acquisition import Implicit
from zope.component import createObject, queryUtility
@ -23,10 +25,14 @@ from zope.component import getMultiAdapter
from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.tests import dummy
from Products.Five.testbrowser import Browser
from Products.PloneTestCase.ptc import PloneTestCase
from Products.PloneTestCase.ptc import FunctionalTestCase
from Products.PloneTestCase.setup import portal_owner, default_password
from plone.app.discussion.comment import Comment
from plone.app.discussion.browser.comments import CommentsViewlet
@ -43,16 +49,19 @@ class TestCommentForm(PloneTestCase):
self.loginAsPortalOwner()
typetool = self.portal.portal_types
typetool.constructContent('Document', self.portal, 'doc1')
self.portal_discussion = getToolByName(self.portal,
self.dtool = getToolByName(self.portal,
'portal_discussion',
None)
self.membership_tool = getToolByName(self.folder, 'portal_membership')
self.dtool.overrideDiscussionFor(self.portal.doc1, False)
self.mtool = getToolByName(self.folder, 'portal_membership', None)
self.memberdata = self.portal.portal_memberdata
self.request = self.app.REQUEST
self.context = getattr(self.portal, 'doc1')
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
def test_add_comment(self):
# Allow discussion
self.dtool.overrideDiscussionFor(self.portal.doc1, True)
self.viewlet = CommentsViewlet(self.context, self.request, None, None)
def make_request(form={}):
request = TestRequest()
@ -66,6 +75,7 @@ class TestCommentForm(PloneTestCase):
factory=CommentForm,
name=u"comment-form")
# The form should return errors if the two required fields are empty
request = make_request(form={})
commentForm = getMultiAdapter((self.context, request),
@ -76,7 +86,7 @@ class TestCommentForm(PloneTestCase):
self.assertEquals(len(errors), 2)
self.failIf(commentForm.handleComment(commentForm, "foo"))
# The form should return an error if the comment text field is empty
request = make_request(form={'form.widgets.text': 'foo'})
commentForm = getMultiAdapter((self.context, request),
@ -85,8 +95,10 @@ class TestCommentForm(PloneTestCase):
data, errors = commentForm.extractData()
self.assertEquals(len(errors), 1)
self.failIf(commentForm.handleComment(commentForm, "foo"))
# The form is submitted successfully, if all required fields are
# filled out
request = make_request(form={'form.widgets.title': 'foo',
'form.widgets.text': 'bar'})
@ -99,6 +111,76 @@ class TestCommentForm(PloneTestCase):
self.failIf(commentForm.handleComment(commentForm, "foo"))
def test_can_not_add_comments_if_discussion_is_not_allowed(self):
"""Make sure that comments can't be posted if discussion is disabled.
"""
# Discussion is disabled by default
def make_request(form={}):
request = TestRequest()
request.form.update(form)
alsoProvides(request, IFormLayer)
alsoProvides(request, IAttributeAnnotatable)
return request
provideAdapter(adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u"comment-form")
request = make_request(form={'form.widgets.title': 'foo',
'form.widgets.text': 'bar'})
commentForm = getMultiAdapter((self.context, request),
name=u"comment-form")
commentForm.update()
data, errors = commentForm.extractData()
# No form errors, but raise unauthorized because discussion is not
# allowed
self.assertEquals(len(errors), 0)
self.assertRaises(Unauthorized,
commentForm.handleComment,
commentForm,
"foo")
def test_add_comment_as_anonymous(self):
"""Make sure that anonymous users can't post comments if anonymous
comments are disabled.
"""
# Anonymous comments are disabled by default
self.logout()
def make_request(form={}):
request = TestRequest()
request.form.update(form)
alsoProvides(request, IFormLayer)
alsoProvides(request, IAttributeAnnotatable)
return request
provideAdapter(adapts=(Interface, IBrowserRequest),
provides=Interface,
factory=CommentForm,
name=u"comment-form")
request = make_request(form={'form.widgets.title': 'foo',
'form.widgets.text': 'bar'})
commentForm = getMultiAdapter((self.context, request),
name=u"comment-form")
commentForm.update()
data, errors = commentForm.extractData()
self.assertEquals(len(errors), 0)
self.assertRaises(Unauthorized,
commentForm.handleComment,
commentForm,
"foo")
class TestCommentsViewletIntegration(FunctionalTestCase):
layer = DiscussionLayer
@ -108,8 +190,6 @@ class TestCommentsViewletIntegration(FunctionalTestCase):
portal_url = self.portal.absolute_url()
browser.handleErrors = False
from Products.PloneTestCase.setup import portal_owner, default_password
browser.open(portal_url + '/login_form')
browser.getControl(name='__ac_name').value = portal_owner
browser.getControl(name='__ac_password').value = default_password
@ -151,7 +231,7 @@ class TestCommentsViewlet(PloneTestCase):
self.portal_discussion = getToolByName(self.portal,
'portal_discussion',
None)
self.membership_tool = getToolByName(self.folder, 'portal_membership')
self.mtool = getToolByName(self.folder, 'portal_membership')
self.memberdata = self.portal.portal_memberdata
request = self.app.REQUEST
context = getattr(self.portal, 'doc1')
@ -265,7 +345,7 @@ class TestCommentsViewlet(PloneTestCase):
def test_get_commenter_portrait(self):
# Add a user with a member image
self.membership_tool.addMember('jim', 'Jim', ['Member'], [])
self.mtool.addMember('jim', 'Jim', ['Member'], [])
self.memberdata._setPortrait(Image(id='jim',
file=dummy.File(),
title=''), 'jim')
@ -298,7 +378,7 @@ class TestCommentsViewlet(PloneTestCase):
def test_get_commenter_portrait_without_userimage(self):
# Create a user without a user image
self.membership_tool.addMember('jim', 'Jim', ['Member'], [])
self.mtool.addMember('jim', 'Jim', ['Member'], [])
# Add a conversation with a comment
conversation = IConversation(self.portal.doc1)