merge master in filippo_moderation_js

This commit is contained in:
Filippo Campi 2018-09-25 16:31:09 +02:00
commit 3648c3345f
25 changed files with 539 additions and 443 deletions

View File

@ -1,7 +1,7 @@
Changelog Changelog
========= =========
3.0.6 (unreleased) 3.0.7 (unreleased)
------------------ ------------------
Breaking changes: Breaking changes:
@ -14,11 +14,27 @@ New features:
Bug fixes: Bug fixes:
- Fix location of controlpanel events.
[jensens]
- Fixed tests when IRichText behavior is used.
IRichText -> IRichTextBehavior
This is a follow up to `issue 476 <https://github.com/plone/plone.app.contenttypes/issues/476>`_.
[iham]
- Fix commenting and tests in python 3.
[pbauer]
3.0.6 (2018-06-18)
------------------
Bug fixes:
- Fix tests to work with merges plone.login. - Fix tests to work with merges plone.login.
[jensens] [jensens]
- More Python 2 / 3 compatibility. - More Python 2 / 3 compatibility.
[pbauer] [pbauer, hvelarde]
3.0.5 (2018-02-04) 3.0.5 (2018-02-04)

View File

@ -14,6 +14,7 @@ from zope.component import getMultiAdapter
from zope.component import getUtility from zope.component import getUtility
from zope.event import notify from zope.event import notify
from zope.lifecycleevent import ObjectModifiedEvent from zope.lifecycleevent import ObjectModifiedEvent
from .comments import CommentForm
class View(BrowserView): class View(BrowserView):

View File

@ -17,6 +17,7 @@ from plone.z3cform import z2
from plone.z3cform.fieldsets import extensible from plone.z3cform.fieldsets import extensible
from plone.z3cform.interfaces import IWrappedForm from plone.z3cform.interfaces import IWrappedForm
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.utils import safe_unicode
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.statusmessages.interfaces import IStatusMessage from Products.statusmessages.interfaces import IStatusMessage
from six.moves.urllib.parse import quote from six.moves.urllib.parse import quote
@ -32,32 +33,30 @@ from zope.i18n import translate
from zope.i18nmessageid import Message from zope.i18nmessageid import Message
from zope.interface import alsoProvides from zope.interface import alsoProvides
import six
COMMENT_DESCRIPTION_PLAIN_TEXT = _( COMMENT_DESCRIPTION_PLAIN_TEXT = _(
u'comment_description_plain_text', u'comment_description_plain_text',
default=u'You can add a comment by filling out the form below. ' default=u'You can add a comment by filling out the form below. '
u'Plain text formatting.' u'Plain text formatting.',
) )
COMMENT_DESCRIPTION_MARKDOWN = _( COMMENT_DESCRIPTION_MARKDOWN = _(
u'comment_description_markdown', u'comment_description_markdown',
default=u'You can add a comment by filling out the form below. ' default=u'You can add a comment by filling out the form below. '
u'Plain text formatting. You can use the Markdown syntax for ' u'Plain text formatting. You can use the Markdown syntax for '
u'links and images.' u'links and images.',
) )
COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _( COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _(
u'comment_description_intelligent_text', u'comment_description_intelligent_text',
default=u'You can add a comment by filling out the form below. ' default=u'You can add a comment by filling out the form below. '
u'Plain text formatting. Web and email addresses are ' u'Plain text formatting. Web and email addresses are '
u'transformed into clickable links.' u'transformed into clickable links.',
) )
COMMENT_DESCRIPTION_MODERATION_ENABLED = _( COMMENT_DESCRIPTION_MODERATION_ENABLED = _(
u'comment_description_moderation_enabled', u'comment_description_moderation_enabled',
default=u'Comments are moderated.' default=u'Comments are moderated.',
) )
@ -152,13 +151,9 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
# Make sure author_name/ author_email is properly encoded # Make sure author_name/ author_email is properly encoded
if 'author_name' in data: if 'author_name' in data:
author_name = data['author_name'] author_name = safe_unicode(data['author_name'])
if isinstance(author_name, str):
author_name = six.text_type(author_name, 'utf-8')
if 'author_email' in data: if 'author_email' in data:
author_email = data['author_email'] author_email = safe_unicode(data['author_email'])
if isinstance(author_email, str):
author_email = six.text_type(author_email, 'utf-8')
# Set comment author properties for anonymous users or members # Set comment author properties for anonymous users or members
portal_membership = getToolByName(context, 'portal_membership') portal_membership = getToolByName(context, 'portal_membership')
@ -167,21 +162,18 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
'Reply to item', context): 'Reply to item', context):
# Member # Member
member = portal_membership.getAuthenticatedMember() member = portal_membership.getAuthenticatedMember()
# memberdata is stored as utf-8 encoded strings email = safe_unicode(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 == '':
fullname = member.getUserName() fullname = member.getUserName()
elif isinstance(fullname, str): fullname = safe_unicode(fullname)
fullname = six.text_type(fullname, 'utf-8')
author_name = fullname author_name = fullname
if email and isinstance(email, str): email = safe_unicode(email)
email = six.text_type(email, 'utf-8') # XXX: according to IComment interface author_email must not be # noqa T000
# XXX: according to IComment interface author_email must not be
# set for logged in users, cite: # set for logged in users, cite:
# 'for anonymous comments only, set to None for logged in comments' # 'for anonymous comments only, set to None for logged in comments'
author_email = email author_email = email
# /XXX # /XXX # noqa T000
return author_name, author_email return author_name, author_email
@ -228,7 +220,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
raise Unauthorized( raise Unauthorized(
u'Anonymous user tries to post a comment, but anonymous ' u'Anonymous user tries to post a comment, but anonymous '
u'commenting is disabled. Or user does not have the ' u'commenting is disabled. Or user does not have the '
u"'reply to item' permission." u"'reply to item' permission.",
) )
return comment return comment
@ -240,10 +232,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
# Check if conversation is enabled on this content object # Check if conversation is enabled on this content object
if not self.__parent__.restrictedTraverse( if not self.__parent__.restrictedTraverse(
'@@conversation_view' '@@conversation_view',
).enabled(): ).enabled():
raise Unauthorized( raise Unauthorized(
'Discussion is not enabled for this content object.' 'Discussion is not enabled for this content object.',
) )
# Validation form # Validation form
@ -293,7 +285,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
comment_review_state = workflowTool.getInfoFor( comment_review_state = workflowTool.getInfoFor(
comment, comment,
'review_state', 'review_state',
None None,
) )
if comment_review_state == 'pending' and not can_review: if comment_review_state == 'pending' and not can_review:
# Show info message when comment moderation is enabled # Show info message when comment moderation is enabled

View File

@ -1,5 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from plone.app.controlpanel.interfaces import IConfigurationChangedEvent
from plone.app.discussion.interfaces import _ from plone.app.discussion.interfaces import _
from plone.app.discussion.interfaces import IDiscussionSettings from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.upgrades import update_registry from plone.app.discussion.upgrades import update_registry
@ -7,6 +6,7 @@ from plone.app.registry.browser import controlpanel
from plone.registry.interfaces import IRecordModifiedEvent from plone.registry.interfaces import IRecordModifiedEvent
from plone.registry.interfaces import IRegistry from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.CMFPlone.interfaces.controlpanel import IConfigurationChangedEvent # noqa: E501
from Products.CMFPlone.interfaces.controlpanel import IMailSchema from Products.CMFPlone.interfaces.controlpanel import IMailSchema
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.statusmessages.interfaces import IStatusMessage from Products.statusmessages.interfaces import IStatusMessage
@ -34,7 +34,7 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
u'To enable the moderation workflow for comments, ' u'To enable the moderation workflow for comments, '
u'go to the Types Control Panel, choose ' u'go to the Types Control Panel, choose '
u'"Comment" and set workflow to ' u'"Comment" and set workflow to '
u'"Comment Review Workflow".' u'"Comment Review Workflow".',
) )
def updateFields(self): def updateFields(self):
@ -68,10 +68,10 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
self.widgets['anonymous_comments'].label = _(u'Anonymous Comments') self.widgets['anonymous_comments'].label = _(u'Anonymous Comments')
self.widgets['show_commenter_image'].label = _(u'Commenter Image') self.widgets['show_commenter_image'].label = _(u'Commenter Image')
self.widgets['moderator_notification_enabled'].label = _( self.widgets['moderator_notification_enabled'].label = _(
u'Moderator Email Notification' u'Moderator Email Notification',
) )
self.widgets['user_notification_enabled'].label = _( self.widgets['user_notification_enabled'].label = _(
u'User Email Notification' u'User Email Notification',
) )
@button.buttonAndHandler(_('Save'), name=None) @button.buttonAndHandler(_('Save'), name=None)
@ -92,8 +92,8 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
self.request.response.redirect( self.request.response.redirect(
'{0}/{1}'.format( '{0}/{1}'.format(
self.context.absolute_url(), self.context.absolute_url(),
self.control_panel_view self.control_panel_view,
) ),
) )

View File

@ -13,6 +13,7 @@ from Products.CMFCore.interfaces import IContentish
from Products.CMFPlone.utils import safe_unicode from Products.CMFPlone.utils import safe_unicode
from Products.ZCatalog.interfaces import IZCatalog from Products.ZCatalog.interfaces import IZCatalog
import six
MAX_DESCRIPTION = 25 MAX_DESCRIPTION = 25
@ -70,13 +71,20 @@ def title(object):
@indexer(IComment) @indexer(IComment)
def creator(object): def creator(object):
return object.creator and safe_unicode(object.creator).encode('utf-8') if not object.creator:
return
value = safe_unicode(object.creator)
if six.PY2:
return value.encode('utf8')
return value
@indexer(IComment) @indexer(IComment)
def description(object): def description(object):
# Return the first 25 words of the comment text and append ' [...]' # Return the first 25 words of the comment text and append ' [...]'
text = ' '.join(object.getText(targetMimetype='text/plain').split()[:MAX_DESCRIPTION]) text = ' '.join(
object.getText(targetMimetype='text/plain').split()[:MAX_DESCRIPTION],
)
if len(object.getText().split()) > 25: if len(object.getText().split()) > 25:
text += ' [...]' text += ' [...]'
return text return text

View File

@ -118,7 +118,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
aclpath = [x for x in user.getPhysicalPath() if x] aclpath = [x for x in user.getPhysicalPath() if x]
self._owner = (aclpath, user.getId(),) self._owner = (aclpath, user.getId(),)
self.__ac_local_roles__ = { self.__ac_local_roles__ = {
user.getId(): ['Owner'] user.getId(): ['Owner'],
} }
@property @property
@ -148,7 +148,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
text = self.text text = self.text
if text is None: if text is None:
return '' return ''
if isinstance(text, six.text_type): if six.PY2 and isinstance(text, six.text_type):
text = text.encode('utf8') text = text.encode('utf8')
transform = transforms.convertTo( transform = transforms.convertTo(
targetMimetype, targetMimetype,
@ -162,7 +162,11 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
msg = u'Transform "{0}" => "{1}" not available. Failed to ' \ msg = u'Transform "{0}" => "{1}" not available. Failed to ' \
u'transform comment "{2}".' u'transform comment "{2}".'
logger.error( logger.error(
msg.format(sourceMimetype, targetMimetype, self.absolute_url()) msg.format(
sourceMimetype,
targetMimetype,
self.absolute_url(),
),
) )
return text return text
@ -174,10 +178,12 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
if not self.author_name: if not self.author_name:
author_name = translate( author_name = translate(
Message(_( Message(
_(
u'label_anonymous', u'label_anonymous',
default=u'Anonymous' default=u'Anonymous',
)) ),
),
) )
else: else:
author_name = self.author_name author_name = self.author_name
@ -284,11 +290,11 @@ def notify_content_object_moved(obj, event):
old_path = '/'.join( old_path = '/'.join(
event.oldParent.getPhysicalPath() + event.oldParent.getPhysicalPath() +
(event.oldName,) + (event.oldName,) +
moved_path moved_path,
) )
brains = catalog.searchResults(dict( brains = catalog.searchResults(dict(
path={'query': old_path}, path={'query': old_path},
portal_type='Discussion Item' portal_type='Discussion Item',
)) ))
for brain in brains: for brain in brains:
catalog.uncatalog_object(brain.getPath()) catalog.uncatalog_object(brain.getPath())
@ -350,24 +356,28 @@ def notify_user(obj, event):
mapping={ mapping={
'title': safe_unicode(content_object.title), 'title': safe_unicode(content_object.title),
'link': content_object.absolute_url() + '/view#' + obj.id, 'link': content_object.absolute_url() + '/view#' + obj.id,
'text': obj.text 'text': obj.text,
} },
), ),
context=obj.REQUEST context=obj.REQUEST,
) )
for email in emails: for email in emails:
# Send email # Send email
try: try:
mail_host.send(message, mail_host.send(
message,
email, email,
sender, sender,
subject, subject,
charset='utf-8') charset='utf-8',
)
except SMTPException: except SMTPException:
logger.error('SMTP exception while trying to send an ' + logger.error(
'SMTP exception while trying to send an ' +
'email from %s to %s', 'email from %s to %s',
sender, sender,
email) email,
)
def notify_moderator(obj, event): def notify_moderator(obj, event):
@ -420,19 +430,21 @@ def notify_moderator(obj, event):
'text': obj.text, 'text': obj.text,
'link_approve': link_approve, 'link_approve': link_approve,
'link_delete': link_delete, 'link_delete': link_delete,
} },
), ),
context=obj.REQUEST context=obj.REQUEST,
) )
# Send email # Send email
try: try:
mail_host.send(message, mto, sender, subject, charset='utf-8') mail_host.send(message, mto, sender, subject, charset='utf-8')
except SMTPException as e: except SMTPException as e:
logger.error('SMTP exception (%s) while trying to send an ' + logger.error(
'SMTP exception (%s) while trying to send an ' +
'email notification to the comment moderator ' + 'email notification to the comment moderator ' +
'(from %s to %s, message: %s)', '(from %s to %s, message: %s)',
e, e,
sender, sender,
mto, mto,
message) message,
)

View File

@ -161,7 +161,7 @@ class Conversation(Traversable, Persistent, Explicit):
comment = aq_base(comment) comment = aq_base(comment)
id = long(time.time() * 1e6) id = int(time.time() * 1e6)
while id in self._comments: while id in self._comments:
id += 1 id += 1
@ -206,22 +206,22 @@ class Conversation(Traversable, Persistent, Explicit):
return len(self._comments) return len(self._comments)
def __contains__(self, key): def __contains__(self, key):
return long(key) in self._comments return int(key) in self._comments
def __getitem__(self, key): def __getitem__(self, key):
"""Get an item by its long key """Get an item by its int key
""" """
try: try:
comment_id = long(key) comment_id = int(key)
except ValueError: except ValueError:
return return
return self._comments[comment_id].__of__(self) return self._comments[comment_id].__of__(self)
def __delitem__(self, key, suppress_container_modified=False): def __delitem__(self, key, suppress_container_modified=False):
"""Delete an item by its long key """Delete an item by its int key
""" """
key = long(key) key = int(key)
comment = self[key].__of__(self) comment = self[key].__of__(self)
commentator = comment.author_username commentator = comment.author_username
@ -260,7 +260,7 @@ class Conversation(Traversable, Persistent, Explicit):
return iter(self._comments) return iter(self._comments)
def get(self, key, default=None): def get(self, key, default=None):
comment = self._comments.get(long(key), default) comment = self._comments.get(int(key), default)
if comment is default: if comment is default:
return default return default
return comment.__of__(self) return comment.__of__(self)
@ -347,20 +347,20 @@ class ConversationReplies(object):
return len(self.children) return len(self.children)
def __contains__(self, key): def __contains__(self, key):
return long(key) in self.children return int(key) in self.children
def __getitem__(self, key): def __getitem__(self, key):
"""Get an item by its long key """Get an item by its int key
""" """
key = long(key) key = int(key)
if key not in self.children: if key not in self.children:
raise KeyError(key) raise KeyError(key)
return self.conversation[key] return self.conversation[key]
def __delitem__(self, key): def __delitem__(self, key):
"""Delete an item by its long key """Delete an item by its int key
""" """
key = long(key) key = int(key)
if key not in self.children: if key not in self.children:
raise KeyError(key) raise KeyError(key)
del self.conversation[key] del self.conversation[key]
@ -369,7 +369,7 @@ class ConversationReplies(object):
return iter(self.children) return iter(self.children)
def get(self, key, default=None): def get(self, key, default=None):
key = long(key) key = int(key)
if key not in self.children: if key not in self.children:
return default return default
return self.conversation.get(key) return self.conversation.get(key)
@ -418,7 +418,7 @@ class CommentReplies(ConversationReplies):
self.conversation = aq_parent(self.comment) self.conversation = aq_parent(self.comment)
conversation_has_no_children = not hasattr( conversation_has_no_children = not hasattr(
self.conversation, self.conversation,
'_children' '_children',
) )
if self.conversation is None or conversation_has_no_children: if self.conversation is None or conversation_has_no_children:
raise TypeError("This adapter doesn't know what to do with the " raise TypeError("This adapter doesn't know what to do with the "

View File

@ -59,7 +59,8 @@ class IConversation(IIterableMapping):
public_commentators = schema.Set( public_commentators = schema.Set(
title=_( title=_(
u'The set of unique commentators (usernames) of published_comments' u'The set of unique commentators (usernames) '
u'of published_comments',
), ),
readonly=True, readonly=True,
) )
@ -174,15 +175,15 @@ class IComment(Interface):
text = schema.Text( text = schema.Text(
title=_( title=_(
u'label_comment', u'label_comment',
default=u'Comment' default=u'Comment',
) ),
) )
user_notification = schema.Bool( user_notification = schema.Bool(
title=_( title=_(
u'Notify me of new comments via email.' u'Notify me of new comments via email.',
), ),
required=False required=False,
) )
creator = schema.TextLine(title=_(u'Username of the commenter')) creator = schema.TextLine(title=_(u'Username of the commenter'))
@ -216,7 +217,7 @@ class IDiscussionSettings(Interface):
default=u'If selected, users are able to post comments on the ' default=u'If selected, users are able to post comments on the '
u'site. However, you will still need to enable comments ' u'site. However, you will still need to enable comments '
u'for specific content types, folders or content ' u'for specific content types, folders or content '
u'objects before users will be able to post comments.' u'objects before users will be able to post comments.',
), ),
required=False, required=False,
default=False, default=False,
@ -230,7 +231,7 @@ class IDiscussionSettings(Interface):
default=u'If selected, anonymous users are able to post ' default=u'If selected, anonymous users are able to post '
u'comments without logging in. It is highly ' u'comments without logging in. It is highly '
u'recommended to use a captcha solution to prevent ' u'recommended to use a captcha solution to prevent '
u'spam if this setting is enabled.' u'spam if this setting is enabled.',
), ),
required=False, required=False,
default=False, default=False,
@ -242,15 +243,16 @@ class IDiscussionSettings(Interface):
description=_( description=_(
u'help_anonymous_email_enabled', u'help_anonymous_email_enabled',
default=u'If selected, anonymous user will have to ' default=u'If selected, anonymous user will have to '
u'give their email.'), u'give their email.',
),
required=False, required=False,
default=False default=False,
) )
moderation_enabled = schema.Bool( moderation_enabled = schema.Bool(
title=_( title=_(
u'label_moderation_enabled', u'label_moderation_enabled',
default='Enable comment moderation' default='Enable comment moderation',
), ),
description=_( description=_(
u'help_moderation_enabled', u'help_moderation_enabled',
@ -260,7 +262,7 @@ class IDiscussionSettings(Interface):
u'or "Manager") can approve comments to make them ' u'or "Manager") can approve comments to make them '
u'visible to the public. If you want to enable a ' u'visible to the public. If you want to enable a '
u'custom comment workflow, you have to go to the ' u'custom comment workflow, you have to go to the '
u'types control panel.' u'types control panel.',
), ),
required=False, required=False,
default=False, default=False,
@ -347,7 +349,7 @@ class IDiscussionSettings(Interface):
moderator_email = schema.ASCIILine( moderator_email = schema.ASCIILine(
title=_( title=_(
u'label_moderator_email', u'label_moderator_email',
default=u'Moderator Email Address' default=u'Moderator Email Address',
), ),
description=_( description=_(
u'help_moderator_email', u'help_moderator_email',
@ -359,14 +361,14 @@ class IDiscussionSettings(Interface):
user_notification_enabled = schema.Bool( user_notification_enabled = schema.Bool(
title=_( title=_(
u'label_user_notification_enabled', u'label_user_notification_enabled',
default=u'Enable user email notification' default=u'Enable user email notification',
), ),
description=_( description=_(
u'help_user_notification_enabled', u'help_user_notification_enabled',
default=u'If selected, users can choose to be notified ' default=u'If selected, users can choose to be notified '
u'of new comments by email.'), u'of new comments by email.'),
required=False, required=False,
default=False default=False,
) )

View File

@ -66,7 +66,7 @@
<!-- Control panel event subscribers --> <!-- Control panel event subscribers -->
<subscriber <subscriber
for="plone.app.controlpanel.interfaces.IConfigurationChangedEvent" for="Products.CMFPlone.interfaces.events.IConfigurationChangedEvent"
handler=".browser.controlpanel.notify_configuration_changed" handler=".browser.controlpanel.notify_configuration_changed"
/> />

View File

@ -92,7 +92,7 @@ class PloneAppDiscussion(PloneSandboxLayer):
portal.invokeFactory( portal.invokeFactory(
id='doc1', id='doc1',
title='Document 1', title='Document 1',
type_name='Document' type_name='Document',
) )
@ -119,5 +119,5 @@ PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING = FunctionalTesting(
name='PloneAppDiscussion:Functional') name='PloneAppDiscussion:Functional')
PLONE_APP_DISCUSSION_ROBOT_TESTING = FunctionalTesting( PLONE_APP_DISCUSSION_ROBOT_TESTING = FunctionalTesting(
bases=(PLONE_APP_DISCUSSION_ROBOT_FIXTURE,), bases=(PLONE_APP_DISCUSSION_ROBOT_FIXTURE,),
name='PloneAppDiscussion:Robot' name='PloneAppDiscussion:Robot',
) )

View File

@ -470,9 +470,9 @@ Edit the content object.
>>> from hashlib import sha1 as sha >>> from hashlib import sha1 as sha
>>> ring = _getKeyring('foo') >>> ring = _getKeyring('foo')
>>> secret = ring.random() >>> secret = ring.random()
>>> token = hmac.new(secret, 'admin', sha).hexdigest() >>> token = hmac.new(secret.encode('utf8'), b'admin', sha).hexdigest()
>>> browser.open("http://nohost/plone/doc1/edit?_authenticator=" + token) >>> browser.open("http://nohost/plone/doc1/edit?_authenticator=" + token)
>>> browser.getControl(name='form.widgets.IRichText.text').value = "Lorem ipsum" >>> browser.getControl(name='form.widgets.IRichTextBehavior.text').value = "Lorem ipsum"
>>> browser.getControl('Save').click() >>> browser.getControl('Save').click()
Make sure the edit was successful. Make sure the edit was successful.

View File

@ -26,19 +26,19 @@ class CatalogSetupTest(unittest.TestCase):
def test_catalog_installed(self): def test_catalog_installed(self):
self.assertTrue( self.assertTrue(
'total_comments' in 'total_comments' in
self.portal.portal_catalog.indexes() self.portal.portal_catalog.indexes(),
) )
self.assertTrue( self.assertTrue(
'commentators' in 'commentators' in
self.portal.portal_catalog.indexes() self.portal.portal_catalog.indexes(),
) )
self.assertTrue( self.assertTrue(
'total_comments' in 'total_comments' in
self.portal.portal_catalog.schema() self.portal.portal_catalog.schema(),
) )
self.assertTrue( self.assertTrue(
'in_response_to' in 'in_response_to' in
self.portal.portal_catalog.schema() self.portal.portal_catalog.schema(),
) )
def test_collection_criteria_installed(self): def test_collection_criteria_installed(self):
@ -76,13 +76,14 @@ class ConversationCatalogTest(unittest.TestCase):
new_comment1_id = conversation.addComment(comment1) new_comment1_id = conversation.addComment(comment1)
self.comment_id = new_comment1_id self.comment_id = new_comment1_id
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
self.conversation = conversation self.conversation = conversation
self.brains = brains self.brains = brains
self.doc1_brain = brains[0] self.doc1_brain = brains[0]
@ -99,16 +100,17 @@ class ConversationCatalogTest(unittest.TestCase):
new_comment2_id = self.conversation.addComment(comment2) new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment2_id) '++conversation++default/{0}'.format(new_comment2_id),
) )
comment2.reindexObject() comment2.reindexObject()
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual(doc1_brain.total_comments, 2) self.assertEqual(doc1_brain.total_comments, 2)
@ -116,7 +118,7 @@ class ConversationCatalogTest(unittest.TestCase):
self.assertTrue('last_comment_date' in self.doc1_brain) self.assertTrue('last_comment_date' in self.doc1_brain)
self.assertEqual( self.assertEqual(
self.doc1_brain.last_comment_date, self.doc1_brain.last_comment_date,
datetime(2006, 9, 17, 14, 18, 12) datetime(2006, 9, 17, 14, 18, 12),
) )
# Add another comment and check if last comment date is updated. # Add another comment and check if last comment date is updated.
@ -128,47 +130,50 @@ class ConversationCatalogTest(unittest.TestCase):
new_comment2_id = self.conversation.addComment(comment2) new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment2_id) '++conversation++default/{0}'.format(new_comment2_id),
) )
comment2.reindexObject() comment2.reindexObject()
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual( self.assertEqual(
doc1_brain.last_comment_date, doc1_brain.last_comment_date,
datetime(2009, 9, 17, 14, 18, 12) datetime(2009, 9, 17, 14, 18, 12),
) )
# Remove the comment again # Remove the comment again
del self.conversation[new_comment2_id] del self.conversation[new_comment2_id]
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual( self.assertEqual(
doc1_brain.last_comment_date, doc1_brain.last_comment_date,
datetime(2006, 9, 17, 14, 18, 12) datetime(2006, 9, 17, 14, 18, 12),
) )
# remove all comments # remove all comments
del self.conversation[self.new_comment1_id] del self.conversation[self.new_comment1_id]
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual(doc1_brain.last_comment_date, None) self.assertEqual(doc1_brain.last_comment_date, None)
@ -185,53 +190,57 @@ class ConversationCatalogTest(unittest.TestCase):
new_comment2_id = self.conversation.addComment(comment2) new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment2_id) '++conversation++default/{0}'.format(new_comment2_id),
) )
comment2.reindexObject() comment2.reindexObject()
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual(doc1_brain.commentators, ('Jim', 'Emma')) self.assertEqual(doc1_brain.commentators, ('Jim', 'Emma'))
# remove one comments # remove one comments
del self.conversation[new_comment2_id] del self.conversation[new_comment2_id]
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual(doc1_brain.commentators, ('Jim',)) self.assertEqual(doc1_brain.commentators, ('Jim',))
# remove all comments # remove all comments
del self.conversation[self.new_comment1_id] del self.conversation[self.new_comment1_id]
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual(doc1_brain.commentators, ()) self.assertEqual(doc1_brain.commentators, ())
def test_conversation_indexes_not_in_comments(self): def test_conversation_indexes_not_in_comments(self):
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Discussion Item' portal_type='Discussion Item',
)) ),
)
comment1_brain = brains[0] comment1_brain = brains[0]
self.assertEqual(comment1_brain.commentators, None) self.assertEqual(comment1_brain.commentators, None)
self.assertEqual(comment1_brain.last_comment_date, None) self.assertEqual(comment1_brain.last_comment_date, None)
@ -240,13 +249,14 @@ class ConversationCatalogTest(unittest.TestCase):
def test_dont_index_private_commentators(self): def test_dont_index_private_commentators(self):
self.comment1.manage_permission('View', roles=tuple()) self.comment1.manage_permission('View', roles=tuple())
self.portal.doc1.reindexObject() self.portal.doc1.reindexObject()
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
doc1_brain = brains[0] doc1_brain = brains[0]
self.assertEqual(doc1_brain.commentators, ()) self.assertEqual(doc1_brain.commentators, ())
@ -272,14 +282,15 @@ class CommentCatalogTest(unittest.TestCase):
# Comment brain # Comment brain
self.comment = self.portal.doc1.restrictedTraverse( self.comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id) '++conversation++default/{0}'.format(new_comment1_id),
) )
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.comment.getPhysicalPath()),
'/'.join(self.comment.getPhysicalPath()) },
} ),
)) )
self.comment_brain = brains[0] self.comment_brain = brains[0]
def test_title(self): def test_title(self):
@ -292,14 +303,15 @@ class CommentCatalogTest(unittest.TestCase):
# Comment brain # Comment brain
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(cid) '++conversation++default/{0}'.format(cid),
) )
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(comment.getPhysicalPath()),
'/'.join(comment.getPhysicalPath()) },
} ),
)) )
comment_brain = brains[0] comment_brain = brains[0]
self.assertEqual(comment_brain.Title, 'Anonymous on Document 1') self.assertEqual(comment_brain.Title, 'Anonymous on Document 1')
@ -327,12 +339,13 @@ class CommentCatalogTest(unittest.TestCase):
# Make sure a comment is removed from the catalog as well when it is # Make sure a comment is removed from the catalog as well when it is
# deleted. # deleted.
del self.conversation[self.comment_id] del self.conversation[self.comment_id]
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.comment.getPhysicalPath()),
'/'.join(self.comment.getPhysicalPath()) },
} ),
)) )
self.assertEqual(len(brains), 0) self.assertEqual(len(brains), 0)
def test_reindex_comment(self): def test_reindex_comment(self):
@ -357,17 +370,17 @@ class CommentCatalogTest(unittest.TestCase):
self.portal.invokeFactory( self.portal.invokeFactory(
id='folder1', id='folder1',
title='Folder 1', title='Folder 1',
type_name='Folder' type_name='Folder',
) )
self.portal.invokeFactory( self.portal.invokeFactory(
id='folder2', id='folder2',
title='Folder 2', title='Folder 2',
type_name='Folder' type_name='Folder',
) )
self.portal.folder1.invokeFactory( self.portal.folder1.invokeFactory(
id='moveme', id='moveme',
title='Move Me', title='Move Me',
type_name='Document' type_name='Document',
) )
conversation = IConversation(self.portal.folder1.moveme) conversation = IConversation(self.portal.folder1.moveme)
comment = createObject('plone.Comment') comment = createObject('plone.Comment')
@ -380,43 +393,57 @@ class CommentCatalogTest(unittest.TestCase):
self.portal.folder2.manage_pasteObjects(cp) self.portal.folder2.manage_pasteObjects(cp)
# Make sure no old comment brains are # Make sure no old comment brains are
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
portal_type='Discussion Item', dict(
path={'query': '/'.join(self.portal.folder1.getPhysicalPath())}
))
self.assertEqual(len(brains), 0)
brains = self.catalog.searchResults(dict(
portal_type='Discussion Item', portal_type='Discussion Item',
path={ path={
'query': '/'.join(self.portal.folder2.getPhysicalPath()) 'query': '/'.join(self.portal.folder1.getPhysicalPath()),
} },
)) ),
)
self.assertEqual(len(brains), 0)
brains = self.catalog.searchResults(
dict(
portal_type='Discussion Item',
path={
'query': '/'.join(self.portal.folder2.getPhysicalPath()),
},
),
)
self.assertEqual(len(brains), 1) self.assertEqual(len(brains), 1)
self.assertEqual( self.assertEqual(
brains[0].getPath(), brains[0].getPath(),
'/plone/folder2/moveme/++conversation++default/' + '/plone/folder2/moveme/++conversation++default/' +
str(comment_id) str(comment_id),
) )
def test_move_upper_level_folder(self): def test_move_upper_level_folder(self):
# create a folder with a nested structure # create a folder with a nested structure
self.portal.invokeFactory(id='sourcefolder', self.portal.invokeFactory(
id='sourcefolder',
title='Source Folder', title='Source Folder',
type_name='Folder') type_name='Folder',
self.portal.sourcefolder.invokeFactory(id='moveme', )
self.portal.sourcefolder.invokeFactory(
id='moveme',
title='Move Me', title='Move Me',
type_name='Folder') type_name='Folder',
self.portal.sourcefolder.moveme.invokeFactory(id='mydocument', )
self.portal.sourcefolder.moveme.invokeFactory(
id='mydocument',
title='My Document', title='My Document',
type_name='Folder') type_name='Folder',
self.portal.invokeFactory(id='targetfolder', )
self.portal.invokeFactory(
id='targetfolder',
title='Target Folder', title='Target Folder',
type_name='Folder') type_name='Folder',
)
# create comment on my-document # create comment on my-document
conversation = IConversation( conversation = IConversation(
self.portal.sourcefolder.moveme.mydocument self.portal.sourcefolder.moveme.mydocument,
) )
comment = createObject('plone.Comment') comment = createObject('plone.Comment')
comment_id = conversation.addComment(comment) comment_id = conversation.addComment(comment)
@ -429,22 +456,26 @@ class CommentCatalogTest(unittest.TestCase):
self.portal.targetfolder.manage_pasteObjects(cp) self.portal.targetfolder.manage_pasteObjects(cp)
# Make sure no old comment brains are left # Make sure no old comment brains are left
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
portal_type='Discussion Item', portal_type='Discussion Item',
path={'query': '/plone/sourcefolder/moveme'} path={'query': '/plone/sourcefolder/moveme'},
)) ),
)
self.assertEqual(len(brains), 0) self.assertEqual(len(brains), 0)
# make sure comments are correctly index on the target # make sure comments are correctly index on the target
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
portal_type='Discussion Item', portal_type='Discussion Item',
path={'query': '/plone/targetfolder/moveme'} path={'query': '/plone/targetfolder/moveme'},
)) ),
)
self.assertEqual(len(brains), 1) self.assertEqual(len(brains), 1)
self.assertEqual( self.assertEqual(
brains[0].getPath(), brains[0].getPath(),
'/plone/targetfolder/moveme/mydocument/++conversation++default/' + '/plone/targetfolder/moveme/mydocument/++conversation++default/' +
str(comment_id) str(comment_id),
) )
def test_update_comments_when_content_object_is_renamed(self): def test_update_comments_when_content_object_is_renamed(self):
@ -454,12 +485,13 @@ class CommentCatalogTest(unittest.TestCase):
self.portal.manage_renameObject('doc1', 'doc2') self.portal.manage_renameObject('doc1', 'doc2')
brains = self.catalog.searchResults( brains = self.catalog.searchResults(
portal_type='Discussion Item') portal_type='Discussion Item',
)
self.assertEqual(len(brains), 1) self.assertEqual(len(brains), 1)
self.assertEqual( self.assertEqual(
brains[0].getPath(), brains[0].getPath(),
'/plone/doc2/++conversation++default/' + '/plone/doc2/++conversation++default/' +
str(self.comment_id) str(self.comment_id),
) )
def test_clear_and_rebuild_catalog(self): def test_clear_and_rebuild_catalog(self):
@ -477,7 +509,7 @@ class CommentCatalogTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
comment_brain.getPath(), comment_brain.getPath(),
'/plone/doc1/++conversation++default/' + '/plone/doc1/++conversation++default/' +
str(self.comment_id) str(self.comment_id),
) )
def test_clear_and_rebuild_catalog_for_nested_comments(self): def test_clear_and_rebuild_catalog_for_nested_comments(self):
@ -549,13 +581,14 @@ class NoConversationCatalogTest(unittest.TestCase):
conversation = IConversation(self.portal.doc1) conversation = IConversation(self.portal.doc1)
brains = self.catalog.searchResults(dict( brains = self.catalog.searchResults(
dict(
path={ path={
'query': 'query': '/'.join(self.portal.doc1.getPhysicalPath()),
'/'.join(self.portal.doc1.getPhysicalPath())
}, },
portal_type='Document' portal_type='Document',
)) ),
)
self.conversation = conversation self.conversation = conversation
self.brains = brains self.brains = brains
self.doc1_brain = brains[0] self.doc1_brain = brains[0]
@ -567,5 +600,5 @@ class NoConversationCatalogTest(unittest.TestCase):
# Make sure no conversation has been created # Make sure no conversation has been created
self.assertTrue( self.assertTrue(
'plone.app.discussion:conversation' not in 'plone.app.discussion:conversation' not in
IAnnotations(self.portal.doc1) IAnnotations(self.portal.doc1),
) )

View File

@ -12,6 +12,7 @@ from zope.component import getMultiAdapter
import datetime import datetime
import logging import logging
import six
import unittest import unittest
@ -54,7 +55,7 @@ class CommentTest(unittest.TestCase):
difference = difference.seconds difference = difference.seconds
# We hope that between comment1 and local_utc happen less than # We hope that between comment1 and local_utc happen less than
# 10 seconds # 10 seconds
self.assertFalse(difference / 10) self.assertFalse(difference // 10)
def test_id(self): def test_id(self):
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
@ -68,7 +69,7 @@ class CommentTest(unittest.TestCase):
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
conversation.addComment(comment1) conversation.addComment(comment1)
comment_brain = self.catalog.searchResults( comment_brain = self.catalog.searchResults(
portal_type='Discussion Item' portal_type='Discussion Item',
)[0] )[0]
self.assertTrue(comment_brain.UID) self.assertTrue(comment_brain.UID)
@ -79,7 +80,7 @@ class CommentTest(unittest.TestCase):
comment2 = createObject('plone.Comment') comment2 = createObject('plone.Comment')
conversation.addComment(comment2) conversation.addComment(comment2)
brains = self.catalog.searchResults( brains = self.catalog.searchResults(
portal_type='Discussion Item' portal_type='Discussion Item',
) )
self.assertNotEqual(brains[0].UID, brains[1].UID) self.assertNotEqual(brains[0].UID, brains[1].UID)
@ -88,7 +89,7 @@ class CommentTest(unittest.TestCase):
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
conversation.addComment(comment1) conversation.addComment(comment1)
comment_brain = self.catalog.searchResults( comment_brain = self.catalog.searchResults(
portal_type='Discussion Item' portal_type='Discussion Item',
)[0] )[0]
self.assertNotEqual(self.document_brain.UID, comment_brain.UID) self.assertNotEqual(self.document_brain.UID, comment_brain.UID)
@ -109,7 +110,7 @@ class CommentTest(unittest.TestCase):
self.portal.invokeFactory( self.portal.invokeFactory(
id='doc_sp_chars', id='doc_sp_chars',
title=u'Document äüö', title=u'Document äüö',
type_name='Document' type_name='Document',
) )
conversation = IConversation(self.portal.doc_sp_chars) conversation = IConversation(self.portal.doc_sp_chars)
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
@ -121,7 +122,7 @@ class CommentTest(unittest.TestCase):
self.portal.invokeFactory( self.portal.invokeFactory(
id='doc_sp_chars_utf8', id='doc_sp_chars_utf8',
title='Document ëïû', title='Document ëïû',
type_name='Document' type_name='Document',
) )
conversation = IConversation(self.portal.doc_sp_chars_utf8) conversation = IConversation(self.portal.doc_sp_chars_utf8)
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
@ -157,7 +158,7 @@ class CommentTest(unittest.TestCase):
comment1.text = 'First paragraph\n\nSecond_paragraph' comment1.text = 'First paragraph\n\nSecond_paragraph'
self.assertEqual( self.assertEqual(
''.join(comment1.getText().split()), ''.join(comment1.getText().split()),
'<p>Firstparagraph<br/><br/>Second_paragraph</p>' '<p>Firstparagraph<br/><br/>Second_paragraph</p>',
) )
def test_getText_escapes_HTML(self): def test_getText_escapes_HTML(self):
@ -165,23 +166,28 @@ class CommentTest(unittest.TestCase):
comment1.text = '<b>Got HTML?</b>' comment1.text = '<b>Got HTML?</b>'
self.assertEqual( self.assertEqual(
comment1.getText(), comment1.getText(),
'<p>&lt;b&gt;Got HTML?&lt;/b&gt;</p>' '<p>&lt;b&gt;Got HTML?&lt;/b&gt;</p>',
) )
def test_getText_with_non_ascii_characters(self): def test_getText_with_non_ascii_characters(self):
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
comment1.text = u'Umlaute sind ä, ö und ü.' comment1.text = u'Umlaute sind ä, ö und ü.'
out = b'<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>'
if six.PY2:
self.assertEqual( self.assertEqual(
comment1.getText(), comment1.getText(),
'<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>' out)
) else:
self.assertEqual(
comment1.getText(),
out.decode('utf8'))
def test_getText_doesnt_link(self): def test_getText_doesnt_link(self):
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
comment1.text = 'Go to http://www.plone.org' comment1.text = 'Go to http://www.plone.org'
self.assertEqual( self.assertEqual(
comment1.getText(), comment1.getText(),
'<p>Go to http://www.plone.org</p>' '<p>Go to http://www.plone.org</p>',
) )
def test_getText_uses_comment_mime_type(self): def test_getText_uses_comment_mime_type(self):
@ -191,7 +197,7 @@ class CommentTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
comment1.getText(), comment1.getText(),
'Go to <a href="http://www.plone.org" ' + 'Go to <a href="http://www.plone.org" ' +
'rel="nofollow">http://www.plone.org</a>' 'rel="nofollow">http://www.plone.org</a>',
) )
def test_getText_uses_comment_mime_type_html(self): def test_getText_uses_comment_mime_type_html(self):
@ -200,7 +206,7 @@ class CommentTest(unittest.TestCase):
comment1.mime_type = 'text/html' comment1.mime_type = 'text/html'
self.assertEqual( self.assertEqual(
comment1.getText(), comment1.getText(),
'Go to <a href="http://www.plone.org">plone.org</a>' 'Go to <a href="http://www.plone.org">plone.org</a>',
) )
def test_getText_w_custom_targetMimetype(self): def test_getText_w_custom_targetMimetype(self):
@ -230,20 +236,20 @@ class CommentTest(unittest.TestCase):
new_comment1_id = conversation.addComment(comment1) new_comment1_id = conversation.addComment(comment1)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id) '++conversation++default/{0}'.format(new_comment1_id),
) )
self.assertTrue(IComment.providedBy(comment)) self.assertTrue(IComment.providedBy(comment))
self.assertEqual( self.assertEqual(
( (
'', 'plone', 'doc1', '++conversation++default', '', 'plone', 'doc1', '++conversation++default',
str(new_comment1_id) str(new_comment1_id),
), ),
comment.getPhysicalPath() comment.getPhysicalPath(),
) )
self.assertEqual( self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' + 'http://nohost/plone/doc1/++conversation++default/' +
str(new_comment1_id), comment.absolute_url() str(new_comment1_id), comment.absolute_url(),
) )
def test_view_blob_types(self): def test_view_blob_types(self):
@ -254,7 +260,7 @@ class CommentTest(unittest.TestCase):
self.portal.invokeFactory( self.portal.invokeFactory(
id='image1', id='image1',
title='Image', title='Image',
type_name='Image' type_name='Image',
) )
conversation = IConversation(self.portal.image1) conversation = IConversation(self.portal.image1)
@ -262,7 +268,7 @@ class CommentTest(unittest.TestCase):
comment1.text = 'Comment text' comment1.text = 'Comment text'
new_comment1_id = conversation.addComment(comment1) new_comment1_id = conversation.addComment(comment1)
comment = self.portal.image1.restrictedTraverse( comment = self.portal.image1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id) '++conversation++default/{0}'.format(new_comment1_id),
) )
view = View(comment, self.request) view = View(comment, self.request)
@ -275,7 +281,8 @@ class CommentTest(unittest.TestCase):
""" """
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('comment_review_workflow,')) ('comment_review_workflow,'),
)
conversation = IConversation(self.portal.doc1) conversation = IConversation(self.portal.doc1)
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
@ -290,15 +297,15 @@ class CommentTest(unittest.TestCase):
# Ensure the initial state was entered and recorded # Ensure the initial state was entered and recorded
self.assertEqual( self.assertEqual(
1, 1,
len(comment.workflow_history['comment_review_workflow']) len(comment.workflow_history['comment_review_workflow']),
) )
self.assertEqual( self.assertEqual(
None, None,
comment.workflow_history['comment_review_workflow'][0]['action'] comment.workflow_history['comment_review_workflow'][0]['action'],
) )
self.assertEqual( self.assertEqual(
'pending', 'pending',
self.portal.portal_workflow.getInfoFor(comment, 'review_state') self.portal.portal_workflow.getInfoFor(comment, 'review_state'),
) )
def test_fti(self): def test_fti(self):
@ -306,7 +313,7 @@ class CommentTest(unittest.TestCase):
self.assertIn( self.assertIn(
'Discussion Item', 'Discussion Item',
self.portal.portal_types.objectIds() self.portal.portal_types.objectIds(),
) )
comment1 = createObject('plone.Comment') comment1 = createObject('plone.Comment')
@ -330,12 +337,16 @@ class CommentTest(unittest.TestCase):
new_comment1_id = conversation.addComment(comment1) new_comment1_id = conversation.addComment(comment1)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_comment1_id) '++conversation++default/{0}'.format(new_comment1_id),
) )
# make sure the view is there # make sure the view is there
self.assertTrue(getMultiAdapter((comment, self.request), self.assertTrue(
name='view')) getMultiAdapter(
(comment, self.request),
name='view',
),
)
# make sure the HTTP redirect (status code 302) works when a comment # make sure the HTTP redirect (status code 302) works when a comment
# is called directly # is called directly
@ -371,7 +382,7 @@ class RepliesTest(unittest.TestCase):
comment.text = 'Comment text' comment.text = 'Comment text'
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id) '++conversation++default/{0}'.format(new_id),
) )
# Add a reply to the CommentReplies adapter of the first comment # Add a reply to the CommentReplies adapter of the first comment
@ -408,7 +419,7 @@ class RepliesTest(unittest.TestCase):
comment.text = 'Comment text' comment.text = 'Comment text'
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id) '++conversation++default/{0}'.format(new_id),
) )
# Add a reply to the CommentReplies adapter of the first comment # Add a reply to the CommentReplies adapter of the first comment
@ -444,7 +455,7 @@ class RepliesTest(unittest.TestCase):
comment.text = 'Comment text' comment.text = 'Comment text'
new_id = conversation.addComment(comment) new_id = conversation.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id) '++conversation++default/{0}'.format(new_id),
) )
# Add a reply to the CommentReplies adapter of the first comment # Add a reply to the CommentReplies adapter of the first comment
@ -453,7 +464,7 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(comment) replies = IReplies(comment)
new_re_id = replies.addComment(re_comment) new_re_id = replies.addComment(re_comment)
re_comment = self.portal.doc1.restrictedTraverse( re_comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_re_id) '++conversation++default/{0}'.format(new_re_id),
) )
# Add a reply to the reply # Add a reply to the reply
@ -462,7 +473,7 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(re_comment) replies = IReplies(re_comment)
new_re_re_id = replies.addComment(re_re_comment) new_re_re_id = replies.addComment(re_re_comment)
re_re_comment = self.portal.doc1.restrictedTraverse( re_re_comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_re_re_id) '++conversation++default/{0}'.format(new_re_re_id),
) )
# Add a reply to the replies reply # Add a reply to the replies reply
@ -471,47 +482,47 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(re_re_comment) replies = IReplies(re_re_comment)
new_re_re_re_id = replies.addComment(re_re_re_comment) new_re_re_re_id = replies.addComment(re_re_re_comment)
re_re_re_comment = self.portal.doc1.restrictedTraverse( re_re_re_comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_re_re_re_id) '++conversation++default/{0}'.format(new_re_re_re_id),
) )
self.assertEqual( self.assertEqual(
('', 'plone', 'doc1', '++conversation++default', str(new_id)), ('', 'plone', 'doc1', '++conversation++default', str(new_id)),
comment.getPhysicalPath() comment.getPhysicalPath(),
) )
self.assertEqual( self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' + 'http://nohost/plone/doc1/++conversation++default/' +
str(new_id), comment.absolute_url() str(new_id), comment.absolute_url(),
) )
self.assertEqual( self.assertEqual(
('', 'plone', 'doc1', '++conversation++default', str(new_re_id)), ('', 'plone', 'doc1', '++conversation++default', str(new_re_id)),
re_comment.getPhysicalPath() re_comment.getPhysicalPath(),
) )
self.assertEqual( self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' + 'http://nohost/plone/doc1/++conversation++default/' +
str(new_re_id), str(new_re_id),
re_comment.absolute_url() re_comment.absolute_url(),
) )
self.assertEqual( self.assertEqual(
( (
'', 'plone', 'doc1', '++conversation++default', '', 'plone', 'doc1', '++conversation++default',
str(new_re_re_id) str(new_re_re_id),
), ),
re_re_comment.getPhysicalPath() re_re_comment.getPhysicalPath(),
) )
self.assertEqual( self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' + 'http://nohost/plone/doc1/++conversation++default/' +
str(new_re_re_id), str(new_re_re_id),
re_re_comment.absolute_url() re_re_comment.absolute_url(),
) )
self.assertEqual( self.assertEqual(
( (
'', 'plone', 'doc1', '++conversation++default', '', 'plone', 'doc1', '++conversation++default',
str(new_re_re_re_id) str(new_re_re_re_id),
), ),
re_re_re_comment.getPhysicalPath() re_re_re_comment.getPhysicalPath(),
) )
self.assertEqual( self.assertEqual(
'http://nohost/plone/doc1/++conversation++default/' + 'http://nohost/plone/doc1/++conversation++default/' +
str(new_re_re_re_id), str(new_re_re_re_id),
re_re_re_comment.absolute_url() re_re_re_comment.absolute_url(),
) )

View File

@ -80,7 +80,7 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u'comment-form' name=u'comment-form',
) )
# The form should return an error if the comment text field is empty # The form should return an error if the comment text field is empty
@ -88,7 +88,7 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u'comment-form' name=u'comment-form',
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -102,7 +102,7 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u'comment-form' name=u'comment-form',
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -144,14 +144,14 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u'comment-form' name=u'comment-form',
) )
provideAdapter( provideAdapter(
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=EditCommentForm, factory=EditCommentForm,
name=u'edit-comment-form' name=u'edit-comment-form',
) )
# The form is submitted successfully, if the required text field is # The form is submitted successfully, if the required text field is
@ -160,7 +160,7 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u'comment-form' name=u'comment-form',
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -174,7 +174,7 @@ class TestCommentForm(unittest.TestCase):
request = make_request(form={'form.widgets.text': u'foobar'}) request = make_request(form={'form.widgets.text': u'foobar'})
editForm = getMultiAdapter( editForm = getMultiAdapter(
(comment, request), (comment, request),
name=u'edit-comment-form' name=u'edit-comment-form',
) )
editForm.update() editForm.update()
data, errors = editForm.extractData() # pylint: disable-msg=W0612 data, errors = editForm.extractData() # pylint: disable-msg=W0612
@ -219,7 +219,7 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u'comment-form' name=u'comment-form',
) )
# The form is submitted successfully, if the required text field is # The form is submitted successfully, if the required text field is
@ -228,7 +228,7 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, form_request), (self.context, form_request),
name=u'comment-form' name=u'comment-form',
) )
commentForm.update() commentForm.update()
@ -241,14 +241,14 @@ class TestCommentForm(unittest.TestCase):
comment = [x for x in conversation.getComments()][-1] comment = [x for x in conversation.getComments()][-1]
deleteView = getMultiAdapter( deleteView = getMultiAdapter(
(comment, self.request), (comment, self.request),
name=u'moderate-delete-comment' name=u'moderate-delete-comment',
) )
# try to delete last comment without 'Delete comments' permission # try to delete last comment without 'Delete comments' permission
setRoles(self.portal, TEST_USER_ID, ['Member']) setRoles(self.portal, TEST_USER_ID, ['Member'])
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
comment.restrictedTraverse, comment.restrictedTraverse,
'@@moderate-delete-comment' '@@moderate-delete-comment',
) )
deleteView() deleteView()
self.assertEqual(1, len([x for x in conversation.getComments()])) self.assertEqual(1, len([x for x in conversation.getComments()]))
@ -277,7 +277,7 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u'comment-form' name=u'comment-form',
) )
# The form is submitted successfully, if the required text field is # The form is submitted successfully, if the required text field is
@ -286,7 +286,7 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, form_request), (self.context, form_request),
name=u'comment-form' name=u'comment-form',
) )
commentForm.update() commentForm.update()
@ -299,7 +299,7 @@ class TestCommentForm(unittest.TestCase):
comment = [x for x in conversation.getComments()][-1] comment = [x for x in conversation.getComments()][-1]
deleteView = getMultiAdapter( deleteView = getMultiAdapter(
(comment, self.request), (comment, self.request),
name=u'delete-own-comment' name=u'delete-own-comment',
) )
# try to delete last comment with johndoe # try to delete last comment with johndoe
setRoles(self.portal, 'johndoe', ['Member']) setRoles(self.portal, 'johndoe', ['Member'])
@ -307,7 +307,7 @@ class TestCommentForm(unittest.TestCase):
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
comment.restrictedTraverse, comment.restrictedTraverse,
'@@delete-own-comment' '@@delete-own-comment',
) )
self.assertEqual(1, len([x for x in conversation.getComments()])) self.assertEqual(1, len([x for x in conversation.getComments()]))
# try to delete last comment with the same user that created it # try to delete last comment with the same user that created it
@ -343,12 +343,12 @@ class TestCommentForm(unittest.TestCase):
# Post an anonymous comment and provide a name # Post an anonymous comment and provide a name
request = make_request(form={ request = make_request(form={
'form.widgets.name': u'john doe', 'form.widgets.name': u'john doe',
'form.widgets.text': u'bar' 'form.widgets.text': u'bar',
}) })
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u'comment-form' name=u'comment-form',
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -391,7 +391,7 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u'comment-form' name=u'comment-form',
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -438,7 +438,7 @@ class TestCommentForm(unittest.TestCase):
Unauthorized, Unauthorized,
commentForm.handleComment, commentForm.handleComment,
commentForm, commentForm,
'foo' 'foo',
) )
@ -454,7 +454,7 @@ class TestCommentsViewlet(unittest.TestCase):
self.folder = self.portal['test-folder'] self.folder = self.portal['test-folder']
interface.alsoProvides( interface.alsoProvides(
self.request, self.request,
interfaces.IDiscussionLayer interfaces.IDiscussionLayer,
) )
self.workflowTool = getToolByName(self.portal, 'portal_workflow') self.workflowTool = getToolByName(self.portal, 'portal_workflow')
@ -532,7 +532,7 @@ class TestCommentsViewlet(unittest.TestCase):
self.viewlet.comment_transform_message(), self.viewlet.comment_transform_message(),
'You can add a comment by filling out the form below. ' + 'You can add a comment by filling out the form below. ' +
'Plain text formatting. Web and email addresses are transformed ' + 'Plain text formatting. Web and email addresses are transformed ' +
'into clickable links.' 'into clickable links.',
) )
# Enable moderation workflow # Enable moderation workflow
@ -567,7 +567,8 @@ class TestCommentsViewlet(unittest.TestCase):
replies = self.viewlet.get_replies() replies = self.viewlet.get_replies()
next(replies) next(replies)
next(replies) next(replies)
self.assertRaises(StopIteration, replies.next) with self.assertRaises(StopIteration):
next(replies)
def test_get_replies_on_non_annotatable_object(self): def test_get_replies_on_non_annotatable_object(self):
context = self.portal.MailHost # the mail host is not annotatable context = self.portal.MailHost # the mail host is not annotatable
@ -575,7 +576,8 @@ class TestCommentsViewlet(unittest.TestCase):
replies = viewlet.get_replies() replies = viewlet.get_replies()
self.assertEqual(len(tuple(replies)), 0) self.assertEqual(len(tuple(replies)), 0)
replies = viewlet.get_replies() replies = viewlet.get_replies()
self.assertRaises(StopIteration, replies.next) with self.assertRaises(StopIteration):
next(replies)
def test_get_replies_with_workflow_actions(self): def test_get_replies_with_workflow_actions(self):
self.assertFalse(self.viewlet.get_replies(workflow_actions=True)) self.assertFalse(self.viewlet.get_replies(workflow_actions=True))
@ -585,25 +587,25 @@ class TestCommentsViewlet(unittest.TestCase):
c1 = conversation.addComment(comment) c1 = conversation.addComment(comment)
self.assertEqual( self.assertEqual(
len(tuple(self.viewlet.get_replies(workflow_actions=True))), len(tuple(self.viewlet.get_replies(workflow_actions=True))),
1 1,
) )
# Enable moderation workflow # Enable moderation workflow
self.workflowTool.setChainForPortalTypes( self.workflowTool.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('comment_review_workflow,') ('comment_review_workflow,'),
) )
# Check if workflow actions are available # Check if workflow actions are available
reply = next(self.viewlet.get_replies(workflow_actions=True)) reply = next(self.viewlet.get_replies(workflow_actions=True))
self.assertTrue('actions' in reply) self.assertTrue('actions' in reply)
self.assertEqual( self.assertEqual(
reply['actions'][0]['id'], reply['actions'][0]['id'],
'publish' 'publish',
) )
expected_url = 'http://nohost/plone/doc1/++conversation++default/{0}' \ expected_url = 'http://nohost/plone/doc1/++conversation++default/{0}' \
'/content_status_modify?workflow_action=publish' '/content_status_modify?workflow_action=publish'
self.assertEqual( self.assertEqual(
reply['actions'][0]['url'], reply['actions'][0]['url'],
expected_url.format(int(c1)) expected_url.format(int(c1)),
) )
def test_get_commenter_home_url(self): def test_get_commenter_home_url(self):
@ -614,7 +616,7 @@ class TestCommentsViewlet(unittest.TestCase):
m = portal_membership.getAuthenticatedMember() m = portal_membership.getAuthenticatedMember()
self.assertEqual( self.assertEqual(
self.viewlet.get_commenter_home_url(m.getUserName()), self.viewlet.get_commenter_home_url(m.getUserName()),
'http://nohost/plone/author/test-user' 'http://nohost/plone/author/test-user',
) )
def test_get_commenter_home_url_is_none(self): def test_get_commenter_home_url_is_none(self):
@ -627,15 +629,15 @@ class TestCommentsViewlet(unittest.TestCase):
self.memberdata._setPortrait(Image( self.memberdata._setPortrait(Image(
id='jim', id='jim',
file=dummy.File(), file=dummy.File(),
title='' title='',
), 'jim') ), 'jim')
self.assertEqual( self.assertEqual(
self.memberdata._getPortrait('jim').getId(), self.memberdata._getPortrait('jim').getId(),
'jim' 'jim',
) )
self.assertEqual( self.assertEqual(
self.memberdata._getPortrait('jim').meta_type, self.memberdata._getPortrait('jim').meta_type,
'Image' 'Image',
) )
# Add a conversation with a comment # Add a conversation with a comment
@ -653,7 +655,7 @@ class TestCommentsViewlet(unittest.TestCase):
# Check if the correct member image URL is returned # Check if the correct member image URL is returned
self.assertEqual( self.assertEqual(
portrait_url, portrait_url,
'http://nohost/plone/portal_memberdata/portraits/jim' 'http://nohost/plone/portal_memberdata/portraits/jim',
) )
def test_get_commenter_portrait_is_none(self): def test_get_commenter_portrait_is_none(self):
@ -662,8 +664,7 @@ class TestCommentsViewlet(unittest.TestCase):
self.viewlet.get_commenter_portrait() in ( self.viewlet.get_commenter_portrait() in (
'defaultUser.png', 'defaultUser.png',
'defaultUser.gif', 'defaultUser.gif',
) ),
) )
def test_get_commenter_portrait_without_userimage(self): def test_get_commenter_portrait_without_userimage(self):
@ -689,8 +690,8 @@ class TestCommentsViewlet(unittest.TestCase):
self.assertTrue( self.assertTrue(
portrait_url in ( portrait_url in (
'http://nohost/plone/defaultUser.png', 'http://nohost/plone/defaultUser.png',
'http://nohost/plone/defaultUser.gif' 'http://nohost/plone/defaultUser.gif',
) ),
) )
def test_anonymous_discussion_allowed(self): def test_anonymous_discussion_allowed(self):
@ -723,7 +724,7 @@ class TestCommentsViewlet(unittest.TestCase):
self.viewlet.update() self.viewlet.update()
self.assertEqual( self.assertEqual(
self.viewlet.login_action(), self.viewlet.login_action(),
'http://nohost/plone/login_form?came_from=http%3A//nohost' 'http://nohost/plone/login_form?came_from=http%3A//nohost',
) )
def test_format_time(self): def test_format_time(self):
@ -737,8 +738,8 @@ class TestCommentsViewlet(unittest.TestCase):
# time of the local time given above. That way, the time for the # time of the local time given above. That way, the time for the
# example below is correct within each time zone, independent of DST # example below is correct within each time zone, independent of DST
python_time = datetime( python_time = datetime(
*time.gmtime(time.mktime(python_time.timetuple()))[:7] *time.gmtime(time.mktime(python_time.timetuple()))[:7])
)
localized_time = self.viewlet.format_time(python_time) localized_time = self.viewlet.format_time(python_time)
self.assertTrue( self.assertTrue(
localized_time in ['Feb 01, 2009 11:32 PM', '2009-02-01 23:32']) localized_time in ['Feb 01, 2009 11:32 PM', '2009-02-01 23:32'],
)

View File

@ -30,7 +30,7 @@ class CommentContentRulesTest(unittest.TestCase):
member = self.portal.portal_membership.getMemberById(TEST_USER_ID) member = self.portal.portal_membership.getMemberById(TEST_USER_ID)
member.setMemberProperties({ member.setMemberProperties({
'fullname': 'X Manager', 'fullname': 'X Manager',
'email': 'xmanager@example.com' 'email': 'xmanager@example.com',
}) })
setRoles(self.portal, TEST_USER_ID, ['Manager']) setRoles(self.portal, TEST_USER_ID, ['Manager'])
@ -54,7 +54,7 @@ class CommentContentRulesTest(unittest.TestCase):
def testCommentIdStringSubstitution(self): def testCommentIdStringSubstitution(self):
comment_id = getAdapter(self.document, IStringSubstitution, comment_id = getAdapter(self.document, IStringSubstitution,
name=u'comment_id') name=u'comment_id')
self.assertIsInstance(comment_id(), long) self.assertIsInstance(comment_id(), int)
def testCommentTextStringSubstitution(self): def testCommentTextStringSubstitution(self):
comment_text = getAdapter(self.document, IStringSubstitution, comment_text = getAdapter(self.document, IStringSubstitution,
@ -96,7 +96,7 @@ class ReplyContentRulesTest(unittest.TestCase):
comment.text = 'This is a comment' comment.text = 'This is a comment'
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.document.restrictedTraverse( comment = self.document.restrictedTraverse(
'++conversation++default/{0}'.format(new_id) '++conversation++default/{0}'.format(new_id),
) )
re_comment = createObject('plone.Comment') re_comment = createObject('plone.Comment')
@ -112,15 +112,15 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_id = getAdapter( reply_id = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u'comment_id' name=u'comment_id',
) )
self.assertIsInstance(reply_id(), long) self.assertIsInstance(reply_id(), int)
def testReplyTextStringSubstitution(self): def testReplyTextStringSubstitution(self):
reply_text = getAdapter( reply_text = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u'comment_text' name=u'comment_text',
) )
self.assertEqual(reply_text(), u'This is a reply') self.assertEqual(reply_text(), u'This is a reply')
@ -128,7 +128,7 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_user_id = getAdapter( reply_user_id = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u'comment_user_id' name=u'comment_user_id',
) )
self.assertEqual(reply_user_id(), u'julia') self.assertEqual(reply_user_id(), u'julia')
@ -136,7 +136,7 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_user_fullname = getAdapter( reply_user_fullname = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u'comment_user_fullname' name=u'comment_user_fullname',
) )
self.assertEqual(reply_user_fullname(), u'Juliana') self.assertEqual(reply_user_fullname(), u'Juliana')
@ -144,6 +144,6 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_user_email = getAdapter( reply_user_email = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u'comment_user_email' name=u'comment_user_email',
) )
self.assertEqual(reply_user_email(), u'julia@example.com') self.assertEqual(reply_user_email(), u'julia@example.com')

View File

@ -29,7 +29,7 @@ class RegistryTest(unittest.TestCase):
def test_discussion_controlpanel_view(self): def test_discussion_controlpanel_view(self):
view = getMultiAdapter( view = getMultiAdapter(
(self.portal, self.portal.REQUEST), (self.portal, self.portal.REQUEST),
name='discussion-controlpanel' name='discussion-controlpanel',
) )
self.assertTrue(view()) self.assertTrue(view())
@ -40,7 +40,7 @@ class RegistryTest(unittest.TestCase):
'discussion' in [ 'discussion' in [
a.getAction(self)['id'] a.getAction(self)['id']
for a in self.controlpanel.listActions() for a in self.controlpanel.listActions()
] ],
) )
def test_globally_enabled(self): def test_globally_enabled(self):
@ -51,7 +51,7 @@ class RegistryTest(unittest.TestCase):
'plone.app.discussion.interfaces.' + 'plone.app.discussion.interfaces.' +
'IDiscussionSettings.globally_enabled' 'IDiscussionSettings.globally_enabled'
], ],
False False,
) )
def test_anonymous_comments(self): def test_anonymous_comments(self):
@ -62,7 +62,7 @@ class RegistryTest(unittest.TestCase):
'plone.app.discussion.interfaces.' + 'plone.app.discussion.interfaces.' +
'IDiscussionSettings.anonymous_comments' 'IDiscussionSettings.anonymous_comments'
], ],
False False,
) )
def test_moderation_enabled(self): def test_moderation_enabled(self):
@ -73,7 +73,7 @@ class RegistryTest(unittest.TestCase):
'plone.app.discussion.interfaces.' + 'plone.app.discussion.interfaces.' +
'IDiscussionSettings.moderation_enabled' 'IDiscussionSettings.moderation_enabled'
], ],
False False,
) )
def test_edit_comment_enabled(self): def test_edit_comment_enabled(self):
@ -82,7 +82,8 @@ class RegistryTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
self.registry['plone.app.discussion.interfaces.' + self.registry['plone.app.discussion.interfaces.' +
'IDiscussionSettings.edit_comment_enabled'], 'IDiscussionSettings.edit_comment_enabled'],
False) False,
)
def test_delete_own_comment_enabled(self): def test_delete_own_comment_enabled(self):
# Check delete_own_comment_enabled record # Check delete_own_comment_enabled record
@ -90,7 +91,8 @@ class RegistryTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
self.registry['plone.app.discussion.interfaces.' + self.registry['plone.app.discussion.interfaces.' +
'IDiscussionSettings.delete_own_comment_enabled'], 'IDiscussionSettings.delete_own_comment_enabled'],
False) False,
)
def test_text_transform(self): def test_text_transform(self):
self.assertTrue('text_transform' in IDiscussionSettings) self.assertTrue('text_transform' in IDiscussionSettings)
@ -99,7 +101,7 @@ class RegistryTest(unittest.TestCase):
'plone.app.discussion.interfaces.' + 'plone.app.discussion.interfaces.' +
'IDiscussionSettings.text_transform' 'IDiscussionSettings.text_transform'
], ],
'text/plain' 'text/plain',
) )
def test_captcha(self): def test_captcha(self):
@ -110,7 +112,7 @@ class RegistryTest(unittest.TestCase):
'plone.app.discussion.interfaces.' + 'plone.app.discussion.interfaces.' +
'IDiscussionSettings.captcha' 'IDiscussionSettings.captcha'
], ],
'disabled' 'disabled',
) )
def test_show_commenter_image(self): def test_show_commenter_image(self):
@ -121,20 +123,20 @@ class RegistryTest(unittest.TestCase):
'plone.app.discussion.interfaces.' + 'plone.app.discussion.interfaces.' +
'IDiscussionSettings.show_commenter_image' 'IDiscussionSettings.show_commenter_image'
], ],
True True,
) )
def test_moderator_notification_enabled(self): def test_moderator_notification_enabled(self):
# Check show_commenter_image record # Check show_commenter_image record
self.assertTrue( self.assertTrue(
'moderator_notification_enabled' in IDiscussionSettings 'moderator_notification_enabled' in IDiscussionSettings,
) )
self.assertEqual( self.assertEqual(
self.registry[ self.registry[
'plone.app.discussion.interfaces.' + 'plone.app.discussion.interfaces.' +
'IDiscussionSettings.moderator_notification_enabled' 'IDiscussionSettings.moderator_notification_enabled'
], ],
False False,
) )
# def test_user_notification_enabled(self): # def test_user_notification_enabled(self):
@ -167,8 +169,8 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
('comment_one_state_workflow',), ('comment_one_state_workflow',),
self.portal.portal_workflow.getChainForPortalType( self.portal.portal_workflow.getChainForPortalType(
'Discussion Item' 'Discussion Item',
) ),
) )
# Enable moderation in the discussion control panel # Enable moderation in the discussion control panel
@ -179,16 +181,16 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
('comment_review_workflow',), ('comment_review_workflow',),
self.portal.portal_workflow.getChainForPortalType( self.portal.portal_workflow.getChainForPortalType(
'Discussion Item' 'Discussion Item',
) ),
) )
# And back # And back
self.settings.moderation_enabled = False self.settings.moderation_enabled = False
self.assertEqual( self.assertEqual(
('comment_one_state_workflow',), ('comment_one_state_workflow',),
self.portal.portal_workflow.getChainForPortalType( self.portal.portal_workflow.getChainForPortalType(
'Discussion Item' 'Discussion Item',
) ),
) )
def test_change_workflow_in_types_control_panel(self): def test_change_workflow_in_types_control_panel(self):
@ -202,7 +204,7 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
# Enable the 'comment_review_workflow' with moderation enabled # Enable the 'comment_review_workflow' with moderation enabled
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('comment_review_workflow',) ('comment_review_workflow',),
) )
# Make sure the moderation_enabled settings has changed # Make sure the moderation_enabled settings has changed
@ -211,14 +213,14 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
# Enable the 'comment_review_workflow' with moderation enabled # Enable the 'comment_review_workflow' with moderation enabled
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('comment_one_state_workflow',) ('comment_one_state_workflow',),
) )
self.settings.moderation_enabled = True self.settings.moderation_enabled = True
# Enable a 'custom' discussion workflow # Enable a 'custom' discussion workflow
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('intranet_workflow',) ('intranet_workflow',),
) )
# Setting has not changed. A Custom workflow disables the # Setting has not changed. A Custom workflow disables the

View File

@ -68,11 +68,11 @@ class ConversationTest(unittest.TestCase):
new_id = conversation.addComment(comment) new_id = conversation.addComment(comment)
# Check that the conversation methods return the correct data # Check that the conversation methods return the correct data
self.assertTrue(isinstance(comment.comment_id, long)) self.assertTrue(isinstance(comment.comment_id, int))
self.assertTrue(IComment.providedBy(conversation[new_id])) self.assertTrue(IComment.providedBy(conversation[new_id]))
self.assertEqual( self.assertEqual(
aq_base(conversation[new_id].__parent__), aq_base(conversation[new_id].__parent__),
aq_base(conversation) aq_base(conversation),
) )
self.assertEqual(new_id, comment.comment_id) self.assertEqual(new_id, comment.comment_id)
self.assertEqual(len(list(conversation.getComments())), 1) self.assertEqual(len(list(conversation.getComments())), 1)
@ -80,7 +80,7 @@ class ConversationTest(unittest.TestCase):
self.assertEqual(conversation.total_comments(), 1) self.assertEqual(conversation.total_comments(), 1)
self.assertTrue( self.assertTrue(
conversation.last_comment_date - datetime.utcnow() < conversation.last_comment_date - datetime.utcnow() <
timedelta(seconds=1) timedelta(seconds=1),
) )
def test_private_comment(self): def test_private_comment(self):
@ -278,7 +278,7 @@ class ConversationTest(unittest.TestCase):
# Create a conversation. # Create a conversation.
conversation = self.portal.doc1.restrictedTraverse( conversation = self.portal.doc1.restrictedTraverse(
'@@conversation_view' '@@conversation_view',
) )
# The Document content type is disabled by default # The Document content type is disabled by default
@ -326,7 +326,7 @@ class ConversationTest(unittest.TestCase):
# Create a conversation. # Create a conversation.
conversation = self.portal.doc1.restrictedTraverse( conversation = self.portal.doc1.restrictedTraverse(
'@@conversation_view' '@@conversation_view',
) )
# Discussion is disallowed by default # Discussion is disallowed by default
@ -396,7 +396,7 @@ class ConversationTest(unittest.TestCase):
self.assertTrue((new_id1, comment1) in six.iteritems(conversation)) self.assertTrue((new_id1, comment1) in six.iteritems(conversation))
self.assertTrue((new_id2, comment2) in six.iteritems(conversation)) self.assertTrue((new_id2, comment2) in six.iteritems(conversation))
# TODO test acquisition wrapping # TODO test acquisition wrapping # noqa T000
# self.assertTrue(aq_base(aq_parent(comment1)) is conversation) # self.assertTrue(aq_base(aq_parent(comment1)) is conversation)
def test_total_comments(self): def test_total_comments(self):
@ -512,11 +512,11 @@ class ConversationTest(unittest.TestCase):
# check if the latest comment is exactly one day old # check if the latest comment is exactly one day old
self.assertTrue( self.assertTrue(
conversation.last_comment_date < datetime.utcnow() - conversation.last_comment_date < datetime.utcnow() -
timedelta(hours=23, minutes=59, seconds=59) timedelta(hours=23, minutes=59, seconds=59),
) )
self.assertTrue( self.assertTrue(
conversation.last_comment_date > conversation.last_comment_date >
datetime.utcnow() - timedelta(days=1, seconds=1) datetime.utcnow() - timedelta(days=1, seconds=1),
) )
# remove the latest comment # remove the latest comment
@ -526,11 +526,11 @@ class ConversationTest(unittest.TestCase):
# the latest comment should be exactly two days old # the latest comment should be exactly two days old
self.assertTrue( self.assertTrue(
conversation.last_comment_date < datetime.utcnow() - conversation.last_comment_date < datetime.utcnow() -
timedelta(days=1, hours=23, minutes=59, seconds=59) timedelta(days=1, hours=23, minutes=59, seconds=59),
) )
self.assertTrue( self.assertTrue(
conversation.last_comment_date > datetime.utcnow() - conversation.last_comment_date > datetime.utcnow() -
timedelta(days=2, seconds=1) timedelta(days=2, seconds=1),
) )
# remove the latest comment again # remove the latest comment again
@ -540,11 +540,11 @@ class ConversationTest(unittest.TestCase):
# the latest comment should be exactly four days old # the latest comment should be exactly four days old
self.assertTrue( self.assertTrue(
conversation.last_comment_date < datetime.utcnow() - conversation.last_comment_date < datetime.utcnow() -
timedelta(days=3, hours=23, minutes=59, seconds=59) timedelta(days=3, hours=23, minutes=59, seconds=59),
) )
self.assertTrue( self.assertTrue(
conversation.last_comment_date > datetime.utcnow() - conversation.last_comment_date > datetime.utcnow() -
timedelta(days=4, seconds=2) timedelta(days=4, seconds=2),
) )
def test_get_comments_full(self): def test_get_comments_full(self):
@ -618,7 +618,7 @@ class ConversationTest(unittest.TestCase):
], list(conversation.getThreads())) ], list(conversation.getThreads()))
def test_get_threads_batched(self): def test_get_threads_batched(self):
# TODO: test start, size, root and depth arguments to getThreads() # TODO: test start, size, root and depth arguments to getThreads() # noqa T000
# - may want to split this into multiple tests # - may want to split this into multiple tests
pass pass
@ -626,25 +626,25 @@ class ConversationTest(unittest.TestCase):
# make sure we can traverse to conversations and get a URL and path # make sure we can traverse to conversations and get a URL and path
conversation = self.portal.doc1.restrictedTraverse( conversation = self.portal.doc1.restrictedTraverse(
'++conversation++default' '++conversation++default',
) )
self.assertTrue(IConversation.providedBy(conversation)) self.assertTrue(IConversation.providedBy(conversation))
self.assertEqual( self.assertEqual(
('', 'plone', 'doc1', '++conversation++default'), ('', 'plone', 'doc1', '++conversation++default'),
conversation.getPhysicalPath() conversation.getPhysicalPath(),
) )
self.assertEqual( self.assertEqual(
'http://nohost/plone/doc1/++conversation++default', 'http://nohost/plone/doc1/++conversation++default',
conversation.absolute_url() conversation.absolute_url(),
) )
def test_unconvertible_id(self): def test_unconvertible_id(self):
# make sure the conversation view doesn't break when given comment id # make sure the conversation view doesn't break when given comment id
# can't be converted to long # can't be converted to int
conversation = self.portal.doc1.restrictedTraverse( conversation = self.portal.doc1.restrictedTraverse(
'++conversation++default/ThisCantBeRight' '++conversation++default/ThisCantBeRight',
) )
self.assertEqual(conversation, None) self.assertEqual(conversation, None)
@ -668,7 +668,7 @@ class ConversationTest(unittest.TestCase):
# Make sure no conversation has been created # Make sure no conversation has been created
self.assertTrue( self.assertTrue(
'plone.app.discussion:conversation' not in 'plone.app.discussion:conversation' not in
IAnnotations(self.portal.doc1) IAnnotations(self.portal.doc1),
) )
@ -681,13 +681,13 @@ class ConversationEnabledForDexterityTypesTest(unittest.TestCase):
setRoles(self.portal, TEST_USER_ID, ['Manager']) setRoles(self.portal, TEST_USER_ID, ['Manager'])
interface.alsoProvides( interface.alsoProvides(
self.portal.REQUEST, self.portal.REQUEST,
interfaces.IDiscussionLayer interfaces.IDiscussionLayer,
) )
if DEXTERITY: if DEXTERITY:
interface.alsoProvides( interface.alsoProvides(
self.portal.doc1, self.portal.doc1,
IDexterityContent IDexterityContent,
) )
def _makeOne(self, *args, **kw): def _makeOne(self, *args, **kw):
@ -847,18 +847,18 @@ class RepliesTest(unittest.TestCase):
# Create the nested comment structure # Create the nested comment structure
new_id_1 = replies.addComment(comment1) new_id_1 = replies.addComment(comment1)
comment1 = self.portal.doc1.restrictedTraverse( comment1 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_1) '++conversation++default/{0}'.format(new_id_1),
) )
replies_to_comment1 = IReplies(comment1) replies_to_comment1 = IReplies(comment1)
new_id_2 = replies.addComment(comment2) new_id_2 = replies.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_2) '++conversation++default/{0}'.format(new_id_2),
) )
replies_to_comment2 = IReplies(comment2) replies_to_comment2 = IReplies(comment2)
new_id_1_1 = replies_to_comment1.addComment(comment1_1) new_id_1_1 = replies_to_comment1.addComment(comment1_1)
comment1_1 = self.portal.doc1.restrictedTraverse( comment1_1 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_1_1) '++conversation++default/{0}'.format(new_id_1_1),
) )
replies_to_comment1_1 = IReplies(comment1_1) replies_to_comment1_1 = IReplies(comment1_1)
replies_to_comment1_1.addComment(comment1_1_1) replies_to_comment1_1.addComment(comment1_1_1)

View File

@ -152,7 +152,7 @@ class RepliesEventsTest(unittest.TestCase):
comment.text = 'Comment text' comment.text = 'Comment text'
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.document.restrictedTraverse( comment = self.document.restrictedTraverse(
'++conversation++default/{0}'.format(new_id) '++conversation++default/{0}'.format(new_id),
) )
re_comment = createObject('plone.Comment') re_comment = createObject('plone.Comment')
@ -173,7 +173,7 @@ class RepliesEventsTest(unittest.TestCase):
comment.text = 'Comment text' comment.text = 'Comment text'
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id) '++conversation++default/{0}'.format(new_id),
) )
re_comment = createObject('plone.Comment') re_comment = createObject('plone.Comment')

View File

@ -25,11 +25,16 @@ normal_testfiles = [
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTests([ suite.addTests([
layered(doctest.DocFileSuite(test, layered(
doctest.DocFileSuite(
test,
optionflags=optionflags, optionflags=optionflags,
globs={'pprint': pprint.pprint, globs={
'pprint': pprint.pprint,
} }
), ),
layer=PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING) layer=PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING,
for test in normal_testfiles]) )
for test in normal_testfiles
])
return suite return suite

View File

@ -70,7 +70,7 @@ class ConversationIndexersTest(unittest.TestCase):
def test_conversation_total_comments(self): def test_conversation_total_comments(self):
self.assertTrue(isinstance( self.assertTrue(isinstance(
catalog.total_comments, catalog.total_comments,
DelegatingIndexerFactory DelegatingIndexerFactory,
)) ))
self.assertEqual(catalog.total_comments(self.portal.doc1)(), 3) self.assertEqual(catalog.total_comments(self.portal.doc1)(), 3)
del self.conversation[self.new_id1] del self.conversation[self.new_id1]
@ -82,16 +82,16 @@ class ConversationIndexersTest(unittest.TestCase):
def test_conversation_last_comment_date(self): def test_conversation_last_comment_date(self):
self.assertTrue(isinstance( self.assertTrue(isinstance(
catalog.last_comment_date, catalog.last_comment_date,
DelegatingIndexerFactory DelegatingIndexerFactory,
)) ))
self.assertEqual( self.assertEqual(
catalog.last_comment_date(self.portal.doc1)(), catalog.last_comment_date(self.portal.doc1)(),
datetime(2009, 4, 12, 11, 12, 12) datetime(2009, 4, 12, 11, 12, 12),
) )
del self.conversation[self.new_id3] del self.conversation[self.new_id3]
self.assertEqual( self.assertEqual(
catalog.last_comment_date(self.portal.doc1)(), catalog.last_comment_date(self.portal.doc1)(),
datetime(2007, 12, 13, 4, 18, 12) datetime(2007, 12, 13, 4, 18, 12),
) )
del self.conversation[self.new_id2] del self.conversation[self.new_id2]
del self.conversation[self.new_id1] del self.conversation[self.new_id1]
@ -138,7 +138,7 @@ class CommentIndexersTest(unittest.TestCase):
def test_description(self): def test_description(self):
self.assertEqual( self.assertEqual(
catalog.description(self.comment)(), catalog.description(self.comment)(),
'Lorem ipsum dolor sit amet.' 'Lorem ipsum dolor sit amet.',
) )
self.assertTrue( self.assertTrue(
isinstance(catalog.description, DelegatingIndexerFactory)) isinstance(catalog.description, DelegatingIndexerFactory))
@ -153,33 +153,33 @@ class CommentIndexersTest(unittest.TestCase):
self.conversation.addComment(comment_long) self.conversation.addComment(comment_long)
self.assertEqual( self.assertEqual(
catalog.description(comment_long)(), catalog.description(comment_long)(),
LONG_TEXT_CUT.replace('\n', ' ') LONG_TEXT_CUT.replace('\n', ' '),
) )
def test_dates(self): def test_dates(self):
# Test if created, modified, effective etc. are set correctly # Test if created, modified, effective etc. are set correctly
self.assertEqual( self.assertEqual(
catalog.created(self.comment)(), catalog.created(self.comment)(),
DateTime(2006, 9, 17, 14, 18, 12, 'GMT') DateTime(2006, 9, 17, 14, 18, 12, 'GMT'),
) )
self.assertEqual( self.assertEqual(
catalog.effective(self.comment)(), catalog.effective(self.comment)(),
DateTime(2006, 9, 17, 14, 18, 12, 'GMT') DateTime(2006, 9, 17, 14, 18, 12, 'GMT'),
) )
self.assertEqual( self.assertEqual(
catalog.modified(self.comment)(), catalog.modified(self.comment)(),
DateTime(2008, 3, 12, 7, 32, 52, 'GMT') DateTime(2008, 3, 12, 7, 32, 52, 'GMT'),
) )
def test_searchable_text(self): def test_searchable_text(self):
# Test if searchable text is a concatenation of title and comment text # Test if searchable text is a concatenation of title and comment text
self.assertEqual( self.assertEqual(
catalog.searchable_text(self.comment)(), catalog.searchable_text(self.comment)(),
('Lorem ipsum dolor sit amet.') ('Lorem ipsum dolor sit amet.'),
) )
self.assertTrue(isinstance( self.assertTrue(isinstance(
catalog.searchable_text, catalog.searchable_text,
DelegatingIndexerFactory DelegatingIndexerFactory,
)) ))
def test_creator(self): def test_creator(self):

View File

@ -69,7 +69,9 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
None) None)
self.context = self.portal self.context = self.portal
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), 'comment_review_workflow') ('Discussion Item',),
'comment_review_workflow',
)
self.wf_tool = self.portal.portal_workflow self.wf_tool = self.portal.portal_workflow
# Add a conversation with three comments # Add a conversation with three comments
conversation = IConversation(self.portal.doc1) conversation = IConversation(self.portal.doc1)
@ -79,7 +81,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment1.Creator = 'Jim' comment1.Creator = 'Jim'
new_id_1 = conversation.addComment(comment1) new_id_1 = conversation.addComment(comment1)
self.comment1 = self.portal.doc1.restrictedTraverse( self.comment1 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_1) '++conversation++default/{0}'.format(new_id_1),
) )
comment2 = createObject('plone.Comment') comment2 = createObject('plone.Comment')
comment2.title = 'Comment 2' comment2.title = 'Comment 2'
@ -87,7 +89,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment2.Creator = 'Joe' comment2.Creator = 'Joe'
new_id_2 = conversation.addComment(comment2) new_id_2 = conversation.addComment(comment2)
self.comment2 = self.portal.doc1.restrictedTraverse( self.comment2 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_2) '++conversation++default/{0}'.format(new_id_2),
) )
comment3 = createObject('plone.Comment') comment3 = createObject('plone.Comment')
comment3.title = 'Comment 3' comment3.title = 'Comment 3'
@ -95,7 +97,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment3.Creator = 'Emma' comment3.Creator = 'Emma'
new_id_3 = conversation.addComment(comment3) new_id_3 = conversation.addComment(comment3)
self.comment3 = self.portal.doc1.restrictedTraverse( self.comment3 = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(new_id_3) '++conversation++default/{0}'.format(new_id_3),
) )
self.conversation = conversation self.conversation = conversation
@ -114,8 +116,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
view = BulkActionsView(self.portal, self.request) view = BulkActionsView(self.portal, self.request)
self.assertRaises(NotImplementedError, self.assertRaises(NotImplementedError, view)
view)
def test_publish(self): def test_publish(self):
self.request.set('form.select.BulkAction', 'publish') self.request.set('form.select.BulkAction', 'publish')
@ -176,12 +177,13 @@ class RedirectionTest(unittest.TestCase):
settings.globally_enabled = True settings.globally_enabled = True
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('comment_review_workflow',)) ('comment_review_workflow',),
)
# Create page plus comment. # Create page plus comment.
self.portal.invokeFactory( self.portal.invokeFactory(
id='page', id='page',
title='Page 1', title='Page 1',
type_name='Document' type_name='Document',
) )
self.page = self.portal.page self.page = self.portal.page
self.conversation = IConversation(self.page) self.conversation = IConversation(self.page)

View File

@ -176,7 +176,7 @@ class TestModeratorNotificationUnit(unittest.TestCase):
self.portal.portal_types['Document'].allow_discussion = True self.portal.portal_types['Document'].allow_discussion = True
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('comment_review_workflow',) ('comment_review_workflow',),
) )
# Enable moderator notification setting # Enable moderator notification setting
registry = queryUtility(IRegistry) registry = queryUtility(IRegistry)
@ -219,23 +219,23 @@ class TestModeratorNotificationUnit(unittest.TestCase):
in msg) in msg)
self.assertIn( self.assertIn(
'http://nohost/plone/d=\noc1/view#{0}'.format(comment_id), 'http://nohost/plone/d=\noc1/view#{0}'.format(comment_id),
msg msg,
) )
self.assertIn( self.assertIn(
'Comment text', 'Comment text',
msg msg,
) )
text = 'Approve comment:\nhttp://nohost/plone/doc1/' \ text = 'Approve comment:\nhttp://nohost/plone/doc1/' \
'++conversation++default/{0}/@@moderat=\ne-publish-comment' '++conversation++default/{0}/@@moderat=\ne-publish-comment'
self.assertIn( self.assertIn(
text.format(comment_id), text.format(comment_id),
msg msg,
) )
text = 'Delete comment:\nhttp://nohost/plone/doc1/' \ text = 'Delete comment:\nhttp://nohost/plone/doc1/' \
'++conversation++default/{0}/@@moderat=\ne-delete-comment' '++conversation++default/{0}/@@moderat=\ne-delete-comment'
self.assertIn( self.assertIn(
text.format(comment_id), text.format(comment_id),
msg msg,
) )
def test_notify_moderator_specific_address(self): def test_notify_moderator_specific_address(self):

View File

@ -23,7 +23,7 @@ def test_suite():
suite.addTests([ suite.addTests([
layered( layered(
robottestsuite, robottestsuite,
layer=PLONE_APP_DISCUSSION_ROBOT_TESTING layer=PLONE_APP_DISCUSSION_ROBOT_TESTING,
), ),
]) ])
return suite return suite

View File

@ -47,8 +47,8 @@ class WorkflowSetupTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
('comment_one_state_workflow',), ('comment_one_state_workflow',),
self.portal.portal_workflow.getChainForPortalType( self.portal.portal_workflow.getChainForPortalType(
'Discussion Item' 'Discussion Item',
) ),
) )
def test_review_comments_permission(self): def test_review_comments_permission(self):
@ -61,9 +61,9 @@ class WorkflowSetupTest(unittest.TestCase):
self.assertFalse( self.assertFalse(
self.portal.portal_membership.checkPermission( self.portal.portal_membership.checkPermission(
'Review comments', 'Review comments',
self.folder self.folder,
), ),
self.folder self.folder,
) )
def test_reply_to_item_permission(self): def test_reply_to_item_permission(self):
@ -125,7 +125,7 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
cid = conversation.addComment(comment) cid = conversation.addComment(comment)
self.comment = self.folder.doc1.restrictedTraverse( self.comment = self.folder.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(cid) '++conversation++default/{0}'.format(cid),
) )
self.portal.acl_users._doAddUser('member', 'secret', ['Member'], []) self.portal.acl_users._doAddUser('member', 'secret', ['Member'], [])
@ -138,8 +138,10 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
def test_initial_workflow_state(self): def test_initial_workflow_state(self):
"""Make sure the initial workflow state of a comment is 'private'. """Make sure the initial workflow state of a comment is 'private'.
""" """
self.assertEqual(self.workflow.getInfoFor(self.doc, 'review_state'), self.assertEqual(
'private') self.workflow.getInfoFor(self.doc, 'review_state'),
'private',
)
def test_view_comments(self): def test_view_comments(self):
"""Make sure published comments can be viewed by everyone. """Make sure published comments can be viewed by everyone.
@ -184,7 +186,8 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
# The workflow chain is still what we want. # The workflow chain is still what we want.
self.assertEqual( self.assertEqual(
self.portal.portal_workflow.getChainFor('Discussion Item'), self.portal.portal_workflow.getChainFor('Discussion Item'),
('comment_one_state_workflow',)) ('comment_one_state_workflow',),
)
# A Manager can still see the comment. # A Manager can still see the comment.
self.assertTrue(checkPerm(View, self.comment)) self.assertTrue(checkPerm(View, self.comment))
# Anonymous cannot see the comment. # Anonymous cannot see the comment.
@ -209,7 +212,8 @@ class CommentReviewWorkflowTest(unittest.TestCase):
# Set workflow for Discussion item to review workflow # Set workflow for Discussion item to review workflow
self.portal.portal_workflow.setChainForPortalTypes( self.portal.portal_workflow.setChainForPortalTypes(
('Discussion Item',), ('Discussion Item',),
('comment_review_workflow',)) ('comment_review_workflow',),
)
# Create a conversation for this Document # Create a conversation for this Document
conversation = IConversation(self.portal.doc1) conversation = IConversation(self.portal.doc1)
@ -219,7 +223,7 @@ class CommentReviewWorkflowTest(unittest.TestCase):
comment.text = 'Comment text' comment.text = 'Comment text'
comment_id = conversation.addComment(comment) comment_id = conversation.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
'++conversation++default/{0}'.format(comment_id) '++conversation++default/{0}'.format(comment_id),
) )
self.conversation = conversation self.conversation = conversation
@ -239,9 +243,11 @@ class CommentReviewWorkflowTest(unittest.TestCase):
# Make sure that anonymous users can not delete comments # Make sure that anonymous users can not delete comments
logout() logout()
self.portal.REQUEST.form['comment_id'] = self.comment_id self.portal.REQUEST.form['comment_id'] = self.comment_id
self.assertRaises(Unauthorized, self.assertRaises(
Unauthorized,
self.comment.restrictedTraverse, self.comment.restrictedTraverse,
'@@moderate-delete-comment') '@@moderate-delete-comment',
)
self.assertTrue(self.comment_id in self.conversation.objectIds()) self.assertTrue(self.comment_id in self.conversation.objectIds())
def test_delete_as_user(self): def test_delete_as_user(self):
@ -249,9 +255,11 @@ class CommentReviewWorkflowTest(unittest.TestCase):
logout() logout()
setRoles(self.portal, TEST_USER_ID, ['Member']) setRoles(self.portal, TEST_USER_ID, ['Member'])
self.portal.REQUEST.form['comment_id'] = self.comment_id self.portal.REQUEST.form['comment_id'] = self.comment_id
self.assertRaises(Unauthorized, self.assertRaises(
Unauthorized,
self.comment.restrictedTraverse, self.comment.restrictedTraverse,
'@@moderate-delete-comment') '@@moderate-delete-comment',
)
self.assertTrue(self.comment_id in self.conversation.objectIds()) self.assertTrue(self.comment_id in self.conversation.objectIds())
def test_publish(self): def test_publish(self):
@ -261,8 +269,8 @@ class CommentReviewWorkflowTest(unittest.TestCase):
'pending', 'pending',
self.portal.portal_workflow.getInfoFor( self.portal.portal_workflow.getInfoFor(
self.comment, self.comment,
'review_state' 'review_state',
) ),
) )
view = self.comment.restrictedTraverse('@@moderate-publish-comment') view = self.comment.restrictedTraverse('@@moderate-publish-comment')
view() view()
@ -270,8 +278,8 @@ class CommentReviewWorkflowTest(unittest.TestCase):
'published', 'published',
self.portal.portal_workflow.getInfoFor( self.portal.portal_workflow.getInfoFor(
self.comment, self.comment,
'review_state' 'review_state',
) ),
) )
def test_publish_as_anonymous(self): def test_publish_as_anonymous(self):
@ -281,20 +289,20 @@ class CommentReviewWorkflowTest(unittest.TestCase):
self.assertEqual( self.assertEqual(
'pending', self.portal.portal_workflow.getInfoFor( 'pending', self.portal.portal_workflow.getInfoFor(
self.comment, self.comment,
'review_state' 'review_state',
) ),
) )
self.assertRaises( self.assertRaises(
Unauthorized, Unauthorized,
self.comment.restrictedTraverse, self.comment.restrictedTraverse,
'@@moderate-publish-comment' '@@moderate-publish-comment',
) )
self.assertEqual( self.assertEqual(
'pending', 'pending',
self.portal.portal_workflow.getInfoFor( self.portal.portal_workflow.getInfoFor(
self.comment, self.comment,
'review_state' 'review_state',
) ),
) )
def test_publish_comment_on_private_content_not_visible_to_world(self): def test_publish_comment_on_private_content_not_visible_to_world(self):

View File

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup from setuptools import setup
version = '3.0.6.dev0' version = '3.0.7.dev0'
install_requires = [ install_requires = [
'setuptools', 'setuptools',
@ -37,9 +37,12 @@ setup(name='plone.app.discussion',
'Framework :: Plone', 'Framework :: Plone',
'Framework :: Plone :: 5.0', 'Framework :: Plone :: 5.0',
'Framework :: Plone :: 5.1', 'Framework :: Plone :: 5.1',
'Framework :: Plone :: 5.2',
'License :: OSI Approved :: GNU General Public License (GPL)', 'License :: OSI Approved :: GNU General Public License (GPL)',
'Programming Language :: Python', 'Programming Language :: Python',
'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
], ],
keywords='plone discussion', keywords='plone discussion',
author='Timo Stollenwerk - Plone Foundation', author='Timo Stollenwerk - Plone Foundation',