Merge pull request #83 from plone/cleanup

Cleanup
This commit is contained in:
Gil Forcada Codinachs 2016-02-05 13:02:53 +01:00
commit f0d837294f
33 changed files with 620 additions and 551 deletions

View File

@ -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)

View File

@ -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__)

View File

@ -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__)

View File

@ -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

View File

@ -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,10 +94,10 @@ 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')

View File

@ -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

View File

@ -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 = \

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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:

View File

@ -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

View File

@ -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(

View File

@ -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)

View File

@ -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

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
""" Custom discussion events
"""
from plone.app.discussion.interfaces import ICommentAddedEvent

View File

@ -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
)

View File

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from Products.CMFCore.utils import getToolByName

View File

@ -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'
)

View File

@ -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

View File

@ -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>&lt;b&gt;Got HTML?&lt;/b&gt;</p>"
'<p>&lt;b&gt;Got HTML?&lt;/b&gt;</p>'
)
def test_getText_with_non_ascii_characters(self):
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)),

View File

@ -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):

View File

@ -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')

View File

@ -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']

View File

@ -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
@ -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)

View File

@ -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'

View File

@ -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):

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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