084d2893e7
Moderator is not forced to delete a comment or to let it pending: Workflow has two more states "rejected" and "spam" to existing review workflow. Moderation view extended showing all states. Filter by state.
560 lines
18 KiB
Plaintext
560 lines
18 KiB
Plaintext
======================
|
|
plone.app.discussion
|
|
======================
|
|
|
|
This is a functional test for the plone.app.discussion comments viewlet.
|
|
|
|
We use zope.testbrowser to simulate browser interaction in order to show how
|
|
the plone.app.discussion commenting works.
|
|
|
|
|
|
Setting up and loggin in
|
|
------------------------
|
|
|
|
First we have to set up some things and login.
|
|
|
|
>>> app = layer['app']
|
|
>>> from plone.testing.z2 import Browser
|
|
>>> browser = Browser(app)
|
|
>>> browser.handleErrors = False
|
|
>>> browser.addHeader('Authorization', 'Basic admin:secret')
|
|
>>> portal = layer['portal']
|
|
>>> portal_url = 'http://nohost/plone'
|
|
|
|
By default, only HTTP error codes (e.g. 500 Server Side Error) are shown when an
|
|
error occurs on the server. To see more details, set handleErrors to False:
|
|
|
|
>>> browser.handleErrors = False
|
|
|
|
We also keep another testbrowser handy for testing how tiles are rendered if
|
|
you're not logged in::
|
|
|
|
>>> unprivileged_browser = Browser(app)
|
|
>>> browser_member = Browser(app)
|
|
>>> browser_user = Browser(app)
|
|
>>> browser_reviewer = Browser(app)
|
|
|
|
Make sure we have a test user from the layer and it uses fancy characters:
|
|
|
|
>>> from Products.CMFCore.utils import getToolByName
|
|
>>> mtool = getToolByName(portal, 'portal_membership', None)
|
|
>>> jim_fullname = mtool.getMemberById('jim').getProperty('fullname')
|
|
>>> jim_fullname
|
|
'Jim Fult\xc3\xb8rn'
|
|
|
|
Enable commenting.
|
|
|
|
>>> from zope.component import queryUtility
|
|
>>> from plone.registry.interfaces import IRegistry
|
|
>>> from plone.app.discussion.interfaces import IDiscussionSettings
|
|
>>> registry = queryUtility(IRegistry)
|
|
>>> settings = registry.forInterface(IDiscussionSettings)
|
|
>>> settings.globally_enabled = True
|
|
|
|
>>> import transaction
|
|
>>> transaction.commit()
|
|
|
|
Create a public page with comments allowed.
|
|
|
|
>>> browser.open(portal['doc1'].absolute_url() + '/edit')
|
|
>>> browser.getControl(name='form.widgets.IDublinCore.title').value = "Doc1"
|
|
>>> browser.getControl(name='form.widgets.IAllowDiscussion.allow_discussion:list').value = ['True']
|
|
>>> browser.getControl('Save').click()
|
|
>>> urldoc1 = browser.url
|
|
|
|
Make sure the document is published:
|
|
|
|
>>> browser.getLink("Publish").click()
|
|
>>> 'Published' in browser.contents
|
|
True
|
|
|
|
Check that the form has been properly submitted
|
|
|
|
>>> browser.url
|
|
'http://nohost/plone/doc1'
|
|
|
|
|
|
Comment Viewlet
|
|
---------------
|
|
|
|
Check that the old comments viewlet does not show up
|
|
|
|
>>> 'discussion_reply_form' in browser.contents
|
|
False
|
|
|
|
Check that the comment form/viewlet shows up
|
|
|
|
>>> 'formfield-form-widgets-in_reply_to' in browser.contents
|
|
True
|
|
|
|
>>> 'formfield-form-widgets-comment-text' in browser.contents
|
|
True
|
|
|
|
|
|
Post a comment as admin
|
|
-----------------------
|
|
|
|
Login as admin.
|
|
|
|
>>> from plone.app.testing import setRoles
|
|
>>> from plone.app.testing import TEST_USER_NAME
|
|
>>> setRoles(portal, 'manager', ['Manager'])
|
|
|
|
Post a comment as admin.
|
|
|
|
>>> browser.getControl(name='form.widgets.text').value = "Comment from admin"
|
|
>>> submit = browser.getControl(name='form.buttons.comment')
|
|
>>> submit.click()
|
|
|
|
Check if comment has been added properly.
|
|
|
|
>>> '<a href="http://nohost/plone/author/admin">admin</a>' in browser.contents
|
|
True
|
|
|
|
>>> browser.contents
|
|
'...<a href="http://nohost/plone/author/admin">admin</a>...says:...'
|
|
|
|
>>> "Comment from admin" in browser.contents
|
|
True
|
|
|
|
|
|
Post a comment as user
|
|
----------------------
|
|
|
|
Login as user (without the 'Member' role).
|
|
|
|
>>> browser_user.open(portal_url + '/login_form')
|
|
>>> browser_user.getControl(name='__ac_name').value = 'johndoe'
|
|
>>> browser_user.getControl(name='__ac_password').value = 'secret'
|
|
>>> browser_user.getControl('Log in').click()
|
|
|
|
Users without the 'Reply to item' permission will not see the comment form,
|
|
because they don't have the 'Reply to item' permission. By default, this
|
|
permission is only granted to the 'Member' role.
|
|
|
|
>>> 'form.widgets.text' in browser_user.contents
|
|
False
|
|
|
|
>>> 'form.buttons.comment' in browser_user.contents
|
|
False
|
|
|
|
|
|
Post a comment as member
|
|
------------------------
|
|
|
|
Login as user 'jim'.
|
|
>>> browser_member.open(portal_url + '/login_form')
|
|
>>> browser_member.getControl(name='__ac_name').value = 'jim'
|
|
>>> browser_member.getControl(name='__ac_password').value = 'secret'
|
|
>>> browser_member.getControl('Log in').click()
|
|
|
|
Post a comment as user jim.
|
|
|
|
>>> browser_member.open(urldoc1)
|
|
>>> browser_member.getControl(name='form.widgets.text').value = "Comment from Jim"
|
|
>>> submit = browser_member.getControl(name='form.buttons.comment')
|
|
>>> submit.click()
|
|
|
|
Check if the comment has been added properly.
|
|
|
|
>>> browser_member.contents
|
|
'...<a href="http://nohost/plone/author/jim">Jim Fult\xc3\xb8rn</a>...says:...'
|
|
|
|
>>> "Comment from Jim" in browser_member.contents
|
|
True
|
|
|
|
|
|
Post a comment as anonymous user
|
|
--------------------------------
|
|
|
|
Login and post comment as Anonymous
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
|
|
>>> 'Log in to add comments' in unprivileged_browser.contents
|
|
True
|
|
|
|
Enable anonymous comment
|
|
|
|
>>> browser.open(portal_url + '/logout')
|
|
>>> browser.open(portal_url + '/login_form')
|
|
>>> browser.getControl(name='__ac_name').value = 'admin'
|
|
>>> browser.getControl(name='__ac_password').value = 'secret'
|
|
>>> browser.getControl('Log in').click()
|
|
>>> browser.open(portal_url+'/@@discussion-controlpanel')
|
|
>>> browser.getControl(name='form.widgets.anonymous_comments:list').value = 'selected'
|
|
>>> browser.getControl(name='form.buttons.save').click()
|
|
>>> browser.open(portal_url + '/logout')
|
|
|
|
Now we can post an anonymous comment.
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "This is an anonymous comment"
|
|
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
|
|
|
|
>>> '<span>Anonymous</span>' in unprivileged_browser.contents
|
|
True
|
|
|
|
>>> 'says' in unprivileged_browser.contents
|
|
True
|
|
|
|
>>> 'This is an anonymous comment' in unprivileged_browser.contents
|
|
True
|
|
|
|
Make sure special characters work as well.
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
>>> tarek_fullname = "Tarek Ziadé"
|
|
>>> unprivileged_browser.getControl(name='form.widgets.author_name').value = tarek_fullname
|
|
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "This is an äüö comment"
|
|
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
|
|
|
|
>>> tarek_fullname in unprivileged_browser.contents
|
|
True
|
|
|
|
>>> 'says' in unprivileged_browser.contents
|
|
True
|
|
|
|
>>> 'This is an äüö comment' in unprivileged_browser.contents
|
|
True
|
|
|
|
|
|
Reply to an existing comment
|
|
----------------------------
|
|
|
|
Check that there is no existing direct reply to a comment.
|
|
|
|
>>> 'replyTreeLevel1' in browser.contents
|
|
False
|
|
|
|
Find a comment id to reply to.
|
|
|
|
>>> browser.open(urldoc1)
|
|
>>> import re
|
|
>>> comment_div = re.findall('<div.*?.class="comment.*?>', browser.contents)[0]
|
|
>>> id = re.findall('"([^"]*)"', comment_div)[1]
|
|
|
|
Post a reply to an existing comment.
|
|
|
|
>>> browser.getControl(name='form.widgets.in_reply_to').value = id
|
|
>>> browser.getControl(name='form.widgets.text').value = "Reply comment"
|
|
>>> browser.getControl(name='form.buttons.comment').click()
|
|
|
|
Check that the reply has been posted properly.
|
|
|
|
>>> 'Reply comment' in browser.contents
|
|
True
|
|
|
|
>>> 'replyTreeLevel1' in browser.contents
|
|
True
|
|
|
|
|
|
Edit an existing comment
|
|
------------------------
|
|
|
|
Log in as admin
|
|
|
|
>>> browser.getLink('Log out').click()
|
|
>>> browser.open(portal_url + '/login_form')
|
|
>>> browser.getControl('Login Name').value = 'admin'
|
|
>>> browser.getControl('Password').value = 'secret'
|
|
>>> browser.getControl('Log in').click()
|
|
|
|
Use the Plone control panel to enable comment editing.
|
|
|
|
>>> browser.open(portal_url + '/@@overview-controlpanel')
|
|
>>> browser.getLink('Discussion').click()
|
|
>>> browser.getControl('Enable editing of comments').selected = True
|
|
>>> browser.getControl(name='form.buttons.save').click()
|
|
|
|
Extract the edit comment url from the first "edit comment" button
|
|
|
|
>>> from Products.CMFPlone import __version__
|
|
>>> browser.open(urldoc1)
|
|
>>> url = __version__[0] == '5' and browser.getLink(url='@@edit-comment').url or browser.getForm(name='edit', index=0).action
|
|
>>> '@@edit-comment' in url
|
|
True
|
|
|
|
Open the edit comment view
|
|
|
|
>>> browser.open(url)
|
|
>>> ctrl = browser.getControl('Comment')
|
|
>>> ctrl.value
|
|
'Comment from admin'
|
|
|
|
Change and save the comment
|
|
|
|
>>> ctrl.value = 'Comment from admin / was edited'
|
|
>>> browser.getControl('Edit comment').click()
|
|
|
|
This used to trigger permissions problems in some portlet configurations.
|
|
Check it ain't so.
|
|
|
|
>>> 'require_login' in browser.url
|
|
False
|
|
>>> browser.url.startswith('http://nohost/plone/doc1')
|
|
True
|
|
>>> 'Comment from admin / was edited' in browser.contents
|
|
True
|
|
|
|
Opening the edit comment view, then cancel, does nothing.
|
|
|
|
>>> url = __version__[0] == '5' and browser.getLink(url='@@edit-comment').url or browser.getForm(name='edit', index=0).action
|
|
>>> '@@edit-comment' in url
|
|
True
|
|
>>> browser.open(url)
|
|
>>> browser.getControl('Cancel').click()
|
|
>>> browser.url.startswith('http://nohost/plone/doc1')
|
|
True
|
|
|
|
|
|
Anon cannot edit comments.
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
>>> '@@edit-comments' in browser.contents
|
|
False
|
|
|
|
But Anon can see the edited comment.
|
|
|
|
>>> 'Comment from admin / was edited' in unprivileged_browser.contents
|
|
True
|
|
|
|
|
|
Deleting existing comments | 'Delete comments' permission
|
|
----------------------------------------------------------
|
|
|
|
Anonymous cannot delete comments
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
>>> 'form.button.DeleteComment' in unprivileged_browser.contents
|
|
False
|
|
|
|
A member cannot delete his own comments if he can't review or he isn't a Site Administrator
|
|
|
|
>>> browser_member.open(urldoc1)
|
|
>>> 'form.button.DeleteComment' in browser_member.contents
|
|
False
|
|
|
|
Admin can delete comments
|
|
|
|
>>> browser.open(urldoc1)
|
|
>>> 'form.button.DeleteComment' in browser.contents
|
|
True
|
|
|
|
Extract the delete comment url from the first "delete comment" button
|
|
|
|
>>> browser.open(urldoc1)
|
|
>>> form = browser.getForm(name='delete', index=0)
|
|
>>> delete_url = form.action
|
|
>>> '@@moderate-delete-comment' in delete_url
|
|
True
|
|
>>> comment_id = delete_url.split('/')[-2]
|
|
|
|
Anonymous cannot delete a comment by hitting the delete url directly.
|
|
|
|
>>> unprivileged_browser.open(delete_url)
|
|
|
|
The comment is still there
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
>>> comment_id in unprivileged_browser.contents
|
|
True
|
|
|
|
A Member cannot delete even his own comment by hitting the delete url directly.
|
|
|
|
Extract the member comment id from the admin browser
|
|
|
|
>>> form = browser.getForm(name='delete', index=2)
|
|
>>> delete_url = form.action
|
|
>>> '@@moderate-delete-comment' in delete_url
|
|
True
|
|
>>> comment_id = delete_url.split('/')[-2]
|
|
|
|
Now try to hit that url as the member owning that comment.
|
|
Work around some possible testbrowser breakage and check the result later.
|
|
|
|
>>> try:
|
|
... browser_member.open(delete_url)
|
|
... except:
|
|
... pass
|
|
|
|
The comment is still there
|
|
|
|
>>> browser_member.open(urldoc1)
|
|
>>> comment_id in browser_member.contents
|
|
True
|
|
>>> 'Comment from Jim' in browser_member.contents
|
|
True
|
|
|
|
Now login as user 'reviewer'
|
|
|
|
>>> browser_reviewer.open(portal_url + '/login_form')
|
|
>>> browser_reviewer.getControl(name='__ac_name').value = 'reviewer'
|
|
>>> browser_reviewer.getControl(name='__ac_password').value = 'secret'
|
|
>>> browser_reviewer.getControl('Log in').click()
|
|
|
|
Admin and who have 'Delete comments' permission (reviewers for example), can delete comments
|
|
|
|
>>> browser_reviewer.open(urldoc1)
|
|
>>> form = browser_reviewer.getForm(name='delete', index=0)
|
|
>>> '@@moderate-delete-comment' in form.action
|
|
True
|
|
|
|
>>> comment_id = form.action.split('/')[-2]
|
|
|
|
Submitting the form runs into a testbrowser notFoundException.
|
|
We'll just catch that and check the result later.
|
|
|
|
>>> try:
|
|
... form.submit()
|
|
... except:
|
|
... pass
|
|
|
|
Returning to the document we find the deleted comment is indeed gone
|
|
|
|
>>> browser_reviewer.open(urldoc1)
|
|
>>> comment_id in browser_reviewer.contents
|
|
False
|
|
|
|
|
|
Post a comment with comment review workflow enabled
|
|
---------------------------------------------------
|
|
|
|
Enable the 'comment review workflow' for comments.
|
|
|
|
>>> portal.portal_workflow.setChainForPortalTypes(('Discussion Item',), ('comment_review_workflow'),)
|
|
>>> portal.portal_workflow.getChainForPortalType('Discussion Item')
|
|
('comment_review_workflow',)
|
|
|
|
We need to commit the transaction, otherwise setting the workflow will not work.
|
|
|
|
>>> import transaction
|
|
>>> transaction.commit()
|
|
|
|
Post comment as anonymous user.
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "Comment review workflow comment"
|
|
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
|
|
|
|
Make sure the comment has not been published.
|
|
|
|
>>> 'Comment review workflow comment' not in unprivileged_browser.contents
|
|
True
|
|
|
|
Make sure the user gets a notification that the comment awaits moderator
|
|
approval.
|
|
|
|
>>> 'Your comment awaits moderator approval' in unprivileged_browser.contents
|
|
True
|
|
|
|
|
|
Edit the content object after a comment has been posted
|
|
-------------------------------------------------------
|
|
|
|
Make sure we still can edit the content object after a comment has been posted.
|
|
This is a regression test for http://dev.plone.org/plone/ticket/11157
|
|
(TypeError: Can't pickle objects in acquisition wrappers).
|
|
|
|
Login as admin.
|
|
|
|
>>> browser.open(portal_url + '/login_form')
|
|
>>> browser.getControl(name='__ac_name').value = 'admin'
|
|
>>> browser.getControl(name='__ac_password').value = 'secret'
|
|
>>> browser.getControl('Log in').click()
|
|
|
|
Edit the content object.
|
|
|
|
>>> from plone.protect.authenticator import _getKeyring
|
|
>>> import hmac
|
|
>>> from hashlib import sha1 as sha
|
|
>>> ring = _getKeyring('foo')
|
|
>>> secret = ring.random()
|
|
>>> token = hmac.new(secret.encode('utf8'), b'admin', sha).hexdigest()
|
|
>>> browser.open("http://nohost/plone/doc1/edit?_authenticator=" + token)
|
|
>>> browser.getControl(name='form.widgets.IRichTextBehavior.text').value = "Lorem ipsum"
|
|
>>> browser.getControl('Save').click()
|
|
|
|
Make sure the edit was successful.
|
|
|
|
>>> 'Lorem ipsum' in browser.contents
|
|
True
|
|
|
|
|
|
Require anonymous email
|
|
-----------------------
|
|
|
|
Edit the control panel.
|
|
|
|
>>> browser.open(portal_url + '/logout')
|
|
>>> browser.open(portal_url + '/login_form')
|
|
>>> browser.getControl(name='__ac_name').value = 'admin'
|
|
>>> browser.getControl(name='__ac_password').value = 'secret'
|
|
>>> browser.getControl('Log in').click()
|
|
>>> browser.open(portal_url+'/@@discussion-controlpanel')
|
|
>>> browser.getControl(name='form.widgets.anonymous_email_enabled:list').value = 'selected'
|
|
>>> browser.getControl(name='form.buttons.save').click()
|
|
>>> browser.open(portal_url + '/logout')
|
|
|
|
Post an anonymous comment without setting the email.
|
|
|
|
>>> unprivileged_browser.open(urldoc1)
|
|
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "This is an anonymous comment without email"
|
|
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
|
|
>>> 'Required input is missing' in unprivileged_browser.contents
|
|
True
|
|
|
|
Try again.
|
|
|
|
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "This is an anonymous comment with email"
|
|
>>> unprivileged_browser.getControl(name='form.widgets.author_email').value = "email@example.org"
|
|
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
|
|
>>> 'Required input missing' in unprivileged_browser.contents
|
|
False
|
|
>>> 'Your comment awaits moderator approval' in unprivileged_browser.contents
|
|
True
|
|
|
|
Email is being validated.
|
|
|
|
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "This is an anonymous comment with email"
|
|
>>> unprivileged_browser.getControl(name='form.widgets.author_email').value = "abc"
|
|
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
|
|
>>> 'Invalid email address.' in unprivileged_browser.contents
|
|
True
|
|
>>> 'Your comment awaits moderator approval' in unprivileged_browser.contents
|
|
False
|
|
|
|
Check again with valid email.
|
|
|
|
>>> unprivileged_browser.getControl(name='form.widgets.text').value = "This is an anonymous comment with email"
|
|
>>> unprivileged_browser.getControl(name='form.widgets.author_email').value = "email@example.org"
|
|
>>> unprivileged_browser.getControl(name='form.buttons.comment').click()
|
|
>>> 'Invalid email address.' in unprivileged_browser.contents
|
|
False
|
|
>>> 'Your comment awaits moderator approval' in unprivileged_browser.contents
|
|
True
|
|
|
|
|
|
Posting as member should still work. Especially it should not
|
|
complain about missing input for an invisible author_email field.
|
|
Login as user 'jim'.
|
|
|
|
>>> browser_member.open(portal_url + '/login_form')
|
|
>>> browser_member.getControl(name='__ac_name').value = 'jim'
|
|
>>> browser_member.getControl(name='__ac_password').value = 'secret'
|
|
>>> browser_member.getControl('Log in').click()
|
|
|
|
Post a comment as user jim.
|
|
|
|
>>> browser_member.open(urldoc1)
|
|
>>> browser_member.getControl(name='form.widgets.text').value = "Use the ZODB, Luke!"
|
|
>>> submit = browser_member.getControl(name='form.buttons.comment')
|
|
>>> submit.click()
|
|
|
|
Check if there are no validation errors.
|
|
|
|
>>> 'Required input missing' in browser_member.contents
|
|
False
|
|
>>> 'Your comment awaits moderator approval' in browser_member.contents
|
|
True
|