merge master in filippo_moderation_js
This commit is contained in:
commit
3648c3345f
20
CHANGES.rst
20
CHANGES.rst
@ -1,7 +1,7 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
3.0.6 (unreleased)
|
||||
3.0.7 (unreleased)
|
||||
------------------
|
||||
|
||||
Breaking changes:
|
||||
@ -14,11 +14,27 @@ New features:
|
||||
|
||||
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.
|
||||
[jensens]
|
||||
|
||||
- More Python 2 / 3 compatibility.
|
||||
[pbauer]
|
||||
[pbauer, hvelarde]
|
||||
|
||||
|
||||
3.0.5 (2018-02-04)
|
||||
|
@ -14,6 +14,7 @@ from zope.component import getMultiAdapter
|
||||
from zope.component import getUtility
|
||||
from zope.event import notify
|
||||
from zope.lifecycleevent import ObjectModifiedEvent
|
||||
from .comments import CommentForm
|
||||
|
||||
|
||||
class View(BrowserView):
|
||||
|
@ -17,6 +17,7 @@ from plone.z3cform import z2
|
||||
from plone.z3cform.fieldsets import extensible
|
||||
from plone.z3cform.interfaces import IWrappedForm
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.utils import safe_unicode
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from six.moves.urllib.parse import quote
|
||||
@ -32,32 +33,30 @@ from zope.i18n import translate
|
||||
from zope.i18nmessageid import Message
|
||||
from zope.interface import alsoProvides
|
||||
|
||||
import six
|
||||
|
||||
|
||||
COMMENT_DESCRIPTION_PLAIN_TEXT = _(
|
||||
u'comment_description_plain_text',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting.'
|
||||
u'Plain text formatting.',
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_MARKDOWN = _(
|
||||
u'comment_description_markdown',
|
||||
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'links and images.'
|
||||
u'links and images.',
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _(
|
||||
u'comment_description_intelligent_text',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting. Web and email addresses are '
|
||||
u'transformed into clickable links.'
|
||||
u'transformed into clickable links.',
|
||||
)
|
||||
|
||||
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
|
||||
if 'author_name' in data:
|
||||
author_name = data['author_name']
|
||||
if isinstance(author_name, str):
|
||||
author_name = six.text_type(author_name, 'utf-8')
|
||||
author_name = safe_unicode(data['author_name'])
|
||||
if 'author_email' in data:
|
||||
author_email = data['author_email']
|
||||
if isinstance(author_email, str):
|
||||
author_email = six.text_type(author_email, 'utf-8')
|
||||
author_email = safe_unicode(data['author_email'])
|
||||
|
||||
# Set comment author properties for anonymous users or members
|
||||
portal_membership = getToolByName(context, 'portal_membership')
|
||||
@ -167,21 +162,18 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
'Reply to item', context):
|
||||
# Member
|
||||
member = portal_membership.getAuthenticatedMember()
|
||||
# memberdata is stored as utf-8 encoded strings
|
||||
email = member.getProperty('email')
|
||||
email = safe_unicode(member.getProperty('email'))
|
||||
fullname = member.getProperty('fullname')
|
||||
if not fullname or fullname == '':
|
||||
fullname = member.getUserName()
|
||||
elif isinstance(fullname, str):
|
||||
fullname = six.text_type(fullname, 'utf-8')
|
||||
fullname = safe_unicode(fullname)
|
||||
author_name = fullname
|
||||
if email and isinstance(email, str):
|
||||
email = six.text_type(email, 'utf-8')
|
||||
# XXX: according to IComment interface author_email must not be
|
||||
email = safe_unicode(email)
|
||||
# XXX: according to IComment interface author_email must not be # noqa T000
|
||||
# set for logged in users, cite:
|
||||
# 'for anonymous comments only, set to None for logged in comments'
|
||||
author_email = email
|
||||
# /XXX
|
||||
# /XXX # noqa T000
|
||||
|
||||
return author_name, author_email
|
||||
|
||||
@ -228,7 +220,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
raise Unauthorized(
|
||||
u'Anonymous user tries to post a comment, but anonymous '
|
||||
u'commenting is disabled. Or user does not have the '
|
||||
u"'reply to item' permission."
|
||||
u"'reply to item' permission.",
|
||||
)
|
||||
|
||||
return comment
|
||||
@ -240,10 +232,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
# Check if conversation is enabled on this content object
|
||||
if not self.__parent__.restrictedTraverse(
|
||||
'@@conversation_view'
|
||||
'@@conversation_view',
|
||||
).enabled():
|
||||
raise Unauthorized(
|
||||
'Discussion is not enabled for this content object.'
|
||||
'Discussion is not enabled for this content object.',
|
||||
)
|
||||
|
||||
# Validation form
|
||||
@ -293,7 +285,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
comment_review_state = workflowTool.getInfoFor(
|
||||
comment,
|
||||
'review_state',
|
||||
None
|
||||
None,
|
||||
)
|
||||
if comment_review_state == 'pending' and not can_review:
|
||||
# Show info message when comment moderation is enabled
|
||||
|
@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from plone.app.controlpanel.interfaces import IConfigurationChangedEvent
|
||||
from plone.app.discussion.interfaces import _
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
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 IRegistry
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces.controlpanel import IConfigurationChangedEvent # noqa: E501
|
||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
@ -34,7 +34,7 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
u'To enable the moderation workflow for comments, '
|
||||
u'go to the Types Control Panel, choose '
|
||||
u'"Comment" and set workflow to '
|
||||
u'"Comment Review Workflow".'
|
||||
u'"Comment Review Workflow".',
|
||||
)
|
||||
|
||||
def updateFields(self):
|
||||
@ -68,10 +68,10 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
self.widgets['anonymous_comments'].label = _(u'Anonymous Comments')
|
||||
self.widgets['show_commenter_image'].label = _(u'Commenter Image')
|
||||
self.widgets['moderator_notification_enabled'].label = _(
|
||||
u'Moderator Email Notification'
|
||||
u'Moderator Email Notification',
|
||||
)
|
||||
self.widgets['user_notification_enabled'].label = _(
|
||||
u'User Email Notification'
|
||||
u'User Email Notification',
|
||||
)
|
||||
|
||||
@button.buttonAndHandler(_('Save'), name=None)
|
||||
@ -92,8 +92,8 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
self.request.response.redirect(
|
||||
'{0}/{1}'.format(
|
||||
self.context.absolute_url(),
|
||||
self.control_panel_view
|
||||
)
|
||||
self.control_panel_view,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@ from Products.CMFCore.interfaces import IContentish
|
||||
from Products.CMFPlone.utils import safe_unicode
|
||||
from Products.ZCatalog.interfaces import IZCatalog
|
||||
|
||||
import six
|
||||
|
||||
MAX_DESCRIPTION = 25
|
||||
|
||||
@ -70,13 +71,20 @@ def title(object):
|
||||
|
||||
@indexer(IComment)
|
||||
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)
|
||||
def description(object):
|
||||
# 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:
|
||||
text += ' [...]'
|
||||
return text
|
||||
|
@ -118,7 +118,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
aclpath = [x for x in user.getPhysicalPath() if x]
|
||||
self._owner = (aclpath, user.getId(),)
|
||||
self.__ac_local_roles__ = {
|
||||
user.getId(): ['Owner']
|
||||
user.getId(): ['Owner'],
|
||||
}
|
||||
|
||||
@property
|
||||
@ -148,7 +148,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
text = self.text
|
||||
if text is None:
|
||||
return ''
|
||||
if isinstance(text, six.text_type):
|
||||
if six.PY2 and isinstance(text, six.text_type):
|
||||
text = text.encode('utf8')
|
||||
transform = transforms.convertTo(
|
||||
targetMimetype,
|
||||
@ -162,7 +162,11 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
msg = u'Transform "{0}" => "{1}" not available. Failed to ' \
|
||||
u'transform comment "{2}".'
|
||||
logger.error(
|
||||
msg.format(sourceMimetype, targetMimetype, self.absolute_url())
|
||||
msg.format(
|
||||
sourceMimetype,
|
||||
targetMimetype,
|
||||
self.absolute_url(),
|
||||
),
|
||||
)
|
||||
return text
|
||||
|
||||
@ -174,10 +178,12 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
|
||||
if not self.author_name:
|
||||
author_name = translate(
|
||||
Message(_(
|
||||
Message(
|
||||
_(
|
||||
u'label_anonymous',
|
||||
default=u'Anonymous'
|
||||
))
|
||||
default=u'Anonymous',
|
||||
),
|
||||
),
|
||||
)
|
||||
else:
|
||||
author_name = self.author_name
|
||||
@ -284,11 +290,11 @@ def notify_content_object_moved(obj, event):
|
||||
old_path = '/'.join(
|
||||
event.oldParent.getPhysicalPath() +
|
||||
(event.oldName,) +
|
||||
moved_path
|
||||
moved_path,
|
||||
)
|
||||
brains = catalog.searchResults(dict(
|
||||
path={'query': old_path},
|
||||
portal_type='Discussion Item'
|
||||
portal_type='Discussion Item',
|
||||
))
|
||||
for brain in brains:
|
||||
catalog.uncatalog_object(brain.getPath())
|
||||
@ -350,24 +356,28 @@ def notify_user(obj, event):
|
||||
mapping={
|
||||
'title': safe_unicode(content_object.title),
|
||||
'link': content_object.absolute_url() + '/view#' + obj.id,
|
||||
'text': obj.text
|
||||
}
|
||||
'text': obj.text,
|
||||
},
|
||||
),
|
||||
context=obj.REQUEST
|
||||
context=obj.REQUEST,
|
||||
)
|
||||
for email in emails:
|
||||
# Send email
|
||||
try:
|
||||
mail_host.send(message,
|
||||
mail_host.send(
|
||||
message,
|
||||
email,
|
||||
sender,
|
||||
subject,
|
||||
charset='utf-8')
|
||||
charset='utf-8',
|
||||
)
|
||||
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',
|
||||
sender,
|
||||
email)
|
||||
email,
|
||||
)
|
||||
|
||||
|
||||
def notify_moderator(obj, event):
|
||||
@ -420,19 +430,21 @@ def notify_moderator(obj, event):
|
||||
'text': obj.text,
|
||||
'link_approve': link_approve,
|
||||
'link_delete': link_delete,
|
||||
}
|
||||
},
|
||||
),
|
||||
context=obj.REQUEST
|
||||
context=obj.REQUEST,
|
||||
)
|
||||
|
||||
# Send email
|
||||
try:
|
||||
mail_host.send(message, mto, sender, subject, charset='utf-8')
|
||||
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 ' +
|
||||
'(from %s to %s, message: %s)',
|
||||
e,
|
||||
sender,
|
||||
mto,
|
||||
message)
|
||||
message,
|
||||
)
|
||||
|
@ -161,7 +161,7 @@ class Conversation(Traversable, Persistent, Explicit):
|
||||
|
||||
comment = aq_base(comment)
|
||||
|
||||
id = long(time.time() * 1e6)
|
||||
id = int(time.time() * 1e6)
|
||||
while id in self._comments:
|
||||
id += 1
|
||||
|
||||
@ -206,22 +206,22 @@ class Conversation(Traversable, Persistent, Explicit):
|
||||
return len(self._comments)
|
||||
|
||||
def __contains__(self, key):
|
||||
return long(key) in self._comments
|
||||
return int(key) in self._comments
|
||||
|
||||
def __getitem__(self, key):
|
||||
"""Get an item by its long key
|
||||
"""Get an item by its int key
|
||||
"""
|
||||
try:
|
||||
comment_id = long(key)
|
||||
comment_id = int(key)
|
||||
except ValueError:
|
||||
return
|
||||
return self._comments[comment_id].__of__(self)
|
||||
|
||||
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)
|
||||
commentator = comment.author_username
|
||||
@ -260,7 +260,7 @@ class Conversation(Traversable, Persistent, Explicit):
|
||||
return iter(self._comments)
|
||||
|
||||
def get(self, key, default=None):
|
||||
comment = self._comments.get(long(key), default)
|
||||
comment = self._comments.get(int(key), default)
|
||||
if comment is default:
|
||||
return default
|
||||
return comment.__of__(self)
|
||||
@ -347,20 +347,20 @@ class ConversationReplies(object):
|
||||
return len(self.children)
|
||||
|
||||
def __contains__(self, key):
|
||||
return long(key) in self.children
|
||||
return int(key) in self.children
|
||||
|
||||
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:
|
||||
raise KeyError(key)
|
||||
return self.conversation[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:
|
||||
raise KeyError(key)
|
||||
del self.conversation[key]
|
||||
@ -369,7 +369,7 @@ class ConversationReplies(object):
|
||||
return iter(self.children)
|
||||
|
||||
def get(self, key, default=None):
|
||||
key = long(key)
|
||||
key = int(key)
|
||||
if key not in self.children:
|
||||
return default
|
||||
return self.conversation.get(key)
|
||||
@ -418,7 +418,7 @@ class CommentReplies(ConversationReplies):
|
||||
self.conversation = aq_parent(self.comment)
|
||||
conversation_has_no_children = not hasattr(
|
||||
self.conversation,
|
||||
'_children'
|
||||
'_children',
|
||||
)
|
||||
if self.conversation is None or conversation_has_no_children:
|
||||
raise TypeError("This adapter doesn't know what to do with the "
|
||||
|
@ -59,7 +59,8 @@ class IConversation(IIterableMapping):
|
||||
|
||||
public_commentators = schema.Set(
|
||||
title=_(
|
||||
u'The set of unique commentators (usernames) of published_comments'
|
||||
u'The set of unique commentators (usernames) '
|
||||
u'of published_comments',
|
||||
),
|
||||
readonly=True,
|
||||
)
|
||||
@ -174,15 +175,15 @@ class IComment(Interface):
|
||||
text = schema.Text(
|
||||
title=_(
|
||||
u'label_comment',
|
||||
default=u'Comment'
|
||||
)
|
||||
default=u'Comment',
|
||||
),
|
||||
)
|
||||
|
||||
user_notification = schema.Bool(
|
||||
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'))
|
||||
@ -216,7 +217,7 @@ class IDiscussionSettings(Interface):
|
||||
default=u'If selected, users are able to post comments on the '
|
||||
u'site. However, you will still need to enable comments '
|
||||
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,
|
||||
default=False,
|
||||
@ -230,7 +231,7 @@ class IDiscussionSettings(Interface):
|
||||
default=u'If selected, anonymous users are able to post '
|
||||
u'comments without logging in. It is highly '
|
||||
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,
|
||||
default=False,
|
||||
@ -242,15 +243,16 @@ class IDiscussionSettings(Interface):
|
||||
description=_(
|
||||
u'help_anonymous_email_enabled',
|
||||
default=u'If selected, anonymous user will have to '
|
||||
u'give their email.'),
|
||||
u'give their email.',
|
||||
),
|
||||
required=False,
|
||||
default=False
|
||||
default=False,
|
||||
)
|
||||
|
||||
moderation_enabled = schema.Bool(
|
||||
title=_(
|
||||
u'label_moderation_enabled',
|
||||
default='Enable comment moderation'
|
||||
default='Enable comment moderation',
|
||||
),
|
||||
description=_(
|
||||
u'help_moderation_enabled',
|
||||
@ -260,7 +262,7 @@ class IDiscussionSettings(Interface):
|
||||
u'or "Manager") can approve comments to make them '
|
||||
u'visible to the public. If you want to enable a '
|
||||
u'custom comment workflow, you have to go to the '
|
||||
u'types control panel.'
|
||||
u'types control panel.',
|
||||
),
|
||||
required=False,
|
||||
default=False,
|
||||
@ -347,7 +349,7 @@ class IDiscussionSettings(Interface):
|
||||
moderator_email = schema.ASCIILine(
|
||||
title=_(
|
||||
u'label_moderator_email',
|
||||
default=u'Moderator Email Address'
|
||||
default=u'Moderator Email Address',
|
||||
),
|
||||
description=_(
|
||||
u'help_moderator_email',
|
||||
@ -359,14 +361,14 @@ class IDiscussionSettings(Interface):
|
||||
user_notification_enabled = schema.Bool(
|
||||
title=_(
|
||||
u'label_user_notification_enabled',
|
||||
default=u'Enable user email notification'
|
||||
default=u'Enable user email notification',
|
||||
),
|
||||
description=_(
|
||||
u'help_user_notification_enabled',
|
||||
default=u'If selected, users can choose to be notified '
|
||||
u'of new comments by email.'),
|
||||
required=False,
|
||||
default=False
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
||||
|
@ -66,7 +66,7 @@
|
||||
<!-- Control panel event subscribers -->
|
||||
|
||||
<subscriber
|
||||
for="plone.app.controlpanel.interfaces.IConfigurationChangedEvent"
|
||||
for="Products.CMFPlone.interfaces.events.IConfigurationChangedEvent"
|
||||
handler=".browser.controlpanel.notify_configuration_changed"
|
||||
/>
|
||||
|
||||
|
@ -92,7 +92,7 @@ class PloneAppDiscussion(PloneSandboxLayer):
|
||||
portal.invokeFactory(
|
||||
id='doc1',
|
||||
title='Document 1',
|
||||
type_name='Document'
|
||||
type_name='Document',
|
||||
)
|
||||
|
||||
|
||||
@ -119,5 +119,5 @@ PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING = FunctionalTesting(
|
||||
name='PloneAppDiscussion:Functional')
|
||||
PLONE_APP_DISCUSSION_ROBOT_TESTING = FunctionalTesting(
|
||||
bases=(PLONE_APP_DISCUSSION_ROBOT_FIXTURE,),
|
||||
name='PloneAppDiscussion:Robot'
|
||||
name='PloneAppDiscussion:Robot',
|
||||
)
|
||||
|
@ -470,9 +470,9 @@ Edit the content object.
|
||||
>>> from hashlib import sha1 as sha
|
||||
>>> ring = _getKeyring('foo')
|
||||
>>> 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.getControl(name='form.widgets.IRichText.text').value = "Lorem ipsum"
|
||||
>>> browser.getControl(name='form.widgets.IRichTextBehavior.text').value = "Lorem ipsum"
|
||||
>>> browser.getControl('Save').click()
|
||||
|
||||
Make sure the edit was successful.
|
||||
|
@ -26,19 +26,19 @@ class CatalogSetupTest(unittest.TestCase):
|
||||
def test_catalog_installed(self):
|
||||
self.assertTrue(
|
||||
'total_comments' in
|
||||
self.portal.portal_catalog.indexes()
|
||||
self.portal.portal_catalog.indexes(),
|
||||
)
|
||||
self.assertTrue(
|
||||
'commentators' in
|
||||
self.portal.portal_catalog.indexes()
|
||||
self.portal.portal_catalog.indexes(),
|
||||
)
|
||||
self.assertTrue(
|
||||
'total_comments' in
|
||||
self.portal.portal_catalog.schema()
|
||||
self.portal.portal_catalog.schema(),
|
||||
)
|
||||
self.assertTrue(
|
||||
'in_response_to' in
|
||||
self.portal.portal_catalog.schema()
|
||||
self.portal.portal_catalog.schema(),
|
||||
)
|
||||
|
||||
def test_collection_criteria_installed(self):
|
||||
@ -76,13 +76,14 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
new_comment1_id = conversation.addComment(comment1)
|
||||
self.comment_id = new_comment1_id
|
||||
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
self.conversation = conversation
|
||||
self.brains = brains
|
||||
self.doc1_brain = brains[0]
|
||||
@ -99,16 +100,17 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
new_comment2_id = self.conversation.addComment(comment2)
|
||||
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_comment2_id)
|
||||
'++conversation++default/{0}'.format(new_comment2_id),
|
||||
)
|
||||
comment2.reindexObject()
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
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.assertEqual(
|
||||
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.
|
||||
@ -128,47 +130,50 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
new_comment2_id = self.conversation.addComment(comment2)
|
||||
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_comment2_id)
|
||||
'++conversation++default/{0}'.format(new_comment2_id),
|
||||
)
|
||||
comment2.reindexObject()
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(
|
||||
doc1_brain.last_comment_date,
|
||||
datetime(2009, 9, 17, 14, 18, 12)
|
||||
datetime(2009, 9, 17, 14, 18, 12),
|
||||
)
|
||||
|
||||
# Remove the comment again
|
||||
del self.conversation[new_comment2_id]
|
||||
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(
|
||||
doc1_brain.last_comment_date,
|
||||
datetime(2006, 9, 17, 14, 18, 12)
|
||||
datetime(2006, 9, 17, 14, 18, 12),
|
||||
)
|
||||
|
||||
# remove all comments
|
||||
del self.conversation[self.new_comment1_id]
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.last_comment_date, None)
|
||||
|
||||
@ -185,53 +190,57 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
new_comment2_id = self.conversation.addComment(comment2)
|
||||
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_comment2_id)
|
||||
'++conversation++default/{0}'.format(new_comment2_id),
|
||||
)
|
||||
comment2.reindexObject()
|
||||
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
|
||||
self.assertEqual(doc1_brain.commentators, ('Jim', 'Emma'))
|
||||
|
||||
# remove one comments
|
||||
del self.conversation[new_comment2_id]
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.commentators, ('Jim',))
|
||||
|
||||
# remove all comments
|
||||
del self.conversation[self.new_comment1_id]
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.commentators, ())
|
||||
|
||||
def test_conversation_indexes_not_in_comments(self):
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Discussion Item'
|
||||
))
|
||||
portal_type='Discussion Item',
|
||||
),
|
||||
)
|
||||
comment1_brain = brains[0]
|
||||
self.assertEqual(comment1_brain.commentators, None)
|
||||
self.assertEqual(comment1_brain.last_comment_date, None)
|
||||
@ -240,13 +249,14 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
def test_dont_index_private_commentators(self):
|
||||
self.comment1.manage_permission('View', roles=tuple())
|
||||
self.portal.doc1.reindexObject()
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.commentators, ())
|
||||
|
||||
@ -272,14 +282,15 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
|
||||
# Comment brain
|
||||
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={
|
||||
'query':
|
||||
'/'.join(self.comment.getPhysicalPath())
|
||||
}
|
||||
))
|
||||
'query': '/'.join(self.comment.getPhysicalPath()),
|
||||
},
|
||||
),
|
||||
)
|
||||
self.comment_brain = brains[0]
|
||||
|
||||
def test_title(self):
|
||||
@ -292,14 +303,15 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
|
||||
# Comment brain
|
||||
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={
|
||||
'query':
|
||||
'/'.join(comment.getPhysicalPath())
|
||||
}
|
||||
))
|
||||
'query': '/'.join(comment.getPhysicalPath()),
|
||||
},
|
||||
),
|
||||
)
|
||||
comment_brain = brains[0]
|
||||
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
|
||||
# deleted.
|
||||
del self.conversation[self.comment_id]
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.comment.getPhysicalPath())
|
||||
}
|
||||
))
|
||||
'query': '/'.join(self.comment.getPhysicalPath()),
|
||||
},
|
||||
),
|
||||
)
|
||||
self.assertEqual(len(brains), 0)
|
||||
|
||||
def test_reindex_comment(self):
|
||||
@ -357,17 +370,17 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
self.portal.invokeFactory(
|
||||
id='folder1',
|
||||
title='Folder 1',
|
||||
type_name='Folder'
|
||||
type_name='Folder',
|
||||
)
|
||||
self.portal.invokeFactory(
|
||||
id='folder2',
|
||||
title='Folder 2',
|
||||
type_name='Folder'
|
||||
type_name='Folder',
|
||||
)
|
||||
self.portal.folder1.invokeFactory(
|
||||
id='moveme',
|
||||
title='Move Me',
|
||||
type_name='Document'
|
||||
type_name='Document',
|
||||
)
|
||||
conversation = IConversation(self.portal.folder1.moveme)
|
||||
comment = createObject('plone.Comment')
|
||||
@ -380,43 +393,57 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
self.portal.folder2.manage_pasteObjects(cp)
|
||||
|
||||
# Make sure no old comment brains are
|
||||
brains = self.catalog.searchResults(dict(
|
||||
portal_type='Discussion Item',
|
||||
path={'query': '/'.join(self.portal.folder1.getPhysicalPath())}
|
||||
))
|
||||
self.assertEqual(len(brains), 0)
|
||||
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
portal_type='Discussion Item',
|
||||
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(
|
||||
brains[0].getPath(),
|
||||
'/plone/folder2/moveme/++conversation++default/' +
|
||||
str(comment_id)
|
||||
str(comment_id),
|
||||
)
|
||||
|
||||
def test_move_upper_level_folder(self):
|
||||
# create a folder with a nested structure
|
||||
self.portal.invokeFactory(id='sourcefolder',
|
||||
self.portal.invokeFactory(
|
||||
id='sourcefolder',
|
||||
title='Source Folder',
|
||||
type_name='Folder')
|
||||
self.portal.sourcefolder.invokeFactory(id='moveme',
|
||||
type_name='Folder',
|
||||
)
|
||||
self.portal.sourcefolder.invokeFactory(
|
||||
id='moveme',
|
||||
title='Move Me',
|
||||
type_name='Folder')
|
||||
self.portal.sourcefolder.moveme.invokeFactory(id='mydocument',
|
||||
type_name='Folder',
|
||||
)
|
||||
self.portal.sourcefolder.moveme.invokeFactory(
|
||||
id='mydocument',
|
||||
title='My Document',
|
||||
type_name='Folder')
|
||||
self.portal.invokeFactory(id='targetfolder',
|
||||
type_name='Folder',
|
||||
)
|
||||
self.portal.invokeFactory(
|
||||
id='targetfolder',
|
||||
title='Target Folder',
|
||||
type_name='Folder')
|
||||
type_name='Folder',
|
||||
)
|
||||
|
||||
# create comment on my-document
|
||||
conversation = IConversation(
|
||||
self.portal.sourcefolder.moveme.mydocument
|
||||
self.portal.sourcefolder.moveme.mydocument,
|
||||
)
|
||||
comment = createObject('plone.Comment')
|
||||
comment_id = conversation.addComment(comment)
|
||||
@ -429,22 +456,26 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
self.portal.targetfolder.manage_pasteObjects(cp)
|
||||
|
||||
# Make sure no old comment brains are left
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
portal_type='Discussion Item',
|
||||
path={'query': '/plone/sourcefolder/moveme'}
|
||||
))
|
||||
path={'query': '/plone/sourcefolder/moveme'},
|
||||
),
|
||||
)
|
||||
self.assertEqual(len(brains), 0)
|
||||
|
||||
# make sure comments are correctly index on the target
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
portal_type='Discussion Item',
|
||||
path={'query': '/plone/targetfolder/moveme'}
|
||||
))
|
||||
path={'query': '/plone/targetfolder/moveme'},
|
||||
),
|
||||
)
|
||||
self.assertEqual(len(brains), 1)
|
||||
self.assertEqual(
|
||||
brains[0].getPath(),
|
||||
'/plone/targetfolder/moveme/mydocument/++conversation++default/' +
|
||||
str(comment_id)
|
||||
str(comment_id),
|
||||
)
|
||||
|
||||
def test_update_comments_when_content_object_is_renamed(self):
|
||||
@ -454,12 +485,13 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
self.portal.manage_renameObject('doc1', 'doc2')
|
||||
|
||||
brains = self.catalog.searchResults(
|
||||
portal_type='Discussion Item')
|
||||
portal_type='Discussion Item',
|
||||
)
|
||||
self.assertEqual(len(brains), 1)
|
||||
self.assertEqual(
|
||||
brains[0].getPath(),
|
||||
'/plone/doc2/++conversation++default/' +
|
||||
str(self.comment_id)
|
||||
str(self.comment_id),
|
||||
)
|
||||
|
||||
def test_clear_and_rebuild_catalog(self):
|
||||
@ -477,7 +509,7 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
comment_brain.getPath(),
|
||||
'/plone/doc1/++conversation++default/' +
|
||||
str(self.comment_id)
|
||||
str(self.comment_id),
|
||||
)
|
||||
|
||||
def test_clear_and_rebuild_catalog_for_nested_comments(self):
|
||||
@ -549,13 +581,14 @@ class NoConversationCatalogTest(unittest.TestCase):
|
||||
|
||||
conversation = IConversation(self.portal.doc1)
|
||||
|
||||
brains = self.catalog.searchResults(dict(
|
||||
brains = self.catalog.searchResults(
|
||||
dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
'query': '/'.join(self.portal.doc1.getPhysicalPath()),
|
||||
},
|
||||
portal_type='Document'
|
||||
))
|
||||
portal_type='Document',
|
||||
),
|
||||
)
|
||||
self.conversation = conversation
|
||||
self.brains = brains
|
||||
self.doc1_brain = brains[0]
|
||||
@ -567,5 +600,5 @@ class NoConversationCatalogTest(unittest.TestCase):
|
||||
# Make sure no conversation has been created
|
||||
self.assertTrue(
|
||||
'plone.app.discussion:conversation' not in
|
||||
IAnnotations(self.portal.doc1)
|
||||
IAnnotations(self.portal.doc1),
|
||||
)
|
||||
|
@ -12,6 +12,7 @@ from zope.component import getMultiAdapter
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import six
|
||||
import unittest
|
||||
|
||||
|
||||
@ -54,7 +55,7 @@ class CommentTest(unittest.TestCase):
|
||||
difference = difference.seconds
|
||||
# We hope that between comment1 and local_utc happen less than
|
||||
# 10 seconds
|
||||
self.assertFalse(difference / 10)
|
||||
self.assertFalse(difference // 10)
|
||||
|
||||
def test_id(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
@ -68,7 +69,7 @@ class CommentTest(unittest.TestCase):
|
||||
comment1 = createObject('plone.Comment')
|
||||
conversation.addComment(comment1)
|
||||
comment_brain = self.catalog.searchResults(
|
||||
portal_type='Discussion Item'
|
||||
portal_type='Discussion Item',
|
||||
)[0]
|
||||
self.assertTrue(comment_brain.UID)
|
||||
|
||||
@ -79,7 +80,7 @@ class CommentTest(unittest.TestCase):
|
||||
comment2 = createObject('plone.Comment')
|
||||
conversation.addComment(comment2)
|
||||
brains = self.catalog.searchResults(
|
||||
portal_type='Discussion Item'
|
||||
portal_type='Discussion Item',
|
||||
)
|
||||
self.assertNotEqual(brains[0].UID, brains[1].UID)
|
||||
|
||||
@ -88,7 +89,7 @@ class CommentTest(unittest.TestCase):
|
||||
comment1 = createObject('plone.Comment')
|
||||
conversation.addComment(comment1)
|
||||
comment_brain = self.catalog.searchResults(
|
||||
portal_type='Discussion Item'
|
||||
portal_type='Discussion Item',
|
||||
)[0]
|
||||
self.assertNotEqual(self.document_brain.UID, comment_brain.UID)
|
||||
|
||||
@ -109,7 +110,7 @@ class CommentTest(unittest.TestCase):
|
||||
self.portal.invokeFactory(
|
||||
id='doc_sp_chars',
|
||||
title=u'Document äüö',
|
||||
type_name='Document'
|
||||
type_name='Document',
|
||||
)
|
||||
conversation = IConversation(self.portal.doc_sp_chars)
|
||||
comment1 = createObject('plone.Comment')
|
||||
@ -121,7 +122,7 @@ class CommentTest(unittest.TestCase):
|
||||
self.portal.invokeFactory(
|
||||
id='doc_sp_chars_utf8',
|
||||
title='Document ëïû',
|
||||
type_name='Document'
|
||||
type_name='Document',
|
||||
)
|
||||
conversation = IConversation(self.portal.doc_sp_chars_utf8)
|
||||
comment1 = createObject('plone.Comment')
|
||||
@ -157,7 +158,7 @@ class CommentTest(unittest.TestCase):
|
||||
comment1.text = 'First paragraph\n\nSecond_paragraph'
|
||||
self.assertEqual(
|
||||
''.join(comment1.getText().split()),
|
||||
'<p>Firstparagraph<br/><br/>Second_paragraph</p>'
|
||||
'<p>Firstparagraph<br/><br/>Second_paragraph</p>',
|
||||
)
|
||||
|
||||
def test_getText_escapes_HTML(self):
|
||||
@ -165,23 +166,28 @@ class CommentTest(unittest.TestCase):
|
||||
comment1.text = '<b>Got HTML?</b>'
|
||||
self.assertEqual(
|
||||
comment1.getText(),
|
||||
'<p><b>Got HTML?</b></p>'
|
||||
'<p><b>Got HTML?</b></p>',
|
||||
)
|
||||
|
||||
def test_getText_with_non_ascii_characters(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = u'Umlaute sind ä, ö und ü.'
|
||||
out = b'<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>'
|
||||
if six.PY2:
|
||||
self.assertEqual(
|
||||
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):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = 'Go to http://www.plone.org'
|
||||
self.assertEqual(
|
||||
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):
|
||||
@ -191,7 +197,7 @@ class CommentTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
comment1.getText(),
|
||||
'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):
|
||||
@ -200,7 +206,7 @@ class CommentTest(unittest.TestCase):
|
||||
comment1.mime_type = 'text/html'
|
||||
self.assertEqual(
|
||||
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):
|
||||
@ -230,20 +236,20 @@ class CommentTest(unittest.TestCase):
|
||||
new_comment1_id = conversation.addComment(comment1)
|
||||
|
||||
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.assertEqual(
|
||||
(
|
||||
'', 'plone', 'doc1', '++conversation++default',
|
||||
str(new_comment1_id)
|
||||
str(new_comment1_id),
|
||||
),
|
||||
comment.getPhysicalPath()
|
||||
comment.getPhysicalPath(),
|
||||
)
|
||||
self.assertEqual(
|
||||
'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):
|
||||
@ -254,7 +260,7 @@ class CommentTest(unittest.TestCase):
|
||||
self.portal.invokeFactory(
|
||||
id='image1',
|
||||
title='Image',
|
||||
type_name='Image'
|
||||
type_name='Image',
|
||||
)
|
||||
conversation = IConversation(self.portal.image1)
|
||||
|
||||
@ -262,7 +268,7 @@ class CommentTest(unittest.TestCase):
|
||||
comment1.text = 'Comment text'
|
||||
new_comment1_id = conversation.addComment(comment1)
|
||||
comment = self.portal.image1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_comment1_id)
|
||||
'++conversation++default/{0}'.format(new_comment1_id),
|
||||
)
|
||||
|
||||
view = View(comment, self.request)
|
||||
@ -275,7 +281,8 @@ class CommentTest(unittest.TestCase):
|
||||
"""
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('comment_review_workflow,'))
|
||||
('comment_review_workflow,'),
|
||||
)
|
||||
|
||||
conversation = IConversation(self.portal.doc1)
|
||||
comment1 = createObject('plone.Comment')
|
||||
@ -290,15 +297,15 @@ class CommentTest(unittest.TestCase):
|
||||
# Ensure the initial state was entered and recorded
|
||||
self.assertEqual(
|
||||
1,
|
||||
len(comment.workflow_history['comment_review_workflow'])
|
||||
len(comment.workflow_history['comment_review_workflow']),
|
||||
)
|
||||
self.assertEqual(
|
||||
None,
|
||||
comment.workflow_history['comment_review_workflow'][0]['action']
|
||||
comment.workflow_history['comment_review_workflow'][0]['action'],
|
||||
)
|
||||
self.assertEqual(
|
||||
'pending',
|
||||
self.portal.portal_workflow.getInfoFor(comment, 'review_state')
|
||||
self.portal.portal_workflow.getInfoFor(comment, 'review_state'),
|
||||
)
|
||||
|
||||
def test_fti(self):
|
||||
@ -306,7 +313,7 @@ class CommentTest(unittest.TestCase):
|
||||
|
||||
self.assertIn(
|
||||
'Discussion Item',
|
||||
self.portal.portal_types.objectIds()
|
||||
self.portal.portal_types.objectIds(),
|
||||
)
|
||||
|
||||
comment1 = createObject('plone.Comment')
|
||||
@ -330,12 +337,16 @@ class CommentTest(unittest.TestCase):
|
||||
new_comment1_id = conversation.addComment(comment1)
|
||||
|
||||
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
|
||||
self.assertTrue(getMultiAdapter((comment, self.request),
|
||||
name='view'))
|
||||
self.assertTrue(
|
||||
getMultiAdapter(
|
||||
(comment, self.request),
|
||||
name='view',
|
||||
),
|
||||
)
|
||||
|
||||
# make sure the HTTP redirect (status code 302) works when a comment
|
||||
# is called directly
|
||||
@ -371,7 +382,7 @@ class RepliesTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
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
|
||||
@ -408,7 +419,7 @@ class RepliesTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
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
|
||||
@ -444,7 +455,7 @@ class RepliesTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = conversation.addComment(comment)
|
||||
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
|
||||
@ -453,7 +464,7 @@ class RepliesTest(unittest.TestCase):
|
||||
replies = IReplies(comment)
|
||||
new_re_id = replies.addComment(re_comment)
|
||||
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
|
||||
@ -462,7 +473,7 @@ class RepliesTest(unittest.TestCase):
|
||||
replies = IReplies(re_comment)
|
||||
new_re_re_id = replies.addComment(re_re_comment)
|
||||
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
|
||||
@ -471,47 +482,47 @@ class RepliesTest(unittest.TestCase):
|
||||
replies = IReplies(re_re_comment)
|
||||
new_re_re_re_id = replies.addComment(re_re_re_comment)
|
||||
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(
|
||||
('', 'plone', 'doc1', '++conversation++default', str(new_id)),
|
||||
comment.getPhysicalPath()
|
||||
comment.getPhysicalPath(),
|
||||
)
|
||||
self.assertEqual(
|
||||
'http://nohost/plone/doc1/++conversation++default/' +
|
||||
str(new_id), comment.absolute_url()
|
||||
str(new_id), comment.absolute_url(),
|
||||
)
|
||||
self.assertEqual(
|
||||
('', 'plone', 'doc1', '++conversation++default', str(new_re_id)),
|
||||
re_comment.getPhysicalPath()
|
||||
re_comment.getPhysicalPath(),
|
||||
)
|
||||
self.assertEqual(
|
||||
'http://nohost/plone/doc1/++conversation++default/' +
|
||||
str(new_re_id),
|
||||
re_comment.absolute_url()
|
||||
re_comment.absolute_url(),
|
||||
)
|
||||
self.assertEqual(
|
||||
(
|
||||
'', 'plone', 'doc1', '++conversation++default',
|
||||
str(new_re_re_id)
|
||||
str(new_re_re_id),
|
||||
),
|
||||
re_re_comment.getPhysicalPath()
|
||||
re_re_comment.getPhysicalPath(),
|
||||
)
|
||||
self.assertEqual(
|
||||
'http://nohost/plone/doc1/++conversation++default/' +
|
||||
str(new_re_re_id),
|
||||
re_re_comment.absolute_url()
|
||||
re_re_comment.absolute_url(),
|
||||
)
|
||||
self.assertEqual(
|
||||
(
|
||||
'', '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(
|
||||
'http://nohost/plone/doc1/++conversation++default/' +
|
||||
str(new_re_re_re_id),
|
||||
re_re_re_comment.absolute_url()
|
||||
re_re_re_comment.absolute_url(),
|
||||
)
|
||||
|
@ -80,7 +80,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
|
||||
# The form should return an error if the comment text field is empty
|
||||
@ -88,7 +88,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
@ -102,7 +102,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
@ -144,14 +144,14 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
|
||||
provideAdapter(
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=EditCommentForm,
|
||||
name=u'edit-comment-form'
|
||||
name=u'edit-comment-form',
|
||||
)
|
||||
|
||||
# The form is submitted successfully, if the required text field is
|
||||
@ -160,7 +160,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
commentForm.update()
|
||||
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'})
|
||||
editForm = getMultiAdapter(
|
||||
(comment, request),
|
||||
name=u'edit-comment-form'
|
||||
name=u'edit-comment-form',
|
||||
)
|
||||
editForm.update()
|
||||
data, errors = editForm.extractData() # pylint: disable-msg=W0612
|
||||
@ -219,7 +219,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
|
||||
# The form is submitted successfully, if the required text field is
|
||||
@ -228,7 +228,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, form_request),
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
|
||||
commentForm.update()
|
||||
@ -241,14 +241,14 @@ class TestCommentForm(unittest.TestCase):
|
||||
comment = [x for x in conversation.getComments()][-1]
|
||||
deleteView = getMultiAdapter(
|
||||
(comment, self.request),
|
||||
name=u'moderate-delete-comment'
|
||||
name=u'moderate-delete-comment',
|
||||
)
|
||||
# try to delete last comment without 'Delete comments' permission
|
||||
setRoles(self.portal, TEST_USER_ID, ['Member'])
|
||||
self.assertRaises(
|
||||
Unauthorized,
|
||||
comment.restrictedTraverse,
|
||||
'@@moderate-delete-comment'
|
||||
'@@moderate-delete-comment',
|
||||
)
|
||||
deleteView()
|
||||
self.assertEqual(1, len([x for x in conversation.getComments()]))
|
||||
@ -277,7 +277,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
|
||||
# The form is submitted successfully, if the required text field is
|
||||
@ -286,7 +286,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, form_request),
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
|
||||
commentForm.update()
|
||||
@ -299,7 +299,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
comment = [x for x in conversation.getComments()][-1]
|
||||
deleteView = getMultiAdapter(
|
||||
(comment, self.request),
|
||||
name=u'delete-own-comment'
|
||||
name=u'delete-own-comment',
|
||||
)
|
||||
# try to delete last comment with johndoe
|
||||
setRoles(self.portal, 'johndoe', ['Member'])
|
||||
@ -307,7 +307,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
self.assertRaises(
|
||||
Unauthorized,
|
||||
comment.restrictedTraverse,
|
||||
'@@delete-own-comment'
|
||||
'@@delete-own-comment',
|
||||
)
|
||||
self.assertEqual(1, len([x for x in conversation.getComments()]))
|
||||
# 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
|
||||
request = make_request(form={
|
||||
'form.widgets.name': u'john doe',
|
||||
'form.widgets.text': u'bar'
|
||||
'form.widgets.text': u'bar',
|
||||
})
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
@ -391,7 +391,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u'comment-form'
|
||||
name=u'comment-form',
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
@ -438,7 +438,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
Unauthorized,
|
||||
commentForm.handleComment,
|
||||
commentForm,
|
||||
'foo'
|
||||
'foo',
|
||||
)
|
||||
|
||||
|
||||
@ -454,7 +454,7 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
self.folder = self.portal['test-folder']
|
||||
interface.alsoProvides(
|
||||
self.request,
|
||||
interfaces.IDiscussionLayer
|
||||
interfaces.IDiscussionLayer,
|
||||
)
|
||||
|
||||
self.workflowTool = getToolByName(self.portal, 'portal_workflow')
|
||||
@ -532,7 +532,7 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
self.viewlet.comment_transform_message(),
|
||||
'You can add a comment by filling out the form below. ' +
|
||||
'Plain text formatting. Web and email addresses are transformed ' +
|
||||
'into clickable links.'
|
||||
'into clickable links.',
|
||||
)
|
||||
|
||||
# Enable moderation workflow
|
||||
@ -567,7 +567,8 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
replies = self.viewlet.get_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):
|
||||
context = self.portal.MailHost # the mail host is not annotatable
|
||||
@ -575,7 +576,8 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
replies = viewlet.get_replies()
|
||||
self.assertEqual(len(tuple(replies)), 0)
|
||||
replies = viewlet.get_replies()
|
||||
self.assertRaises(StopIteration, replies.next)
|
||||
with self.assertRaises(StopIteration):
|
||||
next(replies)
|
||||
|
||||
def test_get_replies_with_workflow_actions(self):
|
||||
self.assertFalse(self.viewlet.get_replies(workflow_actions=True))
|
||||
@ -585,25 +587,25 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
c1 = conversation.addComment(comment)
|
||||
self.assertEqual(
|
||||
len(tuple(self.viewlet.get_replies(workflow_actions=True))),
|
||||
1
|
||||
1,
|
||||
)
|
||||
# Enable moderation workflow
|
||||
self.workflowTool.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('comment_review_workflow,')
|
||||
('comment_review_workflow,'),
|
||||
)
|
||||
# Check if workflow actions are available
|
||||
reply = next(self.viewlet.get_replies(workflow_actions=True))
|
||||
self.assertTrue('actions' in reply)
|
||||
self.assertEqual(
|
||||
reply['actions'][0]['id'],
|
||||
'publish'
|
||||
'publish',
|
||||
)
|
||||
expected_url = 'http://nohost/plone/doc1/++conversation++default/{0}' \
|
||||
'/content_status_modify?workflow_action=publish'
|
||||
self.assertEqual(
|
||||
reply['actions'][0]['url'],
|
||||
expected_url.format(int(c1))
|
||||
expected_url.format(int(c1)),
|
||||
)
|
||||
|
||||
def test_get_commenter_home_url(self):
|
||||
@ -614,7 +616,7 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
m = portal_membership.getAuthenticatedMember()
|
||||
self.assertEqual(
|
||||
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):
|
||||
@ -627,15 +629,15 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
self.memberdata._setPortrait(Image(
|
||||
id='jim',
|
||||
file=dummy.File(),
|
||||
title=''
|
||||
title='',
|
||||
), 'jim')
|
||||
self.assertEqual(
|
||||
self.memberdata._getPortrait('jim').getId(),
|
||||
'jim'
|
||||
'jim',
|
||||
)
|
||||
self.assertEqual(
|
||||
self.memberdata._getPortrait('jim').meta_type,
|
||||
'Image'
|
||||
'Image',
|
||||
)
|
||||
|
||||
# Add a conversation with a comment
|
||||
@ -653,7 +655,7 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
# Check if the correct member image URL is returned
|
||||
self.assertEqual(
|
||||
portrait_url,
|
||||
'http://nohost/plone/portal_memberdata/portraits/jim'
|
||||
'http://nohost/plone/portal_memberdata/portraits/jim',
|
||||
)
|
||||
|
||||
def test_get_commenter_portrait_is_none(self):
|
||||
@ -662,8 +664,7 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
self.viewlet.get_commenter_portrait() in (
|
||||
'defaultUser.png',
|
||||
'defaultUser.gif',
|
||||
)
|
||||
|
||||
),
|
||||
)
|
||||
|
||||
def test_get_commenter_portrait_without_userimage(self):
|
||||
@ -689,8 +690,8 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
self.assertTrue(
|
||||
portrait_url in (
|
||||
'http://nohost/plone/defaultUser.png',
|
||||
'http://nohost/plone/defaultUser.gif'
|
||||
)
|
||||
'http://nohost/plone/defaultUser.gif',
|
||||
),
|
||||
)
|
||||
|
||||
def test_anonymous_discussion_allowed(self):
|
||||
@ -723,7 +724,7 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
self.viewlet.update()
|
||||
self.assertEqual(
|
||||
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):
|
||||
@ -737,8 +738,8 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
# time of the local time given above. That way, the time for the
|
||||
# example below is correct within each time zone, independent of DST
|
||||
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)
|
||||
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'],
|
||||
)
|
||||
|
@ -30,7 +30,7 @@ class CommentContentRulesTest(unittest.TestCase):
|
||||
member = self.portal.portal_membership.getMemberById(TEST_USER_ID)
|
||||
member.setMemberProperties({
|
||||
'fullname': 'X Manager',
|
||||
'email': 'xmanager@example.com'
|
||||
'email': 'xmanager@example.com',
|
||||
})
|
||||
|
||||
setRoles(self.portal, TEST_USER_ID, ['Manager'])
|
||||
@ -54,7 +54,7 @@ class CommentContentRulesTest(unittest.TestCase):
|
||||
def testCommentIdStringSubstitution(self):
|
||||
comment_id = getAdapter(self.document, IStringSubstitution,
|
||||
name=u'comment_id')
|
||||
self.assertIsInstance(comment_id(), long)
|
||||
self.assertIsInstance(comment_id(), int)
|
||||
|
||||
def testCommentTextStringSubstitution(self):
|
||||
comment_text = getAdapter(self.document, IStringSubstitution,
|
||||
@ -96,7 +96,7 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
comment.text = 'This is a comment'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.document.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
'++conversation++default/{0}'.format(new_id),
|
||||
)
|
||||
|
||||
re_comment = createObject('plone.Comment')
|
||||
@ -112,15 +112,15 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
reply_id = getAdapter(
|
||||
self.document,
|
||||
IStringSubstitution,
|
||||
name=u'comment_id'
|
||||
name=u'comment_id',
|
||||
)
|
||||
self.assertIsInstance(reply_id(), long)
|
||||
self.assertIsInstance(reply_id(), int)
|
||||
|
||||
def testReplyTextStringSubstitution(self):
|
||||
reply_text = getAdapter(
|
||||
self.document,
|
||||
IStringSubstitution,
|
||||
name=u'comment_text'
|
||||
name=u'comment_text',
|
||||
)
|
||||
self.assertEqual(reply_text(), u'This is a reply')
|
||||
|
||||
@ -128,7 +128,7 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
reply_user_id = getAdapter(
|
||||
self.document,
|
||||
IStringSubstitution,
|
||||
name=u'comment_user_id'
|
||||
name=u'comment_user_id',
|
||||
)
|
||||
self.assertEqual(reply_user_id(), u'julia')
|
||||
|
||||
@ -136,7 +136,7 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
reply_user_fullname = getAdapter(
|
||||
self.document,
|
||||
IStringSubstitution,
|
||||
name=u'comment_user_fullname'
|
||||
name=u'comment_user_fullname',
|
||||
)
|
||||
self.assertEqual(reply_user_fullname(), u'Juliana')
|
||||
|
||||
@ -144,6 +144,6 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
reply_user_email = getAdapter(
|
||||
self.document,
|
||||
IStringSubstitution,
|
||||
name=u'comment_user_email'
|
||||
name=u'comment_user_email',
|
||||
)
|
||||
self.assertEqual(reply_user_email(), u'julia@example.com')
|
||||
|
@ -29,7 +29,7 @@ class RegistryTest(unittest.TestCase):
|
||||
def test_discussion_controlpanel_view(self):
|
||||
view = getMultiAdapter(
|
||||
(self.portal, self.portal.REQUEST),
|
||||
name='discussion-controlpanel'
|
||||
name='discussion-controlpanel',
|
||||
)
|
||||
self.assertTrue(view())
|
||||
|
||||
@ -40,7 +40,7 @@ class RegistryTest(unittest.TestCase):
|
||||
'discussion' in [
|
||||
a.getAction(self)['id']
|
||||
for a in self.controlpanel.listActions()
|
||||
]
|
||||
],
|
||||
)
|
||||
|
||||
def test_globally_enabled(self):
|
||||
@ -51,7 +51,7 @@ class RegistryTest(unittest.TestCase):
|
||||
'plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.globally_enabled'
|
||||
],
|
||||
False
|
||||
False,
|
||||
)
|
||||
|
||||
def test_anonymous_comments(self):
|
||||
@ -62,7 +62,7 @@ class RegistryTest(unittest.TestCase):
|
||||
'plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.anonymous_comments'
|
||||
],
|
||||
False
|
||||
False,
|
||||
)
|
||||
|
||||
def test_moderation_enabled(self):
|
||||
@ -73,7 +73,7 @@ class RegistryTest(unittest.TestCase):
|
||||
'plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.moderation_enabled'
|
||||
],
|
||||
False
|
||||
False,
|
||||
)
|
||||
|
||||
def test_edit_comment_enabled(self):
|
||||
@ -82,7 +82,8 @@ class RegistryTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
self.registry['plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.edit_comment_enabled'],
|
||||
False)
|
||||
False,
|
||||
)
|
||||
|
||||
def test_delete_own_comment_enabled(self):
|
||||
# Check delete_own_comment_enabled record
|
||||
@ -90,7 +91,8 @@ class RegistryTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
self.registry['plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.delete_own_comment_enabled'],
|
||||
False)
|
||||
False,
|
||||
)
|
||||
|
||||
def test_text_transform(self):
|
||||
self.assertTrue('text_transform' in IDiscussionSettings)
|
||||
@ -99,7 +101,7 @@ class RegistryTest(unittest.TestCase):
|
||||
'plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.text_transform'
|
||||
],
|
||||
'text/plain'
|
||||
'text/plain',
|
||||
)
|
||||
|
||||
def test_captcha(self):
|
||||
@ -110,7 +112,7 @@ class RegistryTest(unittest.TestCase):
|
||||
'plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.captcha'
|
||||
],
|
||||
'disabled'
|
||||
'disabled',
|
||||
)
|
||||
|
||||
def test_show_commenter_image(self):
|
||||
@ -121,20 +123,20 @@ class RegistryTest(unittest.TestCase):
|
||||
'plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.show_commenter_image'
|
||||
],
|
||||
True
|
||||
True,
|
||||
)
|
||||
|
||||
def test_moderator_notification_enabled(self):
|
||||
# Check show_commenter_image record
|
||||
self.assertTrue(
|
||||
'moderator_notification_enabled' in IDiscussionSettings
|
||||
'moderator_notification_enabled' in IDiscussionSettings,
|
||||
)
|
||||
self.assertEqual(
|
||||
self.registry[
|
||||
'plone.app.discussion.interfaces.' +
|
||||
'IDiscussionSettings.moderator_notification_enabled'
|
||||
],
|
||||
False
|
||||
False,
|
||||
)
|
||||
|
||||
# def test_user_notification_enabled(self):
|
||||
@ -167,8 +169,8 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
('comment_one_state_workflow',),
|
||||
self.portal.portal_workflow.getChainForPortalType(
|
||||
'Discussion Item'
|
||||
)
|
||||
'Discussion Item',
|
||||
),
|
||||
)
|
||||
|
||||
# Enable moderation in the discussion control panel
|
||||
@ -179,16 +181,16 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
('comment_review_workflow',),
|
||||
self.portal.portal_workflow.getChainForPortalType(
|
||||
'Discussion Item'
|
||||
)
|
||||
'Discussion Item',
|
||||
),
|
||||
)
|
||||
# And back
|
||||
self.settings.moderation_enabled = False
|
||||
self.assertEqual(
|
||||
('comment_one_state_workflow',),
|
||||
self.portal.portal_workflow.getChainForPortalType(
|
||||
'Discussion Item'
|
||||
)
|
||||
'Discussion Item',
|
||||
),
|
||||
)
|
||||
|
||||
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
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('comment_review_workflow',)
|
||||
('comment_review_workflow',),
|
||||
)
|
||||
|
||||
# Make sure the moderation_enabled settings has changed
|
||||
@ -211,14 +213,14 @@ class ConfigurationChangedSubscriberTest(unittest.TestCase):
|
||||
# Enable the 'comment_review_workflow' with moderation enabled
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('comment_one_state_workflow',)
|
||||
('comment_one_state_workflow',),
|
||||
)
|
||||
self.settings.moderation_enabled = True
|
||||
|
||||
# Enable a 'custom' discussion workflow
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('intranet_workflow',)
|
||||
('intranet_workflow',),
|
||||
)
|
||||
|
||||
# Setting has not changed. A Custom workflow disables the
|
||||
|
@ -68,11 +68,11 @@ class ConversationTest(unittest.TestCase):
|
||||
new_id = conversation.addComment(comment)
|
||||
|
||||
# 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.assertEqual(
|
||||
aq_base(conversation[new_id].__parent__),
|
||||
aq_base(conversation)
|
||||
aq_base(conversation),
|
||||
)
|
||||
self.assertEqual(new_id, comment.comment_id)
|
||||
self.assertEqual(len(list(conversation.getComments())), 1)
|
||||
@ -80,7 +80,7 @@ class ConversationTest(unittest.TestCase):
|
||||
self.assertEqual(conversation.total_comments(), 1)
|
||||
self.assertTrue(
|
||||
conversation.last_comment_date - datetime.utcnow() <
|
||||
timedelta(seconds=1)
|
||||
timedelta(seconds=1),
|
||||
)
|
||||
|
||||
def test_private_comment(self):
|
||||
@ -278,7 +278,7 @@ class ConversationTest(unittest.TestCase):
|
||||
|
||||
# Create a conversation.
|
||||
conversation = self.portal.doc1.restrictedTraverse(
|
||||
'@@conversation_view'
|
||||
'@@conversation_view',
|
||||
)
|
||||
|
||||
# The Document content type is disabled by default
|
||||
@ -326,7 +326,7 @@ class ConversationTest(unittest.TestCase):
|
||||
|
||||
# Create a conversation.
|
||||
conversation = self.portal.doc1.restrictedTraverse(
|
||||
'@@conversation_view'
|
||||
'@@conversation_view',
|
||||
)
|
||||
|
||||
# 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_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)
|
||||
|
||||
def test_total_comments(self):
|
||||
@ -512,11 +512,11 @@ class ConversationTest(unittest.TestCase):
|
||||
# check if the latest comment is exactly one day old
|
||||
self.assertTrue(
|
||||
conversation.last_comment_date < datetime.utcnow() -
|
||||
timedelta(hours=23, minutes=59, seconds=59)
|
||||
timedelta(hours=23, minutes=59, seconds=59),
|
||||
)
|
||||
self.assertTrue(
|
||||
conversation.last_comment_date >
|
||||
datetime.utcnow() - timedelta(days=1, seconds=1)
|
||||
datetime.utcnow() - timedelta(days=1, seconds=1),
|
||||
)
|
||||
|
||||
# remove the latest comment
|
||||
@ -526,11 +526,11 @@ class ConversationTest(unittest.TestCase):
|
||||
# the latest comment should be exactly two days old
|
||||
self.assertTrue(
|
||||
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(
|
||||
conversation.last_comment_date > datetime.utcnow() -
|
||||
timedelta(days=2, seconds=1)
|
||||
timedelta(days=2, seconds=1),
|
||||
)
|
||||
|
||||
# remove the latest comment again
|
||||
@ -540,11 +540,11 @@ class ConversationTest(unittest.TestCase):
|
||||
# the latest comment should be exactly four days old
|
||||
self.assertTrue(
|
||||
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(
|
||||
conversation.last_comment_date > datetime.utcnow() -
|
||||
timedelta(days=4, seconds=2)
|
||||
timedelta(days=4, seconds=2),
|
||||
)
|
||||
|
||||
def test_get_comments_full(self):
|
||||
@ -618,7 +618,7 @@ class ConversationTest(unittest.TestCase):
|
||||
], list(conversation.getThreads()))
|
||||
|
||||
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
|
||||
pass
|
||||
|
||||
@ -626,25 +626,25 @@ class ConversationTest(unittest.TestCase):
|
||||
# make sure we can traverse to conversations and get a URL and path
|
||||
|
||||
conversation = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default'
|
||||
'++conversation++default',
|
||||
)
|
||||
self.assertTrue(IConversation.providedBy(conversation))
|
||||
|
||||
self.assertEqual(
|
||||
('', 'plone', 'doc1', '++conversation++default'),
|
||||
conversation.getPhysicalPath()
|
||||
conversation.getPhysicalPath(),
|
||||
)
|
||||
self.assertEqual(
|
||||
'http://nohost/plone/doc1/++conversation++default',
|
||||
conversation.absolute_url()
|
||||
conversation.absolute_url(),
|
||||
)
|
||||
|
||||
def test_unconvertible_id(self):
|
||||
# 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++default/ThisCantBeRight'
|
||||
'++conversation++default/ThisCantBeRight',
|
||||
)
|
||||
self.assertEqual(conversation, None)
|
||||
|
||||
@ -668,7 +668,7 @@ class ConversationTest(unittest.TestCase):
|
||||
# Make sure no conversation has been created
|
||||
self.assertTrue(
|
||||
'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'])
|
||||
interface.alsoProvides(
|
||||
self.portal.REQUEST,
|
||||
interfaces.IDiscussionLayer
|
||||
interfaces.IDiscussionLayer,
|
||||
)
|
||||
|
||||
if DEXTERITY:
|
||||
interface.alsoProvides(
|
||||
self.portal.doc1,
|
||||
IDexterityContent
|
||||
IDexterityContent,
|
||||
)
|
||||
|
||||
def _makeOne(self, *args, **kw):
|
||||
@ -847,18 +847,18 @@ class RepliesTest(unittest.TestCase):
|
||||
# Create the nested comment structure
|
||||
new_id_1 = replies.addComment(comment1)
|
||||
comment1 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_id_1)
|
||||
'++conversation++default/{0}'.format(new_id_1),
|
||||
)
|
||||
replies_to_comment1 = IReplies(comment1)
|
||||
new_id_2 = replies.addComment(comment2)
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_id_2)
|
||||
'++conversation++default/{0}'.format(new_id_2),
|
||||
)
|
||||
replies_to_comment2 = IReplies(comment2)
|
||||
|
||||
new_id_1_1 = replies_to_comment1.addComment(comment1_1)
|
||||
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.addComment(comment1_1_1)
|
||||
|
@ -152,7 +152,7 @@ class RepliesEventsTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.document.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
'++conversation++default/{0}'.format(new_id),
|
||||
)
|
||||
|
||||
re_comment = createObject('plone.Comment')
|
||||
@ -173,7 +173,7 @@ class RepliesEventsTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
'++conversation++default/{0}'.format(new_id),
|
||||
)
|
||||
|
||||
re_comment = createObject('plone.Comment')
|
||||
|
@ -25,11 +25,16 @@ normal_testfiles = [
|
||||
def test_suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTests([
|
||||
layered(doctest.DocFileSuite(test,
|
||||
layered(
|
||||
doctest.DocFileSuite(
|
||||
test,
|
||||
optionflags=optionflags,
|
||||
globs={'pprint': pprint.pprint,
|
||||
globs={
|
||||
'pprint': pprint.pprint,
|
||||
}
|
||||
),
|
||||
layer=PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING)
|
||||
for test in normal_testfiles])
|
||||
layer=PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING,
|
||||
)
|
||||
for test in normal_testfiles
|
||||
])
|
||||
return suite
|
||||
|
@ -70,7 +70,7 @@ class ConversationIndexersTest(unittest.TestCase):
|
||||
def test_conversation_total_comments(self):
|
||||
self.assertTrue(isinstance(
|
||||
catalog.total_comments,
|
||||
DelegatingIndexerFactory
|
||||
DelegatingIndexerFactory,
|
||||
))
|
||||
self.assertEqual(catalog.total_comments(self.portal.doc1)(), 3)
|
||||
del self.conversation[self.new_id1]
|
||||
@ -82,16 +82,16 @@ class ConversationIndexersTest(unittest.TestCase):
|
||||
def test_conversation_last_comment_date(self):
|
||||
self.assertTrue(isinstance(
|
||||
catalog.last_comment_date,
|
||||
DelegatingIndexerFactory
|
||||
DelegatingIndexerFactory,
|
||||
))
|
||||
self.assertEqual(
|
||||
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]
|
||||
self.assertEqual(
|
||||
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_id1]
|
||||
@ -138,7 +138,7 @@ class CommentIndexersTest(unittest.TestCase):
|
||||
def test_description(self):
|
||||
self.assertEqual(
|
||||
catalog.description(self.comment)(),
|
||||
'Lorem ipsum dolor sit amet.'
|
||||
'Lorem ipsum dolor sit amet.',
|
||||
)
|
||||
self.assertTrue(
|
||||
isinstance(catalog.description, DelegatingIndexerFactory))
|
||||
@ -153,33 +153,33 @@ class CommentIndexersTest(unittest.TestCase):
|
||||
self.conversation.addComment(comment_long)
|
||||
self.assertEqual(
|
||||
catalog.description(comment_long)(),
|
||||
LONG_TEXT_CUT.replace('\n', ' ')
|
||||
LONG_TEXT_CUT.replace('\n', ' '),
|
||||
)
|
||||
|
||||
def test_dates(self):
|
||||
# Test if created, modified, effective etc. are set correctly
|
||||
self.assertEqual(
|
||||
catalog.created(self.comment)(),
|
||||
DateTime(2006, 9, 17, 14, 18, 12, 'GMT')
|
||||
DateTime(2006, 9, 17, 14, 18, 12, 'GMT'),
|
||||
)
|
||||
self.assertEqual(
|
||||
catalog.effective(self.comment)(),
|
||||
DateTime(2006, 9, 17, 14, 18, 12, 'GMT')
|
||||
DateTime(2006, 9, 17, 14, 18, 12, 'GMT'),
|
||||
)
|
||||
self.assertEqual(
|
||||
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):
|
||||
# Test if searchable text is a concatenation of title and comment text
|
||||
self.assertEqual(
|
||||
catalog.searchable_text(self.comment)(),
|
||||
('Lorem ipsum dolor sit amet.')
|
||||
('Lorem ipsum dolor sit amet.'),
|
||||
)
|
||||
self.assertTrue(isinstance(
|
||||
catalog.searchable_text,
|
||||
DelegatingIndexerFactory
|
||||
DelegatingIndexerFactory,
|
||||
))
|
||||
|
||||
def test_creator(self):
|
||||
|
@ -69,7 +69,9 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
None)
|
||||
self.context = self.portal
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',), 'comment_review_workflow')
|
||||
('Discussion Item',),
|
||||
'comment_review_workflow',
|
||||
)
|
||||
self.wf_tool = self.portal.portal_workflow
|
||||
# Add a conversation with three comments
|
||||
conversation = IConversation(self.portal.doc1)
|
||||
@ -79,7 +81,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
comment1.Creator = 'Jim'
|
||||
new_id_1 = conversation.addComment(comment1)
|
||||
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.title = 'Comment 2'
|
||||
@ -87,7 +89,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
comment2.Creator = 'Joe'
|
||||
new_id_2 = conversation.addComment(comment2)
|
||||
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.title = 'Comment 3'
|
||||
@ -95,7 +97,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
comment3.Creator = 'Emma'
|
||||
new_id_3 = conversation.addComment(comment3)
|
||||
self.comment3 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(new_id_3)
|
||||
'++conversation++default/{0}'.format(new_id_3),
|
||||
)
|
||||
self.conversation = conversation
|
||||
|
||||
@ -114,8 +116,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
|
||||
view = BulkActionsView(self.portal, self.request)
|
||||
|
||||
self.assertRaises(NotImplementedError,
|
||||
view)
|
||||
self.assertRaises(NotImplementedError, view)
|
||||
|
||||
def test_publish(self):
|
||||
self.request.set('form.select.BulkAction', 'publish')
|
||||
@ -176,12 +177,13 @@ class RedirectionTest(unittest.TestCase):
|
||||
settings.globally_enabled = True
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('comment_review_workflow',))
|
||||
('comment_review_workflow',),
|
||||
)
|
||||
# Create page plus comment.
|
||||
self.portal.invokeFactory(
|
||||
id='page',
|
||||
title='Page 1',
|
||||
type_name='Document'
|
||||
type_name='Document',
|
||||
)
|
||||
self.page = self.portal.page
|
||||
self.conversation = IConversation(self.page)
|
||||
|
@ -176,7 +176,7 @@ class TestModeratorNotificationUnit(unittest.TestCase):
|
||||
self.portal.portal_types['Document'].allow_discussion = True
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('comment_review_workflow',)
|
||||
('comment_review_workflow',),
|
||||
)
|
||||
# Enable moderator notification setting
|
||||
registry = queryUtility(IRegistry)
|
||||
@ -219,23 +219,23 @@ class TestModeratorNotificationUnit(unittest.TestCase):
|
||||
in msg)
|
||||
self.assertIn(
|
||||
'http://nohost/plone/d=\noc1/view#{0}'.format(comment_id),
|
||||
msg
|
||||
msg,
|
||||
)
|
||||
self.assertIn(
|
||||
'Comment text',
|
||||
msg
|
||||
msg,
|
||||
)
|
||||
text = 'Approve comment:\nhttp://nohost/plone/doc1/' \
|
||||
'++conversation++default/{0}/@@moderat=\ne-publish-comment'
|
||||
self.assertIn(
|
||||
text.format(comment_id),
|
||||
msg
|
||||
msg,
|
||||
)
|
||||
text = 'Delete comment:\nhttp://nohost/plone/doc1/' \
|
||||
'++conversation++default/{0}/@@moderat=\ne-delete-comment'
|
||||
self.assertIn(
|
||||
text.format(comment_id),
|
||||
msg
|
||||
msg,
|
||||
)
|
||||
|
||||
def test_notify_moderator_specific_address(self):
|
||||
|
@ -23,7 +23,7 @@ def test_suite():
|
||||
suite.addTests([
|
||||
layered(
|
||||
robottestsuite,
|
||||
layer=PLONE_APP_DISCUSSION_ROBOT_TESTING
|
||||
layer=PLONE_APP_DISCUSSION_ROBOT_TESTING,
|
||||
),
|
||||
])
|
||||
return suite
|
||||
|
@ -47,8 +47,8 @@ class WorkflowSetupTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
('comment_one_state_workflow',),
|
||||
self.portal.portal_workflow.getChainForPortalType(
|
||||
'Discussion Item'
|
||||
)
|
||||
'Discussion Item',
|
||||
),
|
||||
)
|
||||
|
||||
def test_review_comments_permission(self):
|
||||
@ -61,9 +61,9 @@ class WorkflowSetupTest(unittest.TestCase):
|
||||
self.assertFalse(
|
||||
self.portal.portal_membership.checkPermission(
|
||||
'Review comments',
|
||||
self.folder
|
||||
self.folder,
|
||||
),
|
||||
self.folder
|
||||
self.folder,
|
||||
)
|
||||
|
||||
def test_reply_to_item_permission(self):
|
||||
@ -125,7 +125,7 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
|
||||
cid = conversation.addComment(comment)
|
||||
|
||||
self.comment = self.folder.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(cid)
|
||||
'++conversation++default/{0}'.format(cid),
|
||||
)
|
||||
|
||||
self.portal.acl_users._doAddUser('member', 'secret', ['Member'], [])
|
||||
@ -138,8 +138,10 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
|
||||
def test_initial_workflow_state(self):
|
||||
"""Make sure the initial workflow state of a comment is 'private'.
|
||||
"""
|
||||
self.assertEqual(self.workflow.getInfoFor(self.doc, 'review_state'),
|
||||
'private')
|
||||
self.assertEqual(
|
||||
self.workflow.getInfoFor(self.doc, 'review_state'),
|
||||
'private',
|
||||
)
|
||||
|
||||
def test_view_comments(self):
|
||||
"""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.
|
||||
self.assertEqual(
|
||||
self.portal.portal_workflow.getChainFor('Discussion Item'),
|
||||
('comment_one_state_workflow',))
|
||||
('comment_one_state_workflow',),
|
||||
)
|
||||
# A Manager can still see the comment.
|
||||
self.assertTrue(checkPerm(View, self.comment))
|
||||
# Anonymous cannot see the comment.
|
||||
@ -209,7 +212,8 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
# Set workflow for Discussion item to review workflow
|
||||
self.portal.portal_workflow.setChainForPortalTypes(
|
||||
('Discussion Item',),
|
||||
('comment_review_workflow',))
|
||||
('comment_review_workflow',),
|
||||
)
|
||||
|
||||
# Create a conversation for this Document
|
||||
conversation = IConversation(self.portal.doc1)
|
||||
@ -219,7 +223,7 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
comment_id = conversation.addComment(comment)
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/{0}'.format(comment_id)
|
||||
'++conversation++default/{0}'.format(comment_id),
|
||||
)
|
||||
|
||||
self.conversation = conversation
|
||||
@ -239,9 +243,11 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
# Make sure that anonymous users can not delete comments
|
||||
logout()
|
||||
self.portal.REQUEST.form['comment_id'] = self.comment_id
|
||||
self.assertRaises(Unauthorized,
|
||||
self.assertRaises(
|
||||
Unauthorized,
|
||||
self.comment.restrictedTraverse,
|
||||
'@@moderate-delete-comment')
|
||||
'@@moderate-delete-comment',
|
||||
)
|
||||
self.assertTrue(self.comment_id in self.conversation.objectIds())
|
||||
|
||||
def test_delete_as_user(self):
|
||||
@ -249,9 +255,11 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
logout()
|
||||
setRoles(self.portal, TEST_USER_ID, ['Member'])
|
||||
self.portal.REQUEST.form['comment_id'] = self.comment_id
|
||||
self.assertRaises(Unauthorized,
|
||||
self.assertRaises(
|
||||
Unauthorized,
|
||||
self.comment.restrictedTraverse,
|
||||
'@@moderate-delete-comment')
|
||||
'@@moderate-delete-comment',
|
||||
)
|
||||
self.assertTrue(self.comment_id in self.conversation.objectIds())
|
||||
|
||||
def test_publish(self):
|
||||
@ -261,8 +269,8 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
'pending',
|
||||
self.portal.portal_workflow.getInfoFor(
|
||||
self.comment,
|
||||
'review_state'
|
||||
)
|
||||
'review_state',
|
||||
),
|
||||
)
|
||||
view = self.comment.restrictedTraverse('@@moderate-publish-comment')
|
||||
view()
|
||||
@ -270,8 +278,8 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
'published',
|
||||
self.portal.portal_workflow.getInfoFor(
|
||||
self.comment,
|
||||
'review_state'
|
||||
)
|
||||
'review_state',
|
||||
),
|
||||
)
|
||||
|
||||
def test_publish_as_anonymous(self):
|
||||
@ -281,20 +289,20 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
self.assertEqual(
|
||||
'pending', self.portal.portal_workflow.getInfoFor(
|
||||
self.comment,
|
||||
'review_state'
|
||||
)
|
||||
'review_state',
|
||||
),
|
||||
)
|
||||
self.assertRaises(
|
||||
Unauthorized,
|
||||
self.comment.restrictedTraverse,
|
||||
'@@moderate-publish-comment'
|
||||
'@@moderate-publish-comment',
|
||||
)
|
||||
self.assertEqual(
|
||||
'pending',
|
||||
self.portal.portal_workflow.getInfoFor(
|
||||
self.comment,
|
||||
'review_state'
|
||||
)
|
||||
'review_state',
|
||||
),
|
||||
)
|
||||
|
||||
def test_publish_comment_on_private_content_not_visible_to_world(self):
|
||||
|
5
setup.py
5
setup.py
@ -4,7 +4,7 @@ from setuptools import find_packages
|
||||
from setuptools import setup
|
||||
|
||||
|
||||
version = '3.0.6.dev0'
|
||||
version = '3.0.7.dev0'
|
||||
|
||||
install_requires = [
|
||||
'setuptools',
|
||||
@ -37,9 +37,12 @@ setup(name='plone.app.discussion',
|
||||
'Framework :: Plone',
|
||||
'Framework :: Plone :: 5.0',
|
||||
'Framework :: Plone :: 5.1',
|
||||
'Framework :: Plone :: 5.2',
|
||||
'License :: OSI Approved :: GNU General Public License (GPL)',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
],
|
||||
keywords='plone discussion',
|
||||
author='Timo Stollenwerk - Plone Foundation',
|
||||
|
Loading…
Reference in New Issue
Block a user