commit
f0d837294f
@ -15,6 +15,8 @@ Fixes:
|
||||
Issue https://github.com/plone/Products.CMFPlone/issues/1332
|
||||
[staeff, fredvd]
|
||||
|
||||
- Cleanup code according to our style guide.
|
||||
[gforcada]
|
||||
|
||||
|
||||
2.4.9 (2015-11-25)
|
||||
|
@ -1,6 +1,2 @@
|
||||
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
|
||||
try:
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
except ImportError:
|
||||
from pkgutil import extend_path
|
||||
__path__ = extend_path(__path__, __name__)
|
||||
# -*- coding: utf-8 -*-
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
|
@ -1,6 +1,2 @@
|
||||
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
|
||||
try:
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
except ImportError:
|
||||
from pkgutil import extend_path
|
||||
__path__ = extend_path(__path__, __name__)
|
||||
# -*- coding: utf-8 -*-
|
||||
__import__('pkg_resources').declare_namespace(__name__)
|
||||
|
@ -12,7 +12,8 @@ from z3c.form import interfaces
|
||||
from z3c.form.field import Fields
|
||||
from zope import interface
|
||||
from zope.annotation import factory
|
||||
from zope.component import adapts, queryUtility
|
||||
from zope.component import adapts
|
||||
from zope.component import queryUtility
|
||||
from zope.interface import Interface
|
||||
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
|
||||
|
||||
@ -51,7 +52,7 @@ class CaptchaExtender(extensible.FormExtender):
|
||||
def update(self):
|
||||
if self.captcha != 'disabled' and self.isAnon:
|
||||
# Add a captcha field if captcha is enabled in the registry
|
||||
self.add(ICaptcha, prefix="")
|
||||
self.add(ICaptcha, prefix='')
|
||||
if self.captcha == 'captcha':
|
||||
from plone.formwidget.captcha import CaptchaFieldWidget
|
||||
self.form.fields['captcha'].widgetFactory = CaptchaFieldWidget
|
||||
|
@ -1,16 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from AccessControl import getSecurityManager
|
||||
from Acquisition import aq_inner
|
||||
from Acquisition import aq_parent
|
||||
from zope.component import getUtility
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from comments import CommentForm
|
||||
from plone.app.discussion import _
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from plone.z3cform.layout import wrap_form
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from z3c.form import button
|
||||
from zope.component import getMultiAdapter
|
||||
from zope.component import getUtility
|
||||
|
||||
|
||||
class View(BrowserView):
|
||||
@ -21,9 +22,9 @@ class View(BrowserView):
|
||||
has been posted.
|
||||
|
||||
Redirect from the comment object URL
|
||||
"/path/to/object/++conversation++default/123456789" to the content object
|
||||
'/path/to/object/++conversation++default/123456789' to the content object
|
||||
where the comment has been posted appended by an HTML anchor that points to
|
||||
the comment "/path/to/object#comment-123456789".
|
||||
the comment '/path/to/object#comment-123456789'.
|
||||
|
||||
Context is the comment object. The parent of the comment object is the
|
||||
conversation. The parent of the conversation is the content object where
|
||||
@ -46,15 +47,15 @@ class View(BrowserView):
|
||||
will redirect right to the binary object, bypassing comments.
|
||||
"""
|
||||
if obj.portal_type in view_action_types:
|
||||
url = "%s/view" % url
|
||||
url = '{0}/view'.format(url)
|
||||
|
||||
self.request.response.redirect('%s#%s' % (url, context.id))
|
||||
self.request.response.redirect('{0}#{1}'.format(url, context.id))
|
||||
|
||||
|
||||
class EditCommentForm(CommentForm):
|
||||
"""Form to edit an existing comment."""
|
||||
ignoreContext = True
|
||||
id = "edit-comment-form"
|
||||
id = 'edit-comment-form'
|
||||
label = _(u'edit_comment_form_title', default=u'Edit comment')
|
||||
|
||||
def updateWidgets(self):
|
||||
@ -71,8 +72,8 @@ class EditCommentForm(CommentForm):
|
||||
target = portal_state.portal_url()
|
||||
self.request.response.redirect(target)
|
||||
|
||||
@button.buttonAndHandler(_(u"edit_comment_form_button",
|
||||
default=u"Edit comment"), name='comment')
|
||||
@button.buttonAndHandler(_(u'edit_comment_form_button',
|
||||
default=u'Edit comment'), name='comment')
|
||||
def handleComment(self, action):
|
||||
|
||||
# Validate form
|
||||
@ -93,19 +94,19 @@ class EditCommentForm(CommentForm):
|
||||
|
||||
# Redirect to comment
|
||||
IStatusMessage(self.request).add(_(u'comment_edit_notification',
|
||||
default="Comment was edited"),
|
||||
default='Comment was edited'),
|
||||
type='info')
|
||||
return self._redirect(
|
||||
target=self.action.replace("@@edit-comment", "@@view"))
|
||||
target=self.action.replace('@@edit-comment', '@@view'))
|
||||
|
||||
@button.buttonAndHandler(_(u'cancel_form_button',
|
||||
default=u'Cancel'), name='cancel')
|
||||
def handle_cancel(self, action):
|
||||
IStatusMessage(self.request).add(
|
||||
_(u'comment_edit_cancel_notification',
|
||||
default=u'Edit comment cancelled'),
|
||||
type='info')
|
||||
return self._redirect(target=self.context.absolute_url())
|
||||
IStatusMessage(self.request).add(
|
||||
_(u'comment_edit_cancel_notification',
|
||||
default=u'Edit comment cancelled'),
|
||||
type='info')
|
||||
return self._redirect(target=self.context.absolute_url())
|
||||
|
||||
EditComment = wrap_form(EditCommentForm)
|
||||
|
||||
|
@ -2,11 +2,8 @@
|
||||
from AccessControl import getSecurityManager
|
||||
from AccessControl import Unauthorized
|
||||
from Acquisition import aq_inner
|
||||
from DateTime import DateTime
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from datetime import datetime
|
||||
from DateTime import DateTime
|
||||
from plone.app.discussion import _
|
||||
from plone.app.discussion.browser.validator import CaptchaValidator
|
||||
from plone.app.discussion.interfaces import ICaptcha
|
||||
@ -19,6 +16,9 @@ from plone.registry.interfaces import IRegistry
|
||||
from plone.z3cform import z2
|
||||
from plone.z3cform.fieldsets import extensible
|
||||
from plone.z3cform.interfaces import IWrappedForm
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from urllib import quote as url_quote
|
||||
from z3c.form import button
|
||||
from z3c.form import field
|
||||
@ -34,32 +34,36 @@ from zope.interface import alsoProvides
|
||||
|
||||
|
||||
COMMENT_DESCRIPTION_PLAIN_TEXT = _(
|
||||
u"comment_description_plain_text",
|
||||
default=u"You can add a comment by filling out the form below. " +
|
||||
u"Plain text formatting.")
|
||||
u'comment_description_plain_text',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting.'
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_MARKDOWN = _(
|
||||
u"comment_description_markdown",
|
||||
default=u"You can add a comment by filling out the form below. " +
|
||||
u"Plain text formatting. You can use the Markdown syntax for " +
|
||||
u"links and images.")
|
||||
u'comment_description_markdown',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting. You can use the Markdown syntax for '
|
||||
u'links and images.'
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _(
|
||||
u"comment_description_intelligent_text",
|
||||
default=u"You can add a comment by filling out the form below. " +
|
||||
u"Plain text formatting. Web and email addresses are " +
|
||||
u"transformed into clickable links.")
|
||||
u'comment_description_intelligent_text',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting. Web and email addresses are '
|
||||
u'transformed into clickable links.'
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_MODERATION_ENABLED = _(
|
||||
u"comment_description_moderation_enabled",
|
||||
default=u"Comments are moderated.")
|
||||
u'comment_description_moderation_enabled',
|
||||
default=u'Comments are moderated.'
|
||||
)
|
||||
|
||||
|
||||
class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
ignoreContext = True # don't use context to get widget data
|
||||
id = None
|
||||
label = _(u"Add a comment")
|
||||
label = _(u'Add a comment')
|
||||
fields = field.Fields(IComment).omit('portal_type',
|
||||
'__parent__',
|
||||
'__name__',
|
||||
@ -81,13 +85,13 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
# Widgets
|
||||
self.widgets['in_reply_to'].mode = interfaces.HIDDEN_MODE
|
||||
self.widgets['text'].addClass("autoresize")
|
||||
self.widgets['user_notification'].label = _(u"")
|
||||
self.widgets['text'].addClass('autoresize')
|
||||
self.widgets['user_notification'].label = _(u'')
|
||||
|
||||
# Rename the id of the text widgets because there can be css-id
|
||||
# clashes with the text field of documents when using and overlay
|
||||
# with TinyMCE.
|
||||
self.widgets['text'].id = "form-widgets-comment-text"
|
||||
self.widgets['text'].id = 'form-widgets-comment-text'
|
||||
|
||||
# Anonymous / Logged-in
|
||||
mtool = getToolByName(self.context, 'portal_membership')
|
||||
@ -99,7 +103,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if anon:
|
||||
if settings.anonymous_email_enabled:
|
||||
# according to IDiscussionSettings.anonymous_email_enabled:
|
||||
# "If selected, anonymous user will have to give their email."
|
||||
# 'If selected, anonymous user will have to give their email.'
|
||||
self.widgets['author_email'].field.required = True
|
||||
self.widgets['author_email'].required = True
|
||||
else:
|
||||
@ -121,11 +125,11 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
def updateActions(self):
|
||||
super(CommentForm, self).updateActions()
|
||||
self.actions['cancel'].addClass("standalone")
|
||||
self.actions['cancel'].addClass("hide")
|
||||
self.actions['comment'].addClass("context")
|
||||
self.actions['cancel'].addClass('standalone')
|
||||
self.actions['cancel'].addClass('hide')
|
||||
self.actions['comment'].addClass('context')
|
||||
|
||||
@button.buttonAndHandler(_(u"add_comment_button", default=u"Comment"),
|
||||
@button.buttonAndHandler(_(u'add_comment_button', default=u'Comment'),
|
||||
name='comment')
|
||||
def handleComment(self, action):
|
||||
context = aq_inner(self.context)
|
||||
@ -134,8 +138,9 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if not self.__parent__.restrictedTraverse(
|
||||
'@@conversation_view'
|
||||
).enabled():
|
||||
raise Unauthorized("Discussion is not enabled for this content "
|
||||
"object.")
|
||||
raise Unauthorized(
|
||||
'Discussion is not enabled for this content object.'
|
||||
)
|
||||
|
||||
# Validation form
|
||||
data, errors = self.extractData()
|
||||
@ -151,7 +156,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
anon = portal_membership.isAnonymousUser()
|
||||
if captcha_enabled and anonymous_comments and anon:
|
||||
if 'captcha' not in data:
|
||||
data['captcha'] = u""
|
||||
data['captcha'] = u''
|
||||
captcha = CaptchaValidator(self.context,
|
||||
self.request,
|
||||
None,
|
||||
@ -160,7 +165,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
captcha.validate(data['captcha'])
|
||||
|
||||
# some attributes are not always set
|
||||
author_name = u""
|
||||
author_name = u''
|
||||
|
||||
# Create comment
|
||||
comment = createObject('plone.Comment')
|
||||
@ -207,14 +212,14 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if email and isinstance(email, str):
|
||||
email = unicode(email, 'utf-8')
|
||||
comment.changeOwnership(user, recursive=False)
|
||||
comment.manage_setLocalRoles(memberid, ["Owner"])
|
||||
comment.manage_setLocalRoles(memberid, ['Owner'])
|
||||
comment.creator = memberid
|
||||
comment.author_username = memberid
|
||||
comment.author_name = fullname
|
||||
|
||||
# XXX: according to IComment interface author_email must not be
|
||||
# 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'
|
||||
comment.author_email = email
|
||||
# /XXX
|
||||
|
||||
@ -223,8 +228,8 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
else: # pragma: no cover
|
||||
raise Unauthorized(
|
||||
u"Anonymous user tries to post a comment, but anonymous "
|
||||
u"commenting is disabled. Or user does not have the "
|
||||
u'Anonymous user tries to post a comment, but anonymous '
|
||||
u'commenting is disabled. Or user does not have the '
|
||||
u"'reply to item' permission."
|
||||
)
|
||||
|
||||
@ -255,14 +260,14 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if comment_review_state == 'pending' and not can_review:
|
||||
# Show info message when comment moderation is enabled
|
||||
IStatusMessage(self.context.REQUEST).addStatusMessage(
|
||||
_("Your comment awaits moderator approval."),
|
||||
type="info")
|
||||
_('Your comment awaits moderator approval.'),
|
||||
type='info')
|
||||
self.request.response.redirect(self.action)
|
||||
else:
|
||||
# Redirect to comment (inside a content object page)
|
||||
self.request.response.redirect(self.action + '#' + str(comment_id))
|
||||
|
||||
@button.buttonAndHandler(_(u"Cancel"))
|
||||
@button.buttonAndHandler(_(u'Cancel'))
|
||||
def handleCancel(self, action):
|
||||
# This method should never be called, it's only there to show
|
||||
# a cancel button that is handled by a jQuery method.
|
||||
@ -278,9 +283,9 @@ class CommentsViewlet(ViewletBase):
|
||||
super(CommentsViewlet, self).update()
|
||||
discussion_allowed = self.is_discussion_allowed()
|
||||
anonymous_allowed_or_can_reply = (
|
||||
self.is_anonymous()
|
||||
and self.anonymous_discussion_allowed()
|
||||
or self.can_reply()
|
||||
self.is_anonymous() and
|
||||
self.anonymous_discussion_allowed() or
|
||||
self.can_reply()
|
||||
)
|
||||
if discussion_allowed and anonymous_allowed_or_can_reply:
|
||||
z2.switch_on(self, request_layer=IFormLayer)
|
||||
@ -356,10 +361,10 @@ class CommentsViewlet(ViewletBase):
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
|
||||
# text transform setting
|
||||
if settings.text_transform == "text/x-web-intelligent":
|
||||
if settings.text_transform == 'text/x-web-intelligent':
|
||||
message = translate(Message(COMMENT_DESCRIPTION_INTELLIGENT_TEXT),
|
||||
context=self.request)
|
||||
elif settings.text_transform == "text/x-web-markdown":
|
||||
elif settings.text_transform == 'text/x-web-markdown':
|
||||
message = translate(Message(COMMENT_DESCRIPTION_MARKDOWN),
|
||||
context=self.request)
|
||||
else:
|
||||
@ -367,7 +372,7 @@ class CommentsViewlet(ViewletBase):
|
||||
context=self.request)
|
||||
|
||||
# comment workflow
|
||||
wftool = getToolByName(context, "portal_workflow", None)
|
||||
wftool = getToolByName(context, 'portal_workflow', None)
|
||||
workflow_chain = wftool.getChainForPortalType('Discussion Item')
|
||||
if workflow_chain:
|
||||
comment_workflow = workflow_chain[0]
|
||||
@ -375,7 +380,7 @@ class CommentsViewlet(ViewletBase):
|
||||
# check if the current workflow implements a pending state. If this
|
||||
# is true comments are moderated
|
||||
if 'pending' in comment_workflow.states:
|
||||
message = message + " " + \
|
||||
message = message + ' ' + \
|
||||
translate(Message(COMMENT_DESCRIPTION_MODERATION_ENABLED),
|
||||
context=self.request)
|
||||
|
||||
@ -445,7 +450,7 @@ class CommentsViewlet(ViewletBase):
|
||||
if username is None:
|
||||
return None
|
||||
else:
|
||||
return "%s/author/%s" % (self.context.portal_url(), username)
|
||||
return '{0}/author/{1}'.format(self.context.portal_url(), username)
|
||||
|
||||
def get_commenter_portrait(self, username=None):
|
||||
|
||||
@ -491,9 +496,10 @@ class CommentsViewlet(ViewletBase):
|
||||
return portal_membership.isAnonymousUser()
|
||||
|
||||
def login_action(self):
|
||||
return '%s/login_form?came_from=%s' % \
|
||||
(self.navigation_root_url,
|
||||
url_quote(self.request.get('URL', '')),)
|
||||
return '{0}/login_form?came_from={1}'.format(
|
||||
self.navigation_root_url,
|
||||
url_quote(self.request.get('URL', '')),
|
||||
)
|
||||
|
||||
def format_time(self, time):
|
||||
# We have to transform Python datetime into Zope DateTime
|
||||
|
@ -1,9 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from plone.app.controlpanel.interfaces import IConfigurationChangedEvent
|
||||
from plone.app.discussion.interfaces import _
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
@ -11,6 +6,11 @@ from plone.app.discussion.upgrades import update_registry
|
||||
from plone.app.registry.browser import controlpanel
|
||||
from plone.registry.interfaces import IRecordModifiedEvent
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from z3c.form import button
|
||||
from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget
|
||||
from zope.component import getMultiAdapter
|
||||
@ -23,19 +23,19 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
"""Discussion settings form.
|
||||
"""
|
||||
schema = IDiscussionSettings
|
||||
id = "DiscussionSettingsEditForm"
|
||||
label = _(u"Discussion settings")
|
||||
id = 'DiscussionSettingsEditForm'
|
||||
label = _(u'Discussion settings')
|
||||
description = _(
|
||||
u"help_discussion_settings_editform",
|
||||
default=u"Some discussion related settings are not "
|
||||
u"located in the Discussion Control Panel.\n"
|
||||
u"To enable comments for a specific content type, "
|
||||
u"go to the Types Control Panel of this type and "
|
||||
u"choose \"Allow comments\".\n"
|
||||
u"To enable the moderation workflow for comments, "
|
||||
u"go to the Types Control Panel, choose "
|
||||
u"\"Comment\" and set workflow to "
|
||||
u"\"Comment Review Workflow\"."
|
||||
u'help_discussion_settings_editform',
|
||||
default=u'Some discussion related settings are not '
|
||||
u'located in the Discussion Control Panel.\n'
|
||||
u'To enable comments for a specific content type, '
|
||||
u'go to the Types Control Panel of this type and '
|
||||
u'choose "Allow comments".\n'
|
||||
u'To enable the moderation workflow for comments, '
|
||||
u'go to the Types Control Panel, choose '
|
||||
u'"Comment" and set workflow to '
|
||||
u'"Comment Review Workflow".'
|
||||
)
|
||||
|
||||
def updateFields(self):
|
||||
@ -65,13 +65,15 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
# provide auto-upgrade
|
||||
update_registry(self.context)
|
||||
super(DiscussionSettingsEditForm, self).updateWidgets()
|
||||
self.widgets['globally_enabled'].label = _(u"Enable Comments")
|
||||
self.widgets['anonymous_comments'].label = _(u"Anonymous Comments")
|
||||
self.widgets['show_commenter_image'].label = _(u"Commenter Image")
|
||||
self.widgets['moderator_notification_enabled'].label = \
|
||||
_(u"Moderator Email Notification")
|
||||
self.widgets['user_notification_enabled'].label = \
|
||||
_(u"User Email Notification")
|
||||
self.widgets['globally_enabled'].label = _(u'Enable Comments')
|
||||
self.widgets['anonymous_comments'].label = _(u'Anonymous Comments')
|
||||
self.widgets['show_commenter_image'].label = _(u'Commenter Image')
|
||||
self.widgets['moderator_notification_enabled'].label = _(
|
||||
u'Moderator Email Notification'
|
||||
)
|
||||
self.widgets['user_notification_enabled'].label = _(
|
||||
u'User Email Notification'
|
||||
)
|
||||
|
||||
@button.buttonAndHandler(_('Save'), name=None)
|
||||
def handleSave(self, action):
|
||||
@ -80,16 +82,20 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
self.status = self.formErrorsMessage
|
||||
return
|
||||
self.applyChanges(data)
|
||||
IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
|
||||
"info")
|
||||
self.context.REQUEST.RESPONSE.redirect("@@discussion-controlpanel")
|
||||
IStatusMessage(self.request).addStatusMessage(_(u'Changes saved'),
|
||||
'info')
|
||||
self.context.REQUEST.RESPONSE.redirect('@@discussion-controlpanel')
|
||||
|
||||
@button.buttonAndHandler(_('Cancel'), name='cancel')
|
||||
def handleCancel(self, action):
|
||||
IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"),
|
||||
"info")
|
||||
self.request.response.redirect("%s/%s" % (self.context.absolute_url(),
|
||||
self.control_panel_view))
|
||||
IStatusMessage(self.request).addStatusMessage(_(u'Edit cancelled'),
|
||||
'info')
|
||||
self.request.response.redirect(
|
||||
'{0}/{1}'.format(
|
||||
self.context.absolute_url(),
|
||||
self.control_panel_view
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
||||
@ -104,38 +110,38 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
||||
"""
|
||||
registry = queryUtility(IRegistry)
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
wftool = getToolByName(self.context, "portal_workflow", None)
|
||||
wftool = getToolByName(self.context, 'portal_workflow', None)
|
||||
workflow_chain = wftool.getChainForPortalType('Discussion Item')
|
||||
output = []
|
||||
|
||||
# Globally enabled
|
||||
if settings.globally_enabled:
|
||||
output.append("globally_enabled")
|
||||
output.append('globally_enabled')
|
||||
|
||||
# Comment moderation
|
||||
one_state_worklow_disabled = 'one_state_workflow' not in workflow_chain
|
||||
comment_review_workflow_disabled = \
|
||||
'comment_review_workflow' not in workflow_chain
|
||||
if one_state_worklow_disabled and comment_review_workflow_disabled:
|
||||
output.append("moderation_custom")
|
||||
output.append('moderation_custom')
|
||||
elif settings.moderation_enabled:
|
||||
output.append("moderation_enabled")
|
||||
output.append('moderation_enabled')
|
||||
|
||||
if settings.edit_comment_enabled:
|
||||
output.append("edit_comment_enabled")
|
||||
output.append('edit_comment_enabled')
|
||||
|
||||
if settings.delete_own_comment_enabled:
|
||||
output.append("delte_own_comment_enabled")
|
||||
output.append('delete_own_comment_enabled')
|
||||
|
||||
# Anonymous comments
|
||||
if settings.anonymous_comments:
|
||||
output.append("anonymous_comments")
|
||||
output.append('anonymous_comments')
|
||||
|
||||
# Invalid mail setting
|
||||
ctrlOverview = getMultiAdapter((self.context, self.request),
|
||||
name='overview-controlpanel')
|
||||
if ctrlOverview.mailhost_warning():
|
||||
output.append("invalid_mail_setup")
|
||||
output.append('invalid_mail_setup')
|
||||
|
||||
# Workflow
|
||||
wftool = getToolByName(self.context, 'portal_workflow', None)
|
||||
@ -161,7 +167,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
||||
def custom_comment_workflow_warning(self):
|
||||
"""Returns a warning string if a custom comment workflow is enabled.
|
||||
"""
|
||||
wftool = getToolByName(self.context, "portal_workflow", None)
|
||||
wftool = getToolByName(self.context, 'portal_workflow', None)
|
||||
workflow_chain = wftool.getChainForPortalType('Discussion Item')
|
||||
one_state_workflow_enabled = 'one_state_workflow' in workflow_chain
|
||||
comment_review_workflow_enabled = \
|
||||
|
@ -1,18 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Acquisition import aq_base
|
||||
from Acquisition import aq_chain
|
||||
from Acquisition import aq_inner
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore.interfaces import IFolderish
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces import INonStructuralFolder
|
||||
from Products.CMFPlone.interfaces import IPloneSiteRoot
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from zope.component import queryUtility
|
||||
|
||||
|
||||
try:
|
||||
from plone.dexterity.interfaces import IDexterityContent
|
||||
DEXTERITY_INSTALLED = True
|
||||
except:
|
||||
except ImportError:
|
||||
DEXTERITY_INSTALLED = False
|
||||
|
||||
|
||||
@ -130,7 +132,7 @@ class ConversationView(object):
|
||||
return False
|
||||
|
||||
# Check if discussion is allowed on the content object
|
||||
if hasattr(context, "allow_discussion"):
|
||||
if hasattr(context, 'allow_discussion'):
|
||||
if context.allow_discussion is not None:
|
||||
return context.allow_discussion
|
||||
|
||||
|
@ -1,12 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Acquisition import aq_inner
|
||||
from Acquisition import aq_parent
|
||||
from datetime import datetime
|
||||
from DateTime import DateTime
|
||||
from plone.app.discussion.comment import CommentFactory
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from datetime import datetime
|
||||
from plone.app.discussion.comment import CommentFactory
|
||||
from plone.app.discussion.interfaces import IConversation, IReplies, IComment
|
||||
from types import TupleType
|
||||
|
||||
import transaction
|
||||
@ -35,11 +38,11 @@ class View(BrowserView):
|
||||
self.total_comments_migrated = 0
|
||||
self.total_comments_deleted = 0
|
||||
|
||||
dry_run = "dry_run" in self.request
|
||||
dry_run = 'dry_run' in self.request
|
||||
|
||||
# This is for testing only.
|
||||
# Do not use transactions during a test.
|
||||
test = "test" in self.request
|
||||
test = 'test' in self.request
|
||||
|
||||
if not test:
|
||||
transaction.begin() # pragma: no cover
|
||||
@ -71,10 +74,10 @@ class View(BrowserView):
|
||||
|
||||
for reply in replies:
|
||||
# log
|
||||
indent = " "
|
||||
indent = ' '
|
||||
for i in range(depth):
|
||||
indent += " "
|
||||
log("%smigrate_reply: '%s'." % (indent, reply.title))
|
||||
indent += ' '
|
||||
log('{0}migrate_reply: "{1}".'.format(indent, reply.title))
|
||||
|
||||
should_migrate = True
|
||||
if filter_callback and not filter_callback(reply):
|
||||
@ -172,7 +175,7 @@ class View(BrowserView):
|
||||
talkback.deleteReply(reply.id)
|
||||
obj = aq_parent(talkback)
|
||||
obj.talkback = None
|
||||
log("%sremove %s" % (indent, reply.id))
|
||||
log('{0}remove {1}'.format(indent, reply.id))
|
||||
self.total_comments_deleted += 1
|
||||
|
||||
# Return True when all comments on a certain level have been
|
||||
@ -182,7 +185,7 @@ class View(BrowserView):
|
||||
# Find content
|
||||
brains = catalog.searchResults(
|
||||
object_provides='Products.CMFCore.interfaces._content.IContentish')
|
||||
log("Found %s content objects." % len(brains))
|
||||
log('Found {0} content objects.'.format(len(brains)))
|
||||
|
||||
count_discussion_items = len(
|
||||
catalog.searchResults(Type='Discussion Item')
|
||||
@ -196,12 +199,20 @@ class View(BrowserView):
|
||||
)
|
||||
)
|
||||
|
||||
log("Found %s Discussion Item objects." % count_discussion_items)
|
||||
log("Found %s old discussion items." % count_comments_old)
|
||||
log("Found %s plone.app.discussion comments." % count_comments_pad)
|
||||
log(
|
||||
'Found {0} Discussion Item objects.'.format(
|
||||
count_discussion_items
|
||||
)
|
||||
)
|
||||
log('Found {0} old discussion items.'.format(count_comments_old))
|
||||
log(
|
||||
'Found {0} plone.app.discussion comments.'.format(
|
||||
count_comments_pad
|
||||
)
|
||||
)
|
||||
|
||||
log("\n")
|
||||
log("Start comment migration.")
|
||||
log('\n')
|
||||
log('Start comment migration.')
|
||||
|
||||
# This loop is necessary to get all contentish objects, but not
|
||||
# the Discussion Items. This wouldn't be necessary if the
|
||||
@ -219,46 +230,54 @@ class View(BrowserView):
|
||||
replies = talkback.getReplies()
|
||||
if replies:
|
||||
conversation = IConversation(obj)
|
||||
log("\n")
|
||||
log("Migrate '%s' (%s)" % (obj.Title(),
|
||||
obj.absolute_url(relative=1)))
|
||||
log('\n')
|
||||
log(
|
||||
'Migrate "{0}" ({1})'.format(
|
||||
obj.Title(),
|
||||
obj.absolute_url(relative=1)
|
||||
)
|
||||
)
|
||||
migrate_replies(context, 0, replies)
|
||||
obj = aq_parent(talkback)
|
||||
obj.talkback = None
|
||||
|
||||
if self.total_comments_deleted != self.total_comments_migrated:
|
||||
log(
|
||||
"Something went wrong during migration. The number of " +
|
||||
"migrated comments (%s) differs from the number of deleted " +
|
||||
"comments (%s)." % (
|
||||
'Something went wrong during migration. The number of '
|
||||
'migrated comments ({0}) differs from the number of deleted '
|
||||
'comments ({1}).'.format(
|
||||
self.total_comments_migrated,
|
||||
self.total_comments_deleted
|
||||
)
|
||||
)
|
||||
if not test: # pragma: no cover
|
||||
transaction.abort() # pragma: no cover
|
||||
log("Abort transaction") # pragma: no cover
|
||||
log('Abort transaction') # pragma: no cover
|
||||
|
||||
log("\n")
|
||||
log("Comment migration finished.")
|
||||
log("\n")
|
||||
log('\n')
|
||||
log('Comment migration finished.')
|
||||
log('\n')
|
||||
|
||||
log("%s of %s comments migrated."
|
||||
% (self.total_comments_migrated, count_comments_old))
|
||||
log(
|
||||
'{0} of {1} comments migrated.'.format(
|
||||
self.total_comments_migrated,
|
||||
count_comments_old
|
||||
)
|
||||
)
|
||||
|
||||
if self.total_comments_migrated != count_comments_old:
|
||||
log(
|
||||
"%s comments could not be migrated." % (
|
||||
'{0} comments could not be migrated.'.format(
|
||||
count_comments_old - self.total_comments_migrated
|
||||
)
|
||||
) # pragma: no cover
|
||||
log("Please make sure your " +
|
||||
"portal catalog is up-to-date.") # pragma: no cover
|
||||
log('Please make sure your ' +
|
||||
'portal catalog is up-to-date.') # pragma: no cover
|
||||
|
||||
if dry_run and not test:
|
||||
transaction.abort() # pragma: no cover
|
||||
log("Dry run") # pragma: no cover
|
||||
log("Abort transaction") # pragma: no cover
|
||||
log('Dry run') # pragma: no cover
|
||||
log('Abort transaction') # pragma: no cover
|
||||
if not test:
|
||||
transaction.commit() # pragma: no cover
|
||||
return '\n'.join(out)
|
||||
|
@ -1,15 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from AccessControl import Unauthorized
|
||||
from AccessControl import getSecurityManager
|
||||
from AccessControl import Unauthorized
|
||||
from Acquisition import aq_inner
|
||||
from Acquisition import aq_parent
|
||||
from plone.app.discussion.interfaces import _
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from plone.app.discussion.interfaces import _
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
|
||||
|
||||
class View(BrowserView):
|
||||
@ -101,8 +101,8 @@ class DeleteComment(BrowserView):
|
||||
del conversation[comment.id]
|
||||
content_object.reindexObject()
|
||||
IStatusMessage(self.context.REQUEST).addStatusMessage(
|
||||
_("Comment deleted."),
|
||||
type="info")
|
||||
_('Comment deleted.'),
|
||||
type='info')
|
||||
came_from = self.context.REQUEST.HTTP_REFERER
|
||||
# if the referrer already has a came_from in it, don't redirect back
|
||||
if len(came_from) == 0 or 'came_from=' in came_from:
|
||||
@ -133,14 +133,17 @@ class DeleteOwnComment(DeleteComment):
|
||||
sm = getSecurityManager()
|
||||
comment = comment or aq_inner(self.context)
|
||||
userid = sm.getUser().getId()
|
||||
return (sm.checkPermission('Delete own comments',
|
||||
comment)
|
||||
and 'Owner' in comment.get_local_roles_for_userid(userid))
|
||||
return (
|
||||
sm.checkPermission('Delete own comments', comment) and
|
||||
'Owner' in comment.get_local_roles_for_userid(userid)
|
||||
)
|
||||
|
||||
def can_delete(self, comment=None):
|
||||
comment = comment or self.context
|
||||
return (len(IReplies(aq_inner(comment))) == 0
|
||||
and self.could_delete(comment=comment))
|
||||
return (
|
||||
len(IReplies(aq_inner(comment))) == 0 and
|
||||
self.could_delete(comment=comment)
|
||||
)
|
||||
|
||||
def __call__(self):
|
||||
if self.can_delete():
|
||||
@ -179,8 +182,8 @@ class PublishComment(BrowserView):
|
||||
comment.reindexObject()
|
||||
content_object.reindexObject(idxs=['total_comments'])
|
||||
IStatusMessage(self.context.REQUEST).addStatusMessage(
|
||||
_("Comment approved."),
|
||||
type="info")
|
||||
_('Comment approved.'),
|
||||
type='info')
|
||||
came_from = self.context.REQUEST.HTTP_REFERER
|
||||
# if the referrer already has a came_from in it, don't redirect back
|
||||
if len(came_from) == 0 or 'came_from=' in came_from:
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Implement the ++comments++ traversal namespace. This should return the
|
||||
IDiscussion container for the context, from which traversal will continue
|
||||
into an actual comment object.
|
||||
@ -29,8 +30,8 @@ class ConversationNamespace(object):
|
||||
|
||||
def traverse(self, name, ignore):
|
||||
|
||||
if name == "default":
|
||||
name = u""
|
||||
if name == 'default':
|
||||
name = u''
|
||||
|
||||
conversation = queryAdapter(self.context, IConversation, name=name)
|
||||
if conversation is None:
|
||||
|
@ -1,15 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Catalog indexers, using plone.indexer. These will populate standard catalog
|
||||
indexes with values based on the IComment interface.
|
||||
|
||||
Also provide event handlers to actually catalog the comments.
|
||||
"""
|
||||
from DateTime import DateTime
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.indexer import indexer
|
||||
from plone.uuid.interfaces import IUUID
|
||||
from Products.CMFCore.interfaces import IContentish
|
||||
from Products.CMFPlone.utils import safe_unicode
|
||||
from Products.ZCatalog.interfaces import IZCatalog
|
||||
from plone.app.discussion.interfaces import IConversation, IComment
|
||||
from plone.indexer import indexer
|
||||
from plone.uuid.interfaces import IUUID
|
||||
from string import join
|
||||
|
||||
|
||||
@ -78,7 +80,7 @@ def description(object):
|
||||
text = join(object.getText(
|
||||
targetMimetype='text/plain').split()[:MAX_DESCRIPTION])
|
||||
if len(object.getText().split()) > 25:
|
||||
text += " [...]"
|
||||
text += ' [...]'
|
||||
return text
|
||||
|
||||
|
||||
|
@ -3,16 +3,9 @@
|
||||
"""
|
||||
from AccessControl import ClassSecurityInfo
|
||||
from AccessControl.SecurityManagement import getSecurityManager
|
||||
from Acquisition import Implicit
|
||||
from Acquisition import aq_base
|
||||
from Acquisition import aq_parent
|
||||
from Products.CMFCore import permissions
|
||||
from Products.CMFCore.CMFCatalogAware import CatalogAware
|
||||
from Products.CMFCore.CMFCatalogAware import WorkflowAware
|
||||
from Products.CMFCore.DynamicType import DynamicType
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||
from Products.CMFPlone.utils import safe_unicode
|
||||
from Acquisition import Implicit
|
||||
from datetime import datetime
|
||||
from OFS.owner import Owned
|
||||
from OFS.role import RoleManager
|
||||
@ -27,6 +20,13 @@ from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore import permissions
|
||||
from Products.CMFCore.CMFCatalogAware import CatalogAware
|
||||
from Products.CMFCore.CMFCatalogAware import WorkflowAware
|
||||
from Products.CMFCore.DynamicType import DynamicType
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||
from Products.CMFPlone.utils import safe_unicode
|
||||
from smtplib import SMTPException
|
||||
from zope.annotation.interfaces import IAnnotatable
|
||||
from zope.component import getUtility
|
||||
@ -41,28 +41,28 @@ import logging
|
||||
|
||||
|
||||
COMMENT_TITLE = _(
|
||||
u"comment_title",
|
||||
default=u"${author_name} on ${content}")
|
||||
u'comment_title',
|
||||
default=u'${author_name} on ${content}')
|
||||
|
||||
MAIL_NOTIFICATION_MESSAGE = _(
|
||||
u"mail_notification_message",
|
||||
default=u"A comment on '${title}' "
|
||||
u"has been posted here: ${link}\n\n"
|
||||
u"---\n"
|
||||
u"${text}\n"
|
||||
u"---\n")
|
||||
u'mail_notification_message',
|
||||
default=u'A comment on "${title}" '
|
||||
u'has been posted here: ${link}\n\n'
|
||||
u'---\n'
|
||||
u'${text}\n'
|
||||
u'---\n')
|
||||
|
||||
MAIL_NOTIFICATION_MESSAGE_MODERATOR = _(
|
||||
u"mail_notification_message_moderator",
|
||||
default=u"A comment on '${title}' "
|
||||
u"has been posted here: ${link}\n\n"
|
||||
u"---\n"
|
||||
u"${text}\n"
|
||||
u"---\n\n"
|
||||
u"Approve comment:\n${link_approve}\n\n"
|
||||
u"Delete comment:\n${link_delete}\n")
|
||||
u'mail_notification_message_moderator',
|
||||
default=u'A comment on "${title}" '
|
||||
u'has been posted here: ${link}\n\n'
|
||||
u'---\n'
|
||||
u'${text}\n'
|
||||
u'---\n\n'
|
||||
u'Approve comment:\n${link_approve}\n\n'
|
||||
u'Delete comment:\n${link_delete}\n')
|
||||
|
||||
logger = logging.getLogger("plone.app.discussion")
|
||||
logger = logging.getLogger('plone.app.discussion')
|
||||
|
||||
|
||||
class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
@ -86,10 +86,10 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
comment_id = None # long
|
||||
in_reply_to = None # long
|
||||
|
||||
title = u""
|
||||
title = u''
|
||||
|
||||
mime_type = None
|
||||
text = u""
|
||||
text = u''
|
||||
|
||||
creator = None
|
||||
creation_date = None
|
||||
@ -157,14 +157,12 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
if transform:
|
||||
return transform.getData()
|
||||
else:
|
||||
logger = logging.getLogger("plone.app.discussion")
|
||||
logger.error(_(
|
||||
u"Transform '%s' => '%s' not available." % (
|
||||
sourceMimetype,
|
||||
targetMimetype
|
||||
) +
|
||||
u"Failed to transform comment '%s'." % self.absolute_url()
|
||||
))
|
||||
logger = logging.getLogger('plone.app.discussion')
|
||||
msg = u'Transform "{0}" => "{1}" not available. Failed to ' \
|
||||
u'transform comment "{2}".'
|
||||
logger.error(
|
||||
msg.format(sourceMimetype, targetMimetype, self.absolute_url())
|
||||
)
|
||||
return text
|
||||
|
||||
def Title(self):
|
||||
@ -177,8 +175,8 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
if not self.author_name:
|
||||
author_name = translate(
|
||||
Message(_(
|
||||
u"label_anonymous",
|
||||
default=u"Anonymous"
|
||||
u'label_anonymous',
|
||||
default=u'Anonymous'
|
||||
))
|
||||
)
|
||||
else:
|
||||
@ -198,8 +196,7 @@ class Comment(CatalogAware, WorkflowAware, DynamicType, Traversable,
|
||||
"""
|
||||
return self.creator or self.author_name
|
||||
|
||||
security.declareProtected(permissions.View, 'Type')
|
||||
|
||||
@security.protected(permissions.View)
|
||||
def Type(self):
|
||||
"""The Discussion Item content type.
|
||||
"""
|
||||
@ -292,7 +289,7 @@ def notify_content_object_moved(obj, event):
|
||||
)
|
||||
brains = catalog.searchResults(dict(
|
||||
path={'query': old_path},
|
||||
portal_type="Discussion Item"
|
||||
portal_type='Discussion Item'
|
||||
))
|
||||
for brain in brains:
|
||||
catalog.uncatalog_object(brain.getPath())
|
||||
@ -346,7 +343,7 @@ def notify_user(obj, event):
|
||||
if not emails:
|
||||
return
|
||||
|
||||
subject = translate(_(u"A comment has been posted."),
|
||||
subject = translate(_(u'A comment has been posted.'),
|
||||
context=obj.REQUEST)
|
||||
message = translate(
|
||||
Message(
|
||||
@ -412,7 +409,7 @@ def notify_moderator(obj, event):
|
||||
content_object = aq_parent(conversation)
|
||||
|
||||
# Compose email
|
||||
subject = translate(_(u"A comment has been posted."), context=obj.REQUEST)
|
||||
subject = translate(_(u'A comment has been posted.'), context=obj.REQUEST)
|
||||
link_approve = obj.absolute_url() + '/@@moderate-publish-comment'
|
||||
link_delete = obj.absolute_url() + '/@@moderate-delete-comment'
|
||||
message = translate(
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Content rules handlers
|
||||
"""
|
||||
from plone.app.discussion import _
|
||||
@ -9,6 +10,7 @@ except ImportError:
|
||||
class BaseSubstitution(object):
|
||||
""" Fallback class if plone.stringinterp is not available
|
||||
"""
|
||||
|
||||
def __init__(self, context, **kwargs):
|
||||
self.context = context
|
||||
|
||||
@ -27,6 +29,7 @@ def execute_comment(event):
|
||||
class CommentSubstitution(BaseSubstitution):
|
||||
""" Comment string substitution
|
||||
"""
|
||||
|
||||
def __init__(self, context, **kwargs):
|
||||
super(CommentSubstitution, self).__init__(context, **kwargs)
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The conversation and replies adapters
|
||||
|
||||
The conversation is responsible for storing all comments. It provides a
|
||||
@ -20,12 +21,12 @@ from BTrees.OIBTree import OIBTree
|
||||
from OFS.event import ObjectWillBeAddedEvent
|
||||
from OFS.event import ObjectWillBeRemovedEvent
|
||||
from OFS.Traversable import Traversable
|
||||
from Products.CMFPlone.interfaces import IHideFromBreadcrumbs
|
||||
from Products.CMFPlone import DISCUSSION_ANNOTATION_KEY as ANNOTATION_KEY
|
||||
from persistent import Persistent
|
||||
from plone.app.discussion.comment import Comment
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
from Products.CMFPlone import DISCUSSION_ANNOTATION_KEY as ANNOTATION_KEY
|
||||
from Products.CMFPlone.interfaces import IHideFromBreadcrumbs
|
||||
from zope.annotation.interfaces import IAnnotatable
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
from zope.component import adapter
|
||||
@ -38,7 +39,6 @@ from zope.lifecycleevent import ObjectAddedEvent
|
||||
from zope.lifecycleevent import ObjectCreatedEvent
|
||||
from zope.lifecycleevent import ObjectRemovedEvent
|
||||
|
||||
|
||||
import time
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ class Conversation(Traversable, Persistent, Explicit):
|
||||
|
||||
__allow_access_to_unprotected_subobjects__ = True
|
||||
|
||||
def __init__(self, id="++conversation++default"):
|
||||
def __init__(self, id='++conversation++default'):
|
||||
self.id = id
|
||||
|
||||
# username -> count of comments; key is removed when count reaches 0
|
||||
@ -427,7 +427,7 @@ class CommentReplies(ConversationReplies):
|
||||
)
|
||||
if self.conversation is None or conversation_has_no_children:
|
||||
raise TypeError("This adapter doesn't know what to do with the "
|
||||
"parent conversation")
|
||||
'parent conversation')
|
||||
|
||||
self.comment_id = self.comment.comment_id
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
""" Custom discussion events
|
||||
"""
|
||||
from plone.app.discussion.interfaces import ICommentAddedEvent
|
||||
|
@ -30,25 +30,24 @@ class IConversation(IIterableMapping):
|
||||
"""
|
||||
|
||||
total_comments = schema.Int(
|
||||
title=_(u"Total number of public comments on this item"),
|
||||
title=_(u'Total number of public comments on this item'),
|
||||
min=0,
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
last_comment_date = schema.Date(
|
||||
title=_(u"Date of the most recent public comment"),
|
||||
title=_(u'Date of the most recent public comment'),
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
commentators = schema.Set(
|
||||
title=_(u"The set of unique commentators (usernames)"),
|
||||
title=_(u'The set of unique commentators (usernames)'),
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
public_commentators = schema.Set(
|
||||
title=_(
|
||||
u"The set of unique commentators (usernames) of"
|
||||
u" published_comments"
|
||||
u'The set of unique commentators (usernames) of published_comments'
|
||||
),
|
||||
readonly=True,
|
||||
)
|
||||
@ -129,57 +128,57 @@ class IComment(Interface):
|
||||
"""
|
||||
|
||||
portal_type = schema.ASCIILine(
|
||||
title=_(u"Portal type"),
|
||||
default="Discussion Item",
|
||||
title=_(u'Portal type'),
|
||||
default='Discussion Item',
|
||||
)
|
||||
|
||||
__parent__ = schema.Object(
|
||||
title=_(u"Conversation"), schema=Interface)
|
||||
title=_(u'Conversation'), schema=Interface)
|
||||
|
||||
__name__ = schema.TextLine(title=_(u"Name"))
|
||||
__name__ = schema.TextLine(title=_(u'Name'))
|
||||
|
||||
comment_id = schema.Int(
|
||||
title=_(u"A comment id unique to this conversation"))
|
||||
title=_(u'A comment id unique to this conversation'))
|
||||
|
||||
in_reply_to = schema.Int(
|
||||
title=_(u"Id of comment this comment is in reply to"),
|
||||
title=_(u'Id of comment this comment is in reply to'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
# for logged in comments - set to None for anonymous
|
||||
author_username = schema.TextLine(title=_(u"Name"), required=False)
|
||||
author_username = schema.TextLine(title=_(u'Name'), required=False)
|
||||
|
||||
# for anonymous comments only, set to None for logged in comments
|
||||
author_name = schema.TextLine(title=_(u"Name"), required=False)
|
||||
author_email = schema.TextLine(title=_(u"Email"), required=False)
|
||||
author_name = schema.TextLine(title=_(u'Name'), required=False)
|
||||
author_email = schema.TextLine(title=_(u'Email'), required=False)
|
||||
|
||||
title = schema.TextLine(title=_(u"label_subject",
|
||||
default=u"Subject"))
|
||||
title = schema.TextLine(title=_(u'label_subject',
|
||||
default=u'Subject'))
|
||||
|
||||
mime_type = schema.ASCIILine(title=_(u"MIME type"), default="text/plain")
|
||||
mime_type = schema.ASCIILine(title=_(u'MIME type'), default='text/plain')
|
||||
text = schema.Text(
|
||||
title=_(
|
||||
u"label_comment",
|
||||
default=u"Comment"
|
||||
u'label_comment',
|
||||
default=u'Comment'
|
||||
)
|
||||
)
|
||||
|
||||
user_notification = schema.Bool(
|
||||
title=_(
|
||||
u"Notify me of new comments via email."
|
||||
u'Notify me of new comments via email.'
|
||||
),
|
||||
required=False
|
||||
)
|
||||
|
||||
creator = schema.TextLine(title=_(u"Username of the commenter"))
|
||||
creation_date = schema.Date(title=_(u"Creation date"))
|
||||
modification_date = schema.Date(title=_(u"Modification date"))
|
||||
creator = schema.TextLine(title=_(u'Username of the commenter'))
|
||||
creation_date = schema.Date(title=_(u'Creation date'))
|
||||
modification_date = schema.Date(title=_(u'Modification date'))
|
||||
|
||||
|
||||
class ICaptcha(Interface):
|
||||
"""Captcha/ReCaptcha text field to extend the existing comment form.
|
||||
"""
|
||||
captcha = schema.TextLine(title=_(u"Captcha"),
|
||||
captcha = schema.TextLine(title=_(u'Captcha'),
|
||||
required=False)
|
||||
|
||||
|
||||
@ -195,137 +194,137 @@ class IDiscussionSettings(Interface):
|
||||
# - Search control panel: Show comments in search results
|
||||
|
||||
globally_enabled = schema.Bool(
|
||||
title=_(u"label_globally_enabled",
|
||||
default=u"Globally enable comments"),
|
||||
title=_(u'label_globally_enabled',
|
||||
default=u'Globally enable comments'),
|
||||
description=_(
|
||||
u"help_globally_enabled",
|
||||
default=u"If selected, users are able to post comments on the "
|
||||
u"site. Though, you have to enable comments for "
|
||||
u"specific content types, folders or content objects "
|
||||
u"before users will be able to post comments."
|
||||
u'help_globally_enabled',
|
||||
default=u'If selected, users are able to post comments on the '
|
||||
u'site. Though, you have to enable comments for '
|
||||
u'specific content types, folders or content objects '
|
||||
u'before users will be able to post comments.'
|
||||
),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
anonymous_comments = schema.Bool(
|
||||
title=_(u"label_anonymous_comments",
|
||||
default="Enable anonymous comments"),
|
||||
title=_(u'label_anonymous_comments',
|
||||
default='Enable anonymous comments'),
|
||||
description=_(
|
||||
u"help_anonymous_comments",
|
||||
default=u"If selected, anonymous users are able to post "
|
||||
u"comments without loggin in. It is highly "
|
||||
u"recommended to use a captcha solution to prevent "
|
||||
u"spam if this setting is enabled."
|
||||
u'help_anonymous_comments',
|
||||
default=u'If selected, anonymous users are able to post '
|
||||
u'comments without loggin in. It is highly '
|
||||
u'recommended to use a captcha solution to prevent '
|
||||
u'spam if this setting is enabled.'
|
||||
),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
anonymous_email_enabled = schema.Bool(
|
||||
title=_(u"label_anonymous_email_enabled",
|
||||
default=u"Enable anonymous email field"),
|
||||
title=_(u'label_anonymous_email_enabled',
|
||||
default=u'Enable anonymous email field'),
|
||||
description=_(
|
||||
u"help_anonymous_email_enabled",
|
||||
default=u"If selected, anonymous user will have to "
|
||||
u"give their email."),
|
||||
u'help_anonymous_email_enabled',
|
||||
default=u'If selected, anonymous user will have to '
|
||||
u'give their email.'),
|
||||
required=False,
|
||||
default=False
|
||||
)
|
||||
|
||||
moderation_enabled = schema.Bool(
|
||||
title=_(
|
||||
u"label_moderation_enabled",
|
||||
default="Enable comment moderation"
|
||||
u'label_moderation_enabled',
|
||||
default='Enable comment moderation'
|
||||
),
|
||||
description=_(
|
||||
u"help_moderation_enabled",
|
||||
default=u"If selected, comments will enter a 'Pending' state "
|
||||
u"in which they are invisible to the public. A user "
|
||||
u"with the 'Review comments' permission ('Reviewer' "
|
||||
u"or 'Manager') can approve comments to make them "
|
||||
u"visible to the public. If you want to enable a "
|
||||
u"custom comment workflow, you have to go to the "
|
||||
u"types control panel."
|
||||
u'help_moderation_enabled',
|
||||
default=u'If selected, comments will enter a "Pending" state '
|
||||
u'in which they are invisible to the public. A user '
|
||||
u'with the "Review comments" permission ("Reviewer" '
|
||||
u'or "Manager") can approve comments to make them '
|
||||
u'visible to the public. If you want to enable a '
|
||||
u'custom comment workflow, you have to go to the '
|
||||
u'types control panel.'
|
||||
),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
edit_comment_enabled = schema.Bool(
|
||||
title=_(u"label_edit_comment_enabled",
|
||||
default="Enable editing of comments"),
|
||||
description=_(u"help_edit_comment_enabled",
|
||||
default=u"If selected, supports editing "
|
||||
"of comments for users with the 'Edit comments' "
|
||||
"permission."),
|
||||
title=_(u'label_edit_comment_enabled',
|
||||
default='Enable editing of comments'),
|
||||
description=_(u'help_edit_comment_enabled',
|
||||
default=u'If selected, supports editing '
|
||||
'of comments for users with the "Edit comments" '
|
||||
'permission.'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
delete_own_comment_enabled = schema.Bool(
|
||||
title=_(u"label_delete_own_comment_enabled",
|
||||
default="Enable deleting own comments"),
|
||||
description=_(u"help_delete_own_comment_enabled",
|
||||
default=u"If selected, supports deleting "
|
||||
"of own comments for users with the "
|
||||
"'Delete own comments' permission."),
|
||||
title=_(u'label_delete_own_comment_enabled',
|
||||
default='Enable deleting own comments'),
|
||||
description=_(u'help_delete_own_comment_enabled',
|
||||
default=u'If selected, supports deleting '
|
||||
'of own comments for users with the '
|
||||
'"Delete own comments" permission.'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
|
||||
text_transform = schema.Choice(
|
||||
title=_(u"label_text_transform",
|
||||
default="Comment text transform"),
|
||||
title=_(u'label_text_transform',
|
||||
default='Comment text transform'),
|
||||
description=_(
|
||||
u"help_text_transform",
|
||||
default=u"Use this setting to choose if the comment text " +
|
||||
u"should be transformed in any way. You can choose "
|
||||
u"between 'Plain text' and 'Intelligent text'. " +
|
||||
u"'Intelligent text' converts plain text into HTML " +
|
||||
u"where line breaks and indentation is preserved, " +
|
||||
u"and web and email addresses are made into " +
|
||||
u"clickable links."),
|
||||
u'help_text_transform',
|
||||
default=u'Use this setting to choose if the comment text '
|
||||
u'should be transformed in any way. You can choose '
|
||||
u'between "Plain text" and "Intelligent text". '
|
||||
u'"Intelligent text" converts plain text into HTML '
|
||||
u'where line breaks and indentation is preserved, '
|
||||
u'and web and email addresses are made into '
|
||||
u'clickable links.'),
|
||||
required=True,
|
||||
default='text/plain',
|
||||
vocabulary='plone.app.discussion.vocabularies.TextTransformVocabulary',
|
||||
)
|
||||
|
||||
captcha = schema.Choice(
|
||||
title=_(u"label_captcha",
|
||||
default="Captcha"),
|
||||
title=_(u'label_captcha',
|
||||
default='Captcha'),
|
||||
description=_(
|
||||
u"help_captcha",
|
||||
default=u"Use this setting to enable or disable Captcha "
|
||||
u"validation for comments. Install "
|
||||
u"plone.formwidget.captcha, "
|
||||
u"plone.formwidget.recaptcha, collective.akismet, or "
|
||||
u"collective.z3cform.norobots if there are no options "
|
||||
u"available."),
|
||||
u'help_captcha',
|
||||
default=u'Use this setting to enable or disable Captcha '
|
||||
u'validation for comments. Install '
|
||||
u'plone.formwidget.captcha, '
|
||||
u'plone.formwidget.recaptcha, collective.akismet, or '
|
||||
u'collective.z3cform.norobots if there are no options '
|
||||
u'available.'),
|
||||
required=True,
|
||||
default='disabled',
|
||||
vocabulary='plone.app.discussion.vocabularies.CaptchaVocabulary',
|
||||
)
|
||||
|
||||
show_commenter_image = schema.Bool(
|
||||
title=_(u"label_show_commenter_image",
|
||||
default=u"Show commenter image"),
|
||||
title=_(u'label_show_commenter_image',
|
||||
default=u'Show commenter image'),
|
||||
description=_(
|
||||
u"help_show_commenter_image",
|
||||
default=u"If selected, an image of the user is shown next to "
|
||||
u"the comment."),
|
||||
u'help_show_commenter_image',
|
||||
default=u'If selected, an image of the user is shown next to '
|
||||
u'the comment.'),
|
||||
required=False,
|
||||
default=True,
|
||||
)
|
||||
|
||||
moderator_notification_enabled = schema.Bool(
|
||||
title=_(u"label_moderator_notification_enabled",
|
||||
default=u"Enable moderator email notification"),
|
||||
title=_(u'label_moderator_notification_enabled',
|
||||
default=u'Enable moderator email notification'),
|
||||
description=_(
|
||||
u"help_moderator_notification_enabled",
|
||||
default=u"If selected, the moderator is notified if a comment "
|
||||
u"needs attention. The moderator email address can " +
|
||||
u"be set below."),
|
||||
u'help_moderator_notification_enabled',
|
||||
default=u'If selected, the moderator is notified if a comment '
|
||||
u'needs attention. The moderator email address can '
|
||||
u'be set below.'),
|
||||
required=False,
|
||||
default=False,
|
||||
)
|
||||
@ -337,20 +336,20 @@ class IDiscussionSettings(Interface):
|
||||
),
|
||||
description=_(
|
||||
u'help_moderator_email',
|
||||
default=u"Address to which moderator notifications "
|
||||
u"will be sent."),
|
||||
default=u'Address to which moderator notifications '
|
||||
u'will be sent.'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
user_notification_enabled = schema.Bool(
|
||||
title=_(
|
||||
u"label_user_notification_enabled",
|
||||
default=u"Enable user email notification"
|
||||
u'label_user_notification_enabled',
|
||||
default=u'Enable user email notification'
|
||||
),
|
||||
description=_(
|
||||
u"help_user_notification_enabled",
|
||||
default=u"If selected, users can choose to be notified "
|
||||
u"of new comments by email."),
|
||||
u'help_user_notification_enabled',
|
||||
default=u'If selected, users can choose to be notified '
|
||||
u'of new comments by email.'),
|
||||
required=False,
|
||||
default=False
|
||||
)
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
# -*- coding: utf-8 -*-
|
||||
from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FIXTURE
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
from plone.app.robotframework.testing import REMOTE_LIBRARY_ROBOT_TESTING
|
||||
@ -9,14 +9,16 @@ from plone.app.testing import PloneSandboxLayer
|
||||
from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from zope.component import queryUtility
|
||||
from zope.configuration import xmlconfig
|
||||
|
||||
|
||||
try:
|
||||
import plone.app.collection # noqa
|
||||
COLLECTION_TYPE = "Collection"
|
||||
except:
|
||||
COLLECTION_TYPE = "Topic"
|
||||
COLLECTION_TYPE = 'Collection'
|
||||
except ImportError:
|
||||
COLLECTION_TYPE = 'Topic'
|
||||
|
||||
|
||||
class PloneAppDiscussion(PloneSandboxLayer):
|
||||
@ -77,7 +79,7 @@ class PloneAppDiscussion(PloneSandboxLayer):
|
||||
gtool.addPrincipalToGroup(self.REVIEWER_NAME, 'Reviewers')
|
||||
mtool.addMember('jim', 'Jim', ['Member'], [])
|
||||
mtool.getMemberById('jim').setMemberProperties(
|
||||
{"fullname": 'Jim Fult\xc3\xb8rn'})
|
||||
{'fullname': 'Jim Fult\xc3\xb8rn'})
|
||||
|
||||
acl_users.userFolderAddUser(
|
||||
self.MANAGER_USER_NAME,
|
||||
@ -107,14 +109,14 @@ PLONE_APP_DISCUSSION_ROBOT_FIXTURE = PloneAppDiscussionRobot()
|
||||
PLONE_APP_DISCUSSION_FIXTURE = PloneAppDiscussion()
|
||||
PLONE_APP_DISCUSSION_INTEGRATION_TESTING = IntegrationTesting(
|
||||
bases=(PLONE_APP_DISCUSSION_FIXTURE,),
|
||||
name="PloneAppDiscussion:Integration")
|
||||
name='PloneAppDiscussion:Integration')
|
||||
PLONE_APP_DISCUSSION_FUNCTIONAL_TESTING = FunctionalTesting(
|
||||
bases=(PLONE_APP_DISCUSSION_FIXTURE,),
|
||||
name="PloneAppDiscussion:Functional")
|
||||
name='PloneAppDiscussion:Functional')
|
||||
PLONE_APP_DISCUSSION_ROBOT_TESTING = FunctionalTesting(
|
||||
bases=(
|
||||
PLONE_APP_DISCUSSION_ROBOT_FIXTURE,
|
||||
REMOTE_LIBRARY_ROBOT_TESTING
|
||||
),
|
||||
name="PloneAppDiscussion:Robot"
|
||||
name='PloneAppDiscussion:Robot'
|
||||
)
|
||||
|
@ -1,11 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Test the plone.app.discussion catalog indexes
|
||||
"""
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from datetime import datetime
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
from zope.component import createObject
|
||||
|
||||
@ -74,7 +75,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
self.conversation = conversation
|
||||
self.brains = brains
|
||||
@ -92,14 +93,15 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
new_comment2_id = self.conversation.addComment(comment2)
|
||||
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_comment2_id)
|
||||
'++conversation++default/{0}'.format(new_comment2_id)
|
||||
)
|
||||
comment2.reindexObject()
|
||||
brains = self.catalog.searchResults(dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.total_comments, 2)
|
||||
@ -120,14 +122,15 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
new_comment2_id = self.conversation.addComment(comment2)
|
||||
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_comment2_id)
|
||||
'++conversation++default/{0}'.format(new_comment2_id)
|
||||
)
|
||||
comment2.reindexObject()
|
||||
brains = self.catalog.searchResults(dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(
|
||||
@ -143,7 +146,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(
|
||||
@ -158,7 +161,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.last_comment_date, None)
|
||||
@ -176,7 +179,8 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
new_comment2_id = self.conversation.addComment(comment2)
|
||||
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_comment2_id)
|
||||
'++conversation++default/{0}'.format(new_comment2_id)
|
||||
)
|
||||
comment2.reindexObject()
|
||||
|
||||
brains = self.catalog.searchResults(dict(
|
||||
@ -184,7 +188,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
|
||||
@ -197,7 +201,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.commentators, ('Jim',))
|
||||
@ -209,7 +213,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.commentators, ())
|
||||
@ -220,7 +224,7 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Discussion Item"
|
||||
portal_type='Discussion Item'
|
||||
))
|
||||
comment1_brain = brains[0]
|
||||
self.assertEqual(comment1_brain.commentators, None)
|
||||
@ -228,14 +232,14 @@ class ConversationCatalogTest(unittest.TestCase):
|
||||
self.assertEqual(comment1_brain.total_comments, None)
|
||||
|
||||
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()
|
||||
brains = self.catalog.searchResults(dict(
|
||||
path={
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
doc1_brain = brains[0]
|
||||
self.assertEqual(doc1_brain.commentators, ())
|
||||
@ -262,7 +266,8 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
|
||||
# Comment brain
|
||||
self.comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_comment1_id)
|
||||
'++conversation++default/{0}'.format(new_comment1_id)
|
||||
)
|
||||
brains = self.catalog.searchResults(dict(
|
||||
path={
|
||||
'query':
|
||||
@ -281,7 +286,8 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
|
||||
# Comment brain
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % cid)
|
||||
'++conversation++default/{0}'.format(cid)
|
||||
)
|
||||
brains = self.catalog.searchResults(dict(
|
||||
path={
|
||||
'query':
|
||||
@ -289,7 +295,7 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
}
|
||||
))
|
||||
comment_brain = brains[0]
|
||||
self.assertEqual(comment_brain.Title, "Anonymous on Document 1")
|
||||
self.assertEqual(comment_brain.Title, 'Anonymous on Document 1')
|
||||
|
||||
def test_type(self):
|
||||
self.assertEqual(self.comment_brain.portal_type, 'Discussion Item')
|
||||
@ -329,7 +335,7 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
"""
|
||||
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
|
||||
self.assertEqual(len(brains), 1)
|
||||
self.portal.manage_delObjects(["doc1"])
|
||||
self.portal.manage_delObjects(['doc1'])
|
||||
brains = self.catalog.searchResults({'portal_type': 'Discussion Item'})
|
||||
self.assertEqual(len(brains), 0)
|
||||
|
||||
@ -362,13 +368,13 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
|
||||
# Make sure no old comment brains are
|
||||
brains = self.catalog.searchResults(dict(
|
||||
portal_type="Discussion Item",
|
||||
portal_type='Discussion Item',
|
||||
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={
|
||||
'query': '/'.join(self.portal.folder2.getPhysicalPath())
|
||||
}
|
||||
@ -411,14 +417,14 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
|
||||
# Make sure no old comment brains are left
|
||||
brains = self.catalog.searchResults(dict(
|
||||
portal_type="Discussion Item",
|
||||
portal_type='Discussion Item',
|
||||
path={'query': '/plone/sourcefolder/moveme'}
|
||||
))
|
||||
self.assertEqual(len(brains), 0)
|
||||
|
||||
# make sure comments are correctly index on the target
|
||||
brains = self.catalog.searchResults(dict(
|
||||
portal_type="Discussion Item",
|
||||
portal_type='Discussion Item',
|
||||
path={'query': '/plone/targetfolder/moveme'}
|
||||
))
|
||||
self.assertEqual(len(brains), 1)
|
||||
@ -432,7 +438,7 @@ class CommentCatalogTest(unittest.TestCase):
|
||||
# We need to commit here so that _p_jar isn't None and move will work
|
||||
transaction.savepoint(optimistic=True)
|
||||
|
||||
self.portal.manage_renameObject("doc1", "doc2")
|
||||
self.portal.manage_renameObject('doc1', 'doc2')
|
||||
|
||||
brains = self.catalog.searchResults(
|
||||
portal_type='Discussion Item')
|
||||
@ -535,7 +541,7 @@ class NoConversationCatalogTest(unittest.TestCase):
|
||||
'query':
|
||||
'/'.join(self.portal.doc1.getPhysicalPath())
|
||||
},
|
||||
portal_type="Document"
|
||||
portal_type='Document'
|
||||
))
|
||||
self.conversation = conversation
|
||||
self.brains = brains
|
||||
|
@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from plone.app.discussion.browser.comment import View
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
@ -7,6 +6,7 @@ from plone.app.discussion.interfaces import IReplies
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from zope.component import createObject
|
||||
from zope.component import getMultiAdapter
|
||||
|
||||
@ -41,9 +41,9 @@ class CommentTest(unittest.TestCase):
|
||||
datetime.datetime.now() - datetime.datetime.utcnow()
|
||||
utc_to_local_diff = abs(utc_to_local_diff.seconds)
|
||||
if utc_to_local_diff < 60:
|
||||
logger.warning("Your computer is living in a timezone where local "
|
||||
"time equals utc time. Some potential errors can "
|
||||
"get hidden by that")
|
||||
logger.warning('Your computer is living in a timezone where local '
|
||||
'time equals utc time. Some potential errors can '
|
||||
'get hidden by that')
|
||||
comment1 = createObject('plone.Comment')
|
||||
local_utc = datetime.datetime.utcnow()
|
||||
for date in (comment1.creation_date, comment1.modification_date):
|
||||
@ -92,15 +92,15 @@ class CommentTest(unittest.TestCase):
|
||||
def test_title(self):
|
||||
conversation = IConversation(self.portal.doc1)
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.author_name = "Jim Fulton"
|
||||
comment1.author_name = 'Jim Fulton'
|
||||
conversation.addComment(comment1)
|
||||
self.assertEqual("Jim Fulton on Document 1", comment1.Title())
|
||||
self.assertEqual('Jim Fulton on Document 1', comment1.Title())
|
||||
|
||||
def test_no_name_title(self):
|
||||
conversation = IConversation(self.portal.doc1)
|
||||
comment1 = createObject('plone.Comment')
|
||||
conversation.addComment(comment1)
|
||||
self.assertEqual("Anonymous on Document 1", comment1.Title())
|
||||
self.assertEqual('Anonymous on Document 1', comment1.Title())
|
||||
|
||||
def test_title_special_characters(self):
|
||||
self.portal.invokeFactory(
|
||||
@ -110,9 +110,9 @@ class CommentTest(unittest.TestCase):
|
||||
)
|
||||
conversation = IConversation(self.portal.doc_sp_chars)
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.author_name = u"Tarek Ziadé"
|
||||
comment1.author_name = u'Tarek Ziadé'
|
||||
conversation.addComment(comment1)
|
||||
self.assertEqual(u"Tarek Ziadé on Document äüö", comment1.Title())
|
||||
self.assertEqual(u'Tarek Ziadé on Document äüö', comment1.Title())
|
||||
|
||||
def test_title_special_characters_utf8(self):
|
||||
self.portal.invokeFactory(
|
||||
@ -122,19 +122,19 @@ class CommentTest(unittest.TestCase):
|
||||
)
|
||||
conversation = IConversation(self.portal.doc_sp_chars_utf8)
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.author_name = "Hüüb Bôûmä"
|
||||
comment1.author_name = 'Hüüb Bôûmä'
|
||||
conversation.addComment(comment1)
|
||||
self.assertEqual(u"Hüüb Bôûmä on Document ëïû", comment1.Title())
|
||||
self.assertEqual(u'Hüüb Bôûmä on Document ëïû', comment1.Title())
|
||||
|
||||
def test_creator(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.creator = "jim"
|
||||
self.assertEqual("jim", comment1.Creator())
|
||||
comment1.creator = 'jim'
|
||||
self.assertEqual('jim', comment1.Creator())
|
||||
|
||||
def test_creator_author_name(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.author_name = "joey"
|
||||
self.assertEqual("joey", comment1.Creator())
|
||||
comment1.author_name = 'joey'
|
||||
self.assertEqual('joey', comment1.Creator())
|
||||
|
||||
def test_owner(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
@ -151,25 +151,23 @@ class CommentTest(unittest.TestCase):
|
||||
|
||||
def test_getText(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = """First paragraph
|
||||
|
||||
Second paragraph"""
|
||||
comment1.text = 'First paragraph\n\nSecond paragraph'
|
||||
self.assertEqual(
|
||||
comment1.getText(),
|
||||
"<p>First paragraph<br /><br /> Second paragraph</p>"
|
||||
'<p>First paragraph<br /><br />Second paragraph</p>'
|
||||
)
|
||||
|
||||
def test_getText_escapes_HTML(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = """<b>Got HTML?</b>"""
|
||||
comment1.text = '<b>Got HTML?</b>'
|
||||
self.assertEqual(
|
||||
comment1.getText(),
|
||||
"<p><b>Got HTML?</b></p>"
|
||||
'<p><b>Got HTML?</b></p>'
|
||||
)
|
||||
|
||||
def test_getText_with_non_ascii_characters(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = u"""Umlaute sind ä, ö und ü."""
|
||||
comment1.text = u'Umlaute sind ä, ö und ü.'
|
||||
self.assertEqual(
|
||||
comment1.getText(),
|
||||
'<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>'
|
||||
@ -177,15 +175,15 @@ class CommentTest(unittest.TestCase):
|
||||
|
||||
def test_getText_doesnt_link(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = "Go to http://www.plone.org"
|
||||
comment1.text = 'Go to http://www.plone.org'
|
||||
self.assertEqual(
|
||||
comment1.getText(),
|
||||
"<p>Go to http://www.plone.org</p>"
|
||||
'<p>Go to http://www.plone.org</p>'
|
||||
)
|
||||
|
||||
def test_getText_uses_comment_mime_type(self):
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = "Go to http://www.plone.org"
|
||||
comment1.text = 'Go to http://www.plone.org'
|
||||
comment1.mime_type = 'text/x-web-intelligent'
|
||||
self.assertEqual(
|
||||
comment1.getText(),
|
||||
@ -229,7 +227,8 @@ class CommentTest(unittest.TestCase):
|
||||
new_comment1_id = conversation.addComment(comment1)
|
||||
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_comment1_id)
|
||||
'++conversation++default/{0}'.format(new_comment1_id)
|
||||
)
|
||||
self.assertTrue(IComment.providedBy(comment))
|
||||
|
||||
self.assertEqual(
|
||||
@ -260,12 +259,13 @@ class CommentTest(unittest.TestCase):
|
||||
comment1.text = 'Comment text'
|
||||
new_comment1_id = conversation.addComment(comment1)
|
||||
comment = self.portal.image1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_comment1_id)
|
||||
'++conversation++default/{0}'.format(new_comment1_id)
|
||||
)
|
||||
|
||||
view = View(comment, self.request)
|
||||
View.__call__(view)
|
||||
response = self.request.response
|
||||
self.assertIn("/view", response.headers['location'])
|
||||
self.assertIn('/view', response.headers['location'])
|
||||
|
||||
def test_workflow(self):
|
||||
"""Basic test for the 'comment_review_workflow'
|
||||
@ -301,8 +301,8 @@ class CommentTest(unittest.TestCase):
|
||||
def test_fti(self):
|
||||
# test that we can look up an FTI for Discussion Item
|
||||
|
||||
self.assertTrue(
|
||||
"Discussion Item" in
|
||||
self.assertIn(
|
||||
'Discussion Item',
|
||||
self.portal.portal_types.objectIds()
|
||||
)
|
||||
|
||||
@ -327,7 +327,8 @@ class CommentTest(unittest.TestCase):
|
||||
new_comment1_id = conversation.addComment(comment1)
|
||||
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_comment1_id)
|
||||
'++conversation++default/{0}'.format(new_comment1_id)
|
||||
)
|
||||
|
||||
# make sure the view is there
|
||||
self.assertTrue(getMultiAdapter((comment, self.request),
|
||||
@ -364,7 +365,8 @@ class RepliesTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id)
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
)
|
||||
|
||||
# Add a reply to the CommentReplies adapter of the first comment
|
||||
re_comment = createObject('plone.Comment')
|
||||
@ -400,7 +402,8 @@ class RepliesTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id)
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
)
|
||||
|
||||
# Add a reply to the CommentReplies adapter of the first comment
|
||||
re_comment = createObject('plone.Comment')
|
||||
@ -435,7 +438,8 @@ class RepliesTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = conversation.addComment(comment)
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id)
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
)
|
||||
|
||||
# Add a reply to the CommentReplies adapter of the first comment
|
||||
re_comment = createObject('plone.Comment')
|
||||
@ -443,7 +447,7 @@ class RepliesTest(unittest.TestCase):
|
||||
replies = IReplies(comment)
|
||||
new_re_id = replies.addComment(re_comment)
|
||||
re_comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_re_id
|
||||
'++conversation++default/{0}'.format(new_re_id)
|
||||
)
|
||||
|
||||
# Add a reply to the reply
|
||||
@ -452,7 +456,7 @@ class RepliesTest(unittest.TestCase):
|
||||
replies = IReplies(re_comment)
|
||||
new_re_re_id = replies.addComment(re_re_comment)
|
||||
re_re_comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_re_re_id
|
||||
'++conversation++default/{0}'.format(new_re_re_id)
|
||||
)
|
||||
|
||||
# Add a reply to the replies reply
|
||||
@ -461,7 +465,8 @@ class RepliesTest(unittest.TestCase):
|
||||
replies = IReplies(re_re_comment)
|
||||
new_re_re_re_id = replies.addComment(re_re_re_comment)
|
||||
re_re_re_comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_re_re_re_id)
|
||||
'++conversation++default/{0}'.format(new_re_re_re_id)
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
('', 'plone', 'doc1', '++conversation++default', str(new_id)),
|
||||
|
@ -2,8 +2,6 @@
|
||||
from AccessControl import Unauthorized
|
||||
from datetime import datetime
|
||||
from OFS.Image import Image
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.tests import dummy
|
||||
from plone.app.discussion import interfaces
|
||||
from plone.app.discussion.browser.comment import EditCommentForm
|
||||
from plone.app.discussion.browser.comments import CommentForm
|
||||
@ -17,6 +15,8 @@ from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from plone.app.testing import TEST_USER_NAME
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.tests import dummy
|
||||
from z3c.form.interfaces import IFormLayer
|
||||
from zope import interface
|
||||
from zope.annotation.interfaces import IAttributeAnnotatable
|
||||
@ -49,7 +49,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
interfaces.IDiscussionLayer,
|
||||
)
|
||||
|
||||
wftool = getToolByName(self.portal, "portal_workflow")
|
||||
wftool = getToolByName(self.portal, 'portal_workflow')
|
||||
wftool.doActionFor(self.portal.doc1, action='publish')
|
||||
self.portal.doc1.allow_discussion = True
|
||||
self.membershipTool = getToolByName(self.folder, 'portal_membership')
|
||||
@ -80,7 +80,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
|
||||
# The form should return an error if the comment text field is empty
|
||||
@ -88,13 +88,13 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
|
||||
self.assertEqual(len(errors), 1)
|
||||
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
|
||||
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
|
||||
|
||||
# The form is submitted successfully, if the required text field is
|
||||
# filled out
|
||||
@ -102,22 +102,22 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
|
||||
self.assertEqual(len(errors), 0)
|
||||
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
|
||||
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
|
||||
|
||||
comments = IConversation(commentForm.context).getComments()
|
||||
comments = [comment for comment in comments] # consume iterator
|
||||
self.assertEqual(len(comments), 1)
|
||||
|
||||
for comment in comments:
|
||||
self.assertEqual(comment.text, u"bar")
|
||||
self.assertEqual(comment.creator, "test_user_1_")
|
||||
self.assertEqual(comment.getOwner().getUserName(), "test-user")
|
||||
self.assertEqual(comment.text, u'bar')
|
||||
self.assertEqual(comment.creator, 'test_user_1_')
|
||||
self.assertEqual(comment.getOwner().getUserName(), 'test-user')
|
||||
local_roles = comment.get_local_roles()
|
||||
self.assertEqual(len(local_roles), 1)
|
||||
userid, roles = local_roles[0]
|
||||
@ -144,14 +144,14 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
|
||||
provideAdapter(
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=EditCommentForm,
|
||||
name=u"edit-comment-form"
|
||||
name=u'edit-comment-form'
|
||||
)
|
||||
|
||||
# The form is submitted successfully, if the required text field is
|
||||
@ -160,13 +160,13 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
|
||||
self.assertEqual(len(errors), 0)
|
||||
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
|
||||
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
|
||||
|
||||
# Edit the last comment
|
||||
conversation = IConversation(self.context)
|
||||
@ -174,25 +174,25 @@ class TestCommentForm(unittest.TestCase):
|
||||
request = make_request(form={'form.widgets.text': u'foobar'})
|
||||
editForm = getMultiAdapter(
|
||||
(comment, request),
|
||||
name=u"edit-comment-form"
|
||||
name=u'edit-comment-form'
|
||||
)
|
||||
editForm.update()
|
||||
data, errors = editForm.extractData() # pylint: disable-msg=W0612
|
||||
|
||||
self.assertEqual(len(errors), 0)
|
||||
self.assertFalse(editForm.handleComment(editForm, "foo"))
|
||||
self.assertFalse(editForm.handleComment(editForm, 'foo'))
|
||||
comment = [x for x in conversation.getComments()][-1]
|
||||
self.assertEquals(comment.text, u"foobar")
|
||||
self.assertEqual(comment.text, u'foobar')
|
||||
|
||||
comments = IConversation(commentForm.context).getComments()
|
||||
comments = [c for c in comments] # consume iterator
|
||||
self.assertEqual(len(comments), 1)
|
||||
|
||||
for comment in comments:
|
||||
self.assertEqual(comment.text, u"foobar")
|
||||
self.assertEqual(comment.creator, "test_user_1_")
|
||||
self.assertEqual(comment.text, u'foobar')
|
||||
self.assertEqual(comment.creator, 'test_user_1_')
|
||||
|
||||
self.assertEqual(comment.getOwner().getUserName(), "test-user")
|
||||
self.assertEqual(comment.getOwner().getUserName(), 'test-user')
|
||||
local_roles = comment.get_local_roles()
|
||||
self.assertEqual(len(local_roles), 1)
|
||||
userid, roles = local_roles[0]
|
||||
@ -219,7 +219,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
|
||||
# The form is submitted successfully, if the required text field is
|
||||
@ -228,31 +228,31 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, form_request),
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
self.assertEqual(len(errors), 0)
|
||||
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
|
||||
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
|
||||
|
||||
# Delete the last comment
|
||||
conversation = IConversation(self.context)
|
||||
comment = [x for x in conversation.getComments()][-1]
|
||||
deleteView = getMultiAdapter(
|
||||
(comment, self.request),
|
||||
name=u"moderate-delete-comment"
|
||||
name=u'moderate-delete-comment'
|
||||
)
|
||||
# try to delete last comment without "Delete comments" permission
|
||||
# try to delete last comment without 'Delete comments' permission
|
||||
setRoles(self.portal, TEST_USER_ID, ['Member'])
|
||||
self.assertRaises(
|
||||
Unauthorized,
|
||||
comment.restrictedTraverse,
|
||||
"@@moderate-delete-comment"
|
||||
'@@moderate-delete-comment'
|
||||
)
|
||||
deleteView()
|
||||
self.assertEqual(1, len([x for x in conversation.getComments()]))
|
||||
# try to delete last comment with "Delete comments" permission
|
||||
# try to delete last comment with 'Delete comments' permission
|
||||
setRoles(self.portal, TEST_USER_ID, ['Reviewer'])
|
||||
deleteView()
|
||||
self.assertEqual(0, len([x for x in conversation.getComments()]))
|
||||
@ -277,7 +277,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
|
||||
# The form is submitted successfully, if the required text field is
|
||||
@ -286,20 +286,20 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, form_request),
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
self.assertEqual(len(errors), 0)
|
||||
self.assertFalse(commentForm.handleComment(commentForm, "foo"))
|
||||
self.assertFalse(commentForm.handleComment(commentForm, 'foo'))
|
||||
|
||||
# Delete the last comment
|
||||
conversation = IConversation(self.context)
|
||||
comment = [x for x in conversation.getComments()][-1]
|
||||
deleteView = getMultiAdapter(
|
||||
(comment, self.request),
|
||||
name=u"delete-own-comment"
|
||||
name=u'delete-own-comment'
|
||||
)
|
||||
# try to delete last comment with johndoe
|
||||
setRoles(self.portal, 'johndoe', ['Member'])
|
||||
@ -307,7 +307,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
self.assertRaises(
|
||||
Unauthorized,
|
||||
comment.restrictedTraverse,
|
||||
"@@delete-own-comment"
|
||||
'@@delete-own-comment'
|
||||
)
|
||||
self.assertEqual(1, len([x for x in conversation.getComments()]))
|
||||
# try to delete last comment with the same user that created it
|
||||
@ -338,7 +338,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
provideAdapter(adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u"comment-form")
|
||||
name=u'comment-form')
|
||||
|
||||
# Post an anonymous comment and provide a name
|
||||
request = make_request(form={
|
||||
@ -348,20 +348,20 @@ class TestCommentForm(unittest.TestCase):
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
|
||||
self.assertEqual(len(errors), 0)
|
||||
self.assertFalse(commentForm.handleComment(commentForm, "action"))
|
||||
self.assertFalse(commentForm.handleComment(commentForm, 'action'))
|
||||
|
||||
comments = IConversation(commentForm.context).getComments()
|
||||
comments = [comment for comment in comments] # consume itertor
|
||||
self.assertEqual(len(comments), 1)
|
||||
|
||||
for comment in IConversation(commentForm.context).getComments():
|
||||
self.assertEqual(comment.text, u"bar")
|
||||
self.assertEqual(comment.text, u'bar')
|
||||
self.assertIsNone(comment.creator)
|
||||
roles = comment.get_local_roles()
|
||||
self.assertEqual(len(roles), 0)
|
||||
@ -385,13 +385,13 @@ class TestCommentForm(unittest.TestCase):
|
||||
provideAdapter(adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u"comment-form")
|
||||
name=u'comment-form')
|
||||
|
||||
request = make_request(form={'form.widgets.text': u'bar'})
|
||||
|
||||
commentForm = getMultiAdapter(
|
||||
(self.context, request),
|
||||
name=u"comment-form"
|
||||
name=u'comment-form'
|
||||
)
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
@ -403,7 +403,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
self.assertRaises(Unauthorized,
|
||||
commentForm.handleComment,
|
||||
commentForm,
|
||||
"foo")
|
||||
'foo')
|
||||
|
||||
def test_anonymous_can_not_add_comments_if_discussion_is_not_allowed(self):
|
||||
"""Make sure that anonymous users can't post comments if anonymous
|
||||
@ -424,12 +424,12 @@ class TestCommentForm(unittest.TestCase):
|
||||
provideAdapter(adapts=(Interface, IBrowserRequest),
|
||||
provides=Interface,
|
||||
factory=CommentForm,
|
||||
name=u"comment-form")
|
||||
name=u'comment-form')
|
||||
|
||||
request = make_request(form={'form.widgets.text': u'bar'})
|
||||
|
||||
commentForm = getMultiAdapter((self.context, request),
|
||||
name=u"comment-form")
|
||||
name=u'comment-form')
|
||||
commentForm.update()
|
||||
data, errors = commentForm.extractData() # pylint: disable-msg=W0612
|
||||
|
||||
@ -438,7 +438,7 @@ class TestCommentForm(unittest.TestCase):
|
||||
Unauthorized,
|
||||
commentForm.handleComment,
|
||||
commentForm,
|
||||
"foo"
|
||||
'foo'
|
||||
)
|
||||
|
||||
|
||||
@ -519,20 +519,20 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
self.assertTrue(self.viewlet.comment_transform_message())
|
||||
self.assertEqual(
|
||||
self.viewlet.comment_transform_message(),
|
||||
"You can add a comment by filling out the form below. Plain " +
|
||||
"text formatting.")
|
||||
'You can add a comment by filling out the form below. Plain ' +
|
||||
'text formatting.')
|
||||
|
||||
# Set text transform to intelligent text
|
||||
registry = queryUtility(IRegistry)
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
settings.text_transform = "text/x-web-intelligent"
|
||||
settings.text_transform = 'text/x-web-intelligent'
|
||||
|
||||
# Make sure the comment description changes accordingly
|
||||
self.assertEqual(
|
||||
self.viewlet.comment_transform_message(),
|
||||
"You can add a comment by filling out the form below. " +
|
||||
"Plain text formatting. Web and email addresses are transformed " +
|
||||
"into clickable links."
|
||||
'You can add a comment by filling out the form below. ' +
|
||||
'Plain text formatting. Web and email addresses are transformed ' +
|
||||
'into clickable links.'
|
||||
)
|
||||
|
||||
# Enable moderation workflow
|
||||
@ -543,9 +543,9 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
# Make sure the comment description shows that comments are moderated
|
||||
self.assertEqual(
|
||||
self.viewlet.comment_transform_message(),
|
||||
"You can add a comment by filling out the form below. " +
|
||||
"Plain text formatting. Web and email addresses are transformed " +
|
||||
"into clickable links. Comments are moderated.")
|
||||
'You can add a comment by filling out the form below. ' +
|
||||
'Plain text formatting. Web and email addresses are transformed ' +
|
||||
'into clickable links. Comments are moderated.')
|
||||
|
||||
def test_has_replies(self):
|
||||
self.assertEqual(self.viewlet.has_replies(), False)
|
||||
@ -599,10 +599,11 @@ class TestCommentsViewlet(unittest.TestCase):
|
||||
reply['actions'][0]['id'],
|
||||
'publish'
|
||||
)
|
||||
expected_url = 'http://nohost/plone/doc1/++conversation++default/{0}' \
|
||||
'/content_status_modify?workflow_action=publish'
|
||||
self.assertEqual(
|
||||
reply['actions'][0]['url'],
|
||||
'http://nohost/plone/doc1/++conversation++default/%s' % int(c1) +
|
||||
'/content_status_modify?workflow_action=publish'
|
||||
expected_url.format(int(c1))
|
||||
)
|
||||
|
||||
def test_get_commenter_home_url(self):
|
||||
|
@ -1,7 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from plone.app.discussion.interfaces import ICommentAddedEvent
|
||||
from plone.app.discussion.interfaces import ICommentRemovedEvent
|
||||
from plone.app.discussion.interfaces import IConversation, IReplies
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
from plone.app.discussion.interfaces import IReplyAddedEvent
|
||||
from plone.app.discussion.interfaces import IReplyRemovedEvent
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
@ -37,10 +38,10 @@ class CommentContentRulesTest(unittest.TestCase):
|
||||
self.document = self.portal['doc1']
|
||||
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = "This is a comment"
|
||||
comment.author_username = "jim"
|
||||
comment.author_name = "Jim"
|
||||
comment.author_email = "jim@example.com"
|
||||
comment.text = 'This is a comment'
|
||||
comment.author_username = 'jim'
|
||||
comment.author_name = 'Jim'
|
||||
comment.author_email = 'jim@example.com'
|
||||
conversation = IConversation(self.document)
|
||||
conversation.addComment(comment)
|
||||
|
||||
@ -52,28 +53,28 @@ class CommentContentRulesTest(unittest.TestCase):
|
||||
|
||||
def testCommentIdStringSubstitution(self):
|
||||
comment_id = getAdapter(self.document, IStringSubstitution,
|
||||
name=u"comment_id")
|
||||
name=u'comment_id')
|
||||
self.assertIsInstance(comment_id(), long)
|
||||
|
||||
def testCommentTextStringSubstitution(self):
|
||||
comment_text = getAdapter(self.document, IStringSubstitution,
|
||||
name=u"comment_text")
|
||||
self.assertEqual(comment_text(), u"This is a comment")
|
||||
name=u'comment_text')
|
||||
self.assertEqual(comment_text(), u'This is a comment')
|
||||
|
||||
def testCommentUserIdStringSubstitution(self):
|
||||
comment_user_id = getAdapter(self.document, IStringSubstitution,
|
||||
name=u"comment_user_id")
|
||||
self.assertEqual(comment_user_id(), u"jim")
|
||||
name=u'comment_user_id')
|
||||
self.assertEqual(comment_user_id(), u'jim')
|
||||
|
||||
def testCommentUserFullNameStringSubstitution(self):
|
||||
comment_user_fullname = getAdapter(self.document, IStringSubstitution,
|
||||
name=u"comment_user_fullname")
|
||||
self.assertEqual(comment_user_fullname(), u"Jim")
|
||||
name=u'comment_user_fullname')
|
||||
self.assertEqual(comment_user_fullname(), u'Jim')
|
||||
|
||||
def testCommentUserEmailStringSubstitution(self):
|
||||
comment_user_email = getAdapter(self.document, IStringSubstitution,
|
||||
name=u"comment_user_email")
|
||||
self.assertEqual(comment_user_email(), u"jim@example.com")
|
||||
name=u'comment_user_email')
|
||||
self.assertEqual(comment_user_email(), u'jim@example.com')
|
||||
|
||||
|
||||
class ReplyContentRulesTest(unittest.TestCase):
|
||||
@ -95,13 +96,14 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
comment.text = 'This is a comment'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.document.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id)
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
)
|
||||
|
||||
re_comment = createObject('plone.Comment')
|
||||
re_comment.text = 'This is a reply'
|
||||
re_comment.author_username = "julia"
|
||||
re_comment.author_name = "Juliana"
|
||||
re_comment.author_email = "julia@example.com"
|
||||
re_comment.author_username = 'julia'
|
||||
re_comment.author_name = 'Juliana'
|
||||
re_comment.author_email = 'julia@example.com'
|
||||
|
||||
replies = IReplies(comment)
|
||||
replies.addComment(re_comment)
|
||||
@ -110,7 +112,7 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
reply_id = getAdapter(
|
||||
self.document,
|
||||
IStringSubstitution,
|
||||
name=u"comment_id"
|
||||
name=u'comment_id'
|
||||
)
|
||||
self.assertIsInstance(reply_id(), long)
|
||||
|
||||
@ -118,30 +120,30 @@ class ReplyContentRulesTest(unittest.TestCase):
|
||||
reply_text = getAdapter(
|
||||
self.document,
|
||||
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')
|
||||
|
||||
def testReplyUserIdStringSubstitution(self):
|
||||
reply_user_id = getAdapter(
|
||||
self.document,
|
||||
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')
|
||||
|
||||
def testReplyUserFullNameStringSubstitution(self):
|
||||
reply_user_fullname = getAdapter(
|
||||
self.document,
|
||||
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')
|
||||
|
||||
def testReplyUserEmailStringSubstitution(self):
|
||||
reply_user_email = getAdapter(
|
||||
self.document,
|
||||
IStringSubstitution,
|
||||
name=u"comment_user_email"
|
||||
name=u'comment_user_email'
|
||||
)
|
||||
self.assertEqual(reply_user_email(), u"julia@example.com")
|
||||
self.assertEqual(reply_user_email(), u'julia@example.com')
|
||||
|
@ -29,14 +29,14 @@ class RegistryTest(unittest.TestCase):
|
||||
def test_discussion_controlpanel_view(self):
|
||||
view = getMultiAdapter(
|
||||
(self.portal, self.portal.REQUEST),
|
||||
name="discussion-controlpanel"
|
||||
name='discussion-controlpanel'
|
||||
)
|
||||
view = view.__of__(self.portal)
|
||||
self.assertTrue(view())
|
||||
|
||||
def test_discussion_in_controlpanel(self):
|
||||
# Check if discussion is in the control panel
|
||||
self.controlpanel = getToolByName(self.portal, "portal_controlpanel")
|
||||
self.controlpanel = getToolByName(self.portal, 'portal_controlpanel')
|
||||
self.assertTrue(
|
||||
'discussion' in [
|
||||
a.getAction(self)['id']
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Acquisition import aq_base
|
||||
from Acquisition import aq_parent
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from plone.app.discussion import interfaces
|
||||
@ -13,6 +13,7 @@ from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from plone.app.vocabularies.types import BAD_TYPES
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from zope import interface
|
||||
from zope.annotation.interfaces import IAnnotations
|
||||
from zope.component import createObject
|
||||
@ -24,7 +25,7 @@ import unittest2 as unittest
|
||||
try:
|
||||
from plone.dexterity.interfaces import IDexterityContent
|
||||
DEXTERITY = True
|
||||
except:
|
||||
except ImportError:
|
||||
DEXTERITY = False
|
||||
|
||||
|
||||
@ -82,12 +83,12 @@ class ConversationTest(unittest.TestCase):
|
||||
conversation = IConversation(self.portal.doc1)
|
||||
|
||||
comment = createObject('plone.Comment')
|
||||
comment.author_username = "nobody"
|
||||
comment.author_username = 'nobody'
|
||||
conversation.addComment(comment)
|
||||
comment.manage_permission("View", roles=tuple())
|
||||
comment.manage_permission('View', roles=tuple())
|
||||
self.assertEqual(0, conversation.total_comments())
|
||||
self.assertEqual(None, conversation.last_comment_date)
|
||||
self.assertEqual(["nobody"], list(conversation.commentators))
|
||||
self.assertEqual(['nobody'], list(conversation.commentators))
|
||||
self.assertEqual([], list(conversation.public_commentators))
|
||||
|
||||
def test_delete_comment(self):
|
||||
@ -434,22 +435,22 @@ class ConversationTest(unittest.TestCase):
|
||||
# swapped in
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = 'Comment text'
|
||||
comment1.author_username = "Jim"
|
||||
comment1.author_username = 'Jim'
|
||||
conversation.addComment(comment1)
|
||||
|
||||
comment2 = createObject('plone.Comment')
|
||||
comment2.text = 'Comment text'
|
||||
comment2.author_username = "Joe"
|
||||
comment2.author_username = 'Joe'
|
||||
conversation.addComment(comment2)
|
||||
|
||||
comment3 = createObject('plone.Comment')
|
||||
comment3.text = 'Comment text'
|
||||
comment3.author_username = "Jack"
|
||||
comment3.author_username = 'Jack'
|
||||
new_comment3_id = conversation.addComment(comment3)
|
||||
|
||||
comment4 = createObject('plone.Comment')
|
||||
comment4.text = 'Comment text'
|
||||
comment4.author_username = "Jack"
|
||||
comment4.author_username = 'Jack'
|
||||
new_comment4_id = conversation.addComment(comment4)
|
||||
|
||||
# check if all commentators are in the commentators list
|
||||
@ -680,10 +681,10 @@ class ConversationEnabledForDexterityTypesTest(unittest.TestCase):
|
||||
)
|
||||
|
||||
if DEXTERITY:
|
||||
interface.alsoProvides(
|
||||
self.portal.doc1,
|
||||
IDexterityContent
|
||||
)
|
||||
interface.alsoProvides(
|
||||
self.portal.doc1,
|
||||
IDexterityContent
|
||||
)
|
||||
|
||||
def _makeOne(self, *args, **kw):
|
||||
return self.portal.doc1.restrictedTraverse('@@conversation_view')
|
||||
@ -839,16 +840,19 @@ class RepliesTest(unittest.TestCase):
|
||||
# Create the nested comment structure
|
||||
new_id_1 = replies.addComment(comment1)
|
||||
comment1 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id_1)
|
||||
'++conversation++default/{0}'.format(new_id_1)
|
||||
)
|
||||
replies_to_comment1 = IReplies(comment1)
|
||||
new_id_2 = replies.addComment(comment2)
|
||||
comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id_2)
|
||||
'++conversation++default/{0}'.format(new_id_2)
|
||||
)
|
||||
replies_to_comment2 = IReplies(comment2)
|
||||
|
||||
new_id_1_1 = replies_to_comment1.addComment(comment1_1)
|
||||
comment1_1 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id_1_1)
|
||||
'++conversation++default/{0}'.format(new_id_1_1)
|
||||
)
|
||||
replies_to_comment1_1 = IReplies(comment1_1)
|
||||
replies_to_comment1_1.addComment(comment1_1_1)
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Zope2.App import zcml
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from zope.component import createObject
|
||||
from Zope2.App import zcml
|
||||
|
||||
import Products.Five
|
||||
import unittest2 as unittest
|
||||
@ -86,7 +86,7 @@ class CommentEventsTest(unittest.TestCase):
|
||||
|
||||
</configure>
|
||||
"""
|
||||
zcml.load_config("configure.zcml", Products.Five)
|
||||
zcml.load_config('configure.zcml', Products.Five)
|
||||
zcml.load_string(configure)
|
||||
|
||||
def test_addEvent(self):
|
||||
@ -139,7 +139,7 @@ class RepliesEventsTest(unittest.TestCase):
|
||||
|
||||
</configure>
|
||||
"""
|
||||
zcml.load_config("configure.zcml", Products.Five)
|
||||
zcml.load_config('configure.zcml', Products.Five)
|
||||
zcml.load_string(configure)
|
||||
|
||||
def test_addEvent(self):
|
||||
@ -152,7 +152,8 @@ class RepliesEventsTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.document.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id)
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
)
|
||||
|
||||
re_comment = createObject('plone.Comment')
|
||||
re_comment.text = 'Comment text'
|
||||
@ -172,7 +173,8 @@ class RepliesEventsTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
new_id = replies.addComment(comment)
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id)
|
||||
'++conversation++default/{0}'.format(new_id)
|
||||
)
|
||||
|
||||
re_comment = createObject('plone.Comment')
|
||||
re_comment.text = 'Comment text'
|
||||
|
@ -1,7 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Test for the plone.app.discussion indexers
|
||||
"""
|
||||
from DateTime import DateTime
|
||||
from datetime import datetime
|
||||
from DateTime import DateTime
|
||||
from plone.app.discussion import catalog
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
@ -39,24 +40,24 @@ class ConversationIndexersTest(unittest.TestCase):
|
||||
|
||||
comment1 = createObject('plone.Comment')
|
||||
comment1.text = 'Comment Text'
|
||||
comment1.creator = "jim"
|
||||
comment1.author_username = "Jim"
|
||||
comment1.creator = 'jim'
|
||||
comment1.author_username = 'Jim'
|
||||
comment1.creation_date = datetime(2006, 9, 17, 14, 18, 12)
|
||||
comment1.modification_date = datetime(2006, 9, 17, 14, 18, 12)
|
||||
self.new_id1 = conversation.addComment(comment1)
|
||||
|
||||
comment2 = createObject('plone.Comment')
|
||||
comment2.text = 'Comment Text'
|
||||
comment2.creator = "emma"
|
||||
comment2.author_username = "Emma"
|
||||
comment2.creator = 'emma'
|
||||
comment2.author_username = 'Emma'
|
||||
comment2.creation_date = datetime(2007, 12, 13, 4, 18, 12)
|
||||
comment2.modification_date = datetime(2007, 12, 13, 4, 18, 12)
|
||||
self.new_id2 = conversation.addComment(comment2)
|
||||
|
||||
comment3 = createObject('plone.Comment')
|
||||
comment3.text = 'Comment Text'
|
||||
comment3.creator = "lukas"
|
||||
comment3.author_username = "Lukas"
|
||||
comment3.creator = 'lukas'
|
||||
comment3.author_username = 'Lukas'
|
||||
comment3.creation_date = datetime(2009, 4, 12, 11, 12, 12)
|
||||
comment3.modification_date = datetime(2009, 4, 12, 11, 12, 12)
|
||||
self.new_id3 = conversation.addComment(comment3)
|
||||
@ -118,8 +119,8 @@ class CommentIndexersTest(unittest.TestCase):
|
||||
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Lorem ipsum dolor sit amet.'
|
||||
comment.creator = "jim"
|
||||
comment.author_name = "Jim"
|
||||
comment.creator = 'jim'
|
||||
comment.author_name = 'Jim'
|
||||
comment.creation_date = datetime(2006, 9, 17, 14, 18, 12)
|
||||
comment.modification_date = datetime(2008, 3, 12, 7, 32, 52)
|
||||
|
||||
@ -149,7 +150,7 @@ class CommentIndexersTest(unittest.TestCase):
|
||||
self.conversation.addComment(comment_long)
|
||||
self.assertEqual(
|
||||
catalog.description(comment_long)(),
|
||||
LONG_TEXT_CUT.replace("\n", " ")
|
||||
LONG_TEXT_CUT.replace('\n', ' ')
|
||||
)
|
||||
|
||||
def test_dates(self):
|
||||
|
@ -1,11 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from plone.app.discussion.browser.moderation import BulkActionsView
|
||||
from plone.app.discussion.browser.moderation import View
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from zope.component import createObject
|
||||
|
||||
import unittest
|
||||
@ -75,7 +75,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
comment1.Creator = 'Jim'
|
||||
new_id_1 = conversation.addComment(comment1)
|
||||
self.comment1 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id_1
|
||||
'++conversation++default/{0}'.format(new_id_1)
|
||||
)
|
||||
comment2 = createObject('plone.Comment')
|
||||
comment2.title = 'Comment 2'
|
||||
@ -83,7 +83,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
comment2.Creator = 'Joe'
|
||||
new_id_2 = conversation.addComment(comment2)
|
||||
self.comment2 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id_2
|
||||
'++conversation++default/{0}'.format(new_id_2)
|
||||
)
|
||||
comment3 = createObject('plone.Comment')
|
||||
comment3.title = 'Comment 3'
|
||||
@ -91,7 +91,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
|
||||
comment3.Creator = 'Emma'
|
||||
new_id_3 = conversation.addComment(comment3)
|
||||
self.comment3 = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % new_id_3
|
||||
'++conversation++default/{0}'.format(new_id_3)
|
||||
)
|
||||
self.conversation = conversation
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Acquisition import aq_base
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFPlone.interfaces import IMailSchema
|
||||
from Products.CMFPlone.tests.utils import MockMailHost
|
||||
from Products.MailHost.interfaces import IMailHost
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from plone.app.testing import setRoles
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from zope.component import createObject
|
||||
from zope.component import getSiteManager
|
||||
from zope.component import getUtility
|
||||
@ -32,7 +32,7 @@ class TestUserNotificationUnit(unittest.TestCase):
|
||||
# We need to fake a valid mail setup
|
||||
registry = getUtility(IRegistry)
|
||||
mail_settings = registry.forInterface(IMailSchema, prefix='plone')
|
||||
mail_settings.email_from_address = "portal@plone.test"
|
||||
mail_settings.email_from_address = 'portal@plone.test'
|
||||
self.mailhost = self.portal.MailHost
|
||||
# Enable user notification setting
|
||||
registry = queryUtility(IRegistry)
|
||||
@ -40,7 +40,7 @@ class TestUserNotificationUnit(unittest.TestCase):
|
||||
'.user_notification_enabled'] = True
|
||||
# Archetypes content types store data as utf-8 encoded strings
|
||||
# The missing u in front of a string is therefor not missing
|
||||
self.portal.doc1.title = 'Kölle Alaaf' # What is "Fasching"?
|
||||
self.portal.doc1.title = 'Kölle Alaaf' # What is 'Fasching'?
|
||||
self.conversation = IConversation(self.portal.doc1)
|
||||
|
||||
def beforeTearDown(self):
|
||||
@ -56,7 +56,7 @@ class TestUserNotificationUnit(unittest.TestCase):
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
comment.user_notification = True
|
||||
comment.author_email = "john@plone.test"
|
||||
comment.author_email = 'john@plone.test'
|
||||
self.conversation.addComment(comment)
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
@ -75,11 +75,10 @@ class TestUserNotificationUnit(unittest.TestCase):
|
||||
# The output should be encoded in a reasonable manner
|
||||
# (in this case quoted-printable):
|
||||
self.assertTrue(
|
||||
"A comment on \'K=C3=B6lle Alaaf\' has been posted here:"
|
||||
'A comment on "K=C3=B6lle Alaaf" has been posted here:'
|
||||
in msg)
|
||||
self.assertTrue(
|
||||
"http://nohost/plone/d=\noc1/view#%s"
|
||||
% comment_id
|
||||
'http://nohost/plone/d=\noc1/view#{0}'.format(comment_id)
|
||||
in msg)
|
||||
self.assertTrue('Comment text' in msg)
|
||||
self.assertFalse('Approve comment' in msg)
|
||||
@ -94,7 +93,7 @@ class TestUserNotificationUnit(unittest.TestCase):
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
comment.user_notification = True
|
||||
comment.author_email = "john@plone.test"
|
||||
comment.author_email = 'john@plone.test'
|
||||
self.conversation.addComment(comment)
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
@ -124,7 +123,7 @@ class TestUserNotificationUnit(unittest.TestCase):
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
comment.user_notification = True
|
||||
comment.author_email = "john@plone.test"
|
||||
comment.author_email = 'john@plone.test'
|
||||
self.conversation.addComment(comment)
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
@ -139,12 +138,12 @@ class TestUserNotificationUnit(unittest.TestCase):
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
comment.user_notification = True
|
||||
comment.author_email = "john@plone.test"
|
||||
comment.author_email = 'john@plone.test'
|
||||
self.conversation.addComment(comment)
|
||||
comment = createObject('plone.Comment')
|
||||
comment.text = 'Comment text'
|
||||
comment.user_notification = True
|
||||
comment.author_email = "john@plone.test"
|
||||
comment.author_email = 'john@plone.test'
|
||||
|
||||
self.conversation.addComment(comment)
|
||||
|
||||
@ -171,7 +170,7 @@ class TestModeratorNotificationUnit(unittest.TestCase):
|
||||
# We need to fake a valid mail setup
|
||||
registry = getUtility(IRegistry)
|
||||
mail_settings = registry.forInterface(IMailSchema, prefix='plone')
|
||||
mail_settings.email_from_address = "portal@plone.test"
|
||||
mail_settings.email_from_address = 'portal@plone.test'
|
||||
self.mailhost = self.portal.MailHost
|
||||
# Enable comment moderation
|
||||
self.portal.portal_types['Document'].allow_discussion = True
|
||||
@ -187,7 +186,7 @@ class TestModeratorNotificationUnit(unittest.TestCase):
|
||||
] = True
|
||||
# Archetypes content types store data as utf-8 encoded strings
|
||||
# The missing u in front of a string is therefor not missing
|
||||
self.portal.doc1.title = 'Kölle Alaaf' # What is "Fasching"?
|
||||
self.portal.doc1.title = 'Kölle Alaaf' # What is 'Fasching'?
|
||||
self.conversation = IConversation(self.portal.doc1)
|
||||
|
||||
def beforeTearDown(self):
|
||||
@ -216,21 +215,28 @@ class TestModeratorNotificationUnit(unittest.TestCase):
|
||||
# The output should be encoded in a reasonable manner
|
||||
# (in this case quoted-printable):
|
||||
self.assertTrue(
|
||||
"A comment on \'K=C3=B6lle Alaaf\' has been posted here:"
|
||||
'A comment on "K=C3=B6lle Alaaf" has been posted here:'
|
||||
in msg)
|
||||
self.assertTrue(
|
||||
"http://nohost/plone/d=\noc1/view#%s"
|
||||
% comment_id
|
||||
in msg)
|
||||
self.assertTrue('Comment text' in msg)
|
||||
self.assertTrue(
|
||||
'Approve comment:\nhttp://nohost/plone/doc1/' +
|
||||
'++conversation++default/%s/@@moderat=\ne-publish-comment'
|
||||
% comment_id in msg)
|
||||
self.assertTrue(
|
||||
'Delete comment:\nhttp://nohost/plone/doc1/' +
|
||||
'++conversation++default/%s/@@moderat=\ne-delete-comment'
|
||||
% comment_id in msg)
|
||||
self.assertIn(
|
||||
'http://nohost/plone/d=\noc1/view#{0}'.format(comment_id),
|
||||
msg
|
||||
)
|
||||
self.assertIn(
|
||||
'Comment text',
|
||||
msg
|
||||
)
|
||||
text = 'Approve comment:\nhttp://nohost/plone/doc1/' \
|
||||
'++conversation++default/{0}/@@moderat=\ne-publish-comment'
|
||||
self.assertIn(
|
||||
text.format(comment_id),
|
||||
msg
|
||||
)
|
||||
text = 'Delete comment:\nhttp://nohost/plone/doc1/' \
|
||||
'++conversation++default/{0}/@@moderat=\ne-delete-comment'
|
||||
self.assertIn(
|
||||
text.format(comment_id),
|
||||
msg
|
||||
)
|
||||
|
||||
def test_notify_moderator_specific_address(self):
|
||||
# A moderator email address can be specified in the control panel.
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_ROBOT_TESTING
|
||||
from plone.app.testing import ROBOT_TEST_LEVEL
|
||||
from plone.testing import layered
|
||||
|
@ -2,8 +2,6 @@
|
||||
"""Test plone.app.discussion workflow and permissions.
|
||||
"""
|
||||
from AccessControl import Unauthorized
|
||||
from Products.CMFCore.permissions import View
|
||||
from Products.CMFCore.utils import _checkPermission as checkPerm
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.interfaces import IDiscussionLayer
|
||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_INTEGRATION_TESTING # noqa
|
||||
@ -11,6 +9,8 @@ from plone.app.testing import login
|
||||
from plone.app.testing import logout
|
||||
from plone.app.testing import setRoles
|
||||
from plone.app.testing import TEST_USER_ID
|
||||
from Products.CMFCore.permissions import View
|
||||
from Products.CMFCore.utils import _checkPermission as checkPerm
|
||||
from zope.component import createObject
|
||||
from zope.interface import alsoProvides
|
||||
|
||||
@ -87,7 +87,7 @@ class PermissionsSetupTest(unittest.TestCase):
|
||||
plone.app.discussion assigns this permission to 'Authenticated' as
|
||||
well to emulate the behavior of the old commenting system.
|
||||
"""
|
||||
ReplyToItemPerm = "Reply to item"
|
||||
ReplyToItemPerm = 'Reply to item'
|
||||
# should be allowed as Member
|
||||
self.assertTrue(self.checkPermission(ReplyToItemPerm, self.portal))
|
||||
# should be allowed as Authenticated
|
||||
@ -126,7 +126,7 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
|
||||
cid = conversation.addComment(comment)
|
||||
|
||||
self.comment = self.folder.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % cid
|
||||
'++conversation++default/{0}'.format(cid)
|
||||
)
|
||||
|
||||
self.portal.acl_users._doAddUser('member', 'secret', ['Member'], [])
|
||||
@ -192,7 +192,8 @@ class CommentReviewWorkflowTest(unittest.TestCase):
|
||||
comment.text = 'Comment text'
|
||||
comment_id = conversation.addComment(comment)
|
||||
comment = self.portal.doc1.restrictedTraverse(
|
||||
'++conversation++default/%s' % comment_id)
|
||||
'++conversation++default/{0}'.format(comment_id)
|
||||
)
|
||||
|
||||
self.conversation = conversation
|
||||
self.comment_id = comment_id
|
||||
|
@ -1,14 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The portal_discussion tool, usually accessed via
|
||||
queryUtility(ICommentingTool). The default implementation delegates to the
|
||||
standard portal_catalog for indexing comments.
|
||||
|
||||
BBB support for the old portal_discussion is provided in the bbb package.
|
||||
"""
|
||||
from OFS.SimpleItem import SimpleItem
|
||||
from Products.CMFCore.utils import UniqueObject
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from interfaces import IComment
|
||||
from interfaces import ICommentingTool
|
||||
from OFS.SimpleItem import SimpleItem
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFCore.utils import UniqueObject
|
||||
from zope import interface
|
||||
from zope.component import queryUtility
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from zope.component import getUtility
|
||||
|
Loading…
Reference in New Issue
Block a user