merge master in filippo_moderation_js
This commit is contained in:
commit
3648c3345f
20
CHANGES.rst
20
CHANGES.rst
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
)
|
||||||
|
@ -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 "
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -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',
|
||||||
)
|
)
|
||||||
|
@ -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.
|
||||||
|
@ -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),
|
||||||
)
|
)
|
||||||
|
@ -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><b>Got HTML?</b></p>'
|
'<p><b>Got HTML?</b></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(),
|
||||||
)
|
)
|
||||||
|
@ -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'],
|
||||||
|
)
|
||||||
|
@ -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')
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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')
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
@ -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)
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
@ -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):
|
||||||
|
5
setup.py
5
setup.py
@ -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',
|
||||||
|
Loading…
Reference in New Issue
Block a user