Cleanup
Follow https://github.com/plone/jenkins.plone.org/blob/master/docs/source/run-qa-on-package.rst to clean up the code.
This commit is contained in:
@@ -12,7 +12,8 @@ from z3c.form import interfaces
|
||||
from z3c.form.field import Fields
|
||||
from zope import interface
|
||||
from zope.annotation import factory
|
||||
from zope.component import adapts, queryUtility
|
||||
from zope.component import adapts
|
||||
from zope.component import queryUtility
|
||||
from zope.interface import Interface
|
||||
from zope.publisher.interfaces.browser import IDefaultBrowserLayer
|
||||
|
||||
@@ -51,7 +52,7 @@ class CaptchaExtender(extensible.FormExtender):
|
||||
def update(self):
|
||||
if self.captcha != 'disabled' and self.isAnon:
|
||||
# Add a captcha field if captcha is enabled in the registry
|
||||
self.add(ICaptcha, prefix="")
|
||||
self.add(ICaptcha, prefix='')
|
||||
if self.captcha == 'captcha':
|
||||
from plone.formwidget.captcha import CaptchaFieldWidget
|
||||
self.form.fields['captcha'].widgetFactory = CaptchaFieldWidget
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from AccessControl import getSecurityManager
|
||||
from Acquisition import aq_inner
|
||||
from Acquisition import aq_parent
|
||||
from zope.component import getUtility
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from comments import CommentForm
|
||||
from plone.app.discussion import _
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from plone.z3cform.layout import wrap_form
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from z3c.form import button
|
||||
from zope.component import getMultiAdapter
|
||||
from zope.component import getUtility
|
||||
|
||||
|
||||
class View(BrowserView):
|
||||
@@ -21,9 +22,9 @@ class View(BrowserView):
|
||||
has been posted.
|
||||
|
||||
Redirect from the comment object URL
|
||||
"/path/to/object/++conversation++default/123456789" to the content object
|
||||
'/path/to/object/++conversation++default/123456789' to the content object
|
||||
where the comment has been posted appended by an HTML anchor that points to
|
||||
the comment "/path/to/object#comment-123456789".
|
||||
the comment '/path/to/object#comment-123456789'.
|
||||
|
||||
Context is the comment object. The parent of the comment object is the
|
||||
conversation. The parent of the conversation is the content object where
|
||||
@@ -46,15 +47,15 @@ class View(BrowserView):
|
||||
will redirect right to the binary object, bypassing comments.
|
||||
"""
|
||||
if obj.portal_type in view_action_types:
|
||||
url = "%s/view" % url
|
||||
url = '{0}/view'.format(url)
|
||||
|
||||
self.request.response.redirect('%s#%s' % (url, context.id))
|
||||
self.request.response.redirect('{0}#{1}'.format(url, context.id))
|
||||
|
||||
|
||||
class EditCommentForm(CommentForm):
|
||||
"""Form to edit an existing comment."""
|
||||
ignoreContext = True
|
||||
id = "edit-comment-form"
|
||||
id = 'edit-comment-form'
|
||||
label = _(u'edit_comment_form_title', default=u'Edit comment')
|
||||
|
||||
def updateWidgets(self):
|
||||
@@ -71,8 +72,8 @@ class EditCommentForm(CommentForm):
|
||||
target = portal_state.portal_url()
|
||||
self.request.response.redirect(target)
|
||||
|
||||
@button.buttonAndHandler(_(u"edit_comment_form_button",
|
||||
default=u"Edit comment"), name='comment')
|
||||
@button.buttonAndHandler(_(u'edit_comment_form_button',
|
||||
default=u'Edit comment'), name='comment')
|
||||
def handleComment(self, action):
|
||||
|
||||
# Validate form
|
||||
@@ -93,19 +94,19 @@ class EditCommentForm(CommentForm):
|
||||
|
||||
# Redirect to comment
|
||||
IStatusMessage(self.request).add(_(u'comment_edit_notification',
|
||||
default="Comment was edited"),
|
||||
default='Comment was edited'),
|
||||
type='info')
|
||||
return self._redirect(
|
||||
target=self.action.replace("@@edit-comment", "@@view"))
|
||||
target=self.action.replace('@@edit-comment', '@@view'))
|
||||
|
||||
@button.buttonAndHandler(_(u'cancel_form_button',
|
||||
default=u'Cancel'), name='cancel')
|
||||
def handle_cancel(self, action):
|
||||
IStatusMessage(self.request).add(
|
||||
_(u'comment_edit_cancel_notification',
|
||||
default=u'Edit comment cancelled'),
|
||||
type='info')
|
||||
return self._redirect(target=self.context.absolute_url())
|
||||
IStatusMessage(self.request).add(
|
||||
_(u'comment_edit_cancel_notification',
|
||||
default=u'Edit comment cancelled'),
|
||||
type='info')
|
||||
return self._redirect(target=self.context.absolute_url())
|
||||
|
||||
EditComment = wrap_form(EditCommentForm)
|
||||
|
||||
|
||||
@@ -2,11 +2,8 @@
|
||||
from AccessControl import getSecurityManager
|
||||
from AccessControl import Unauthorized
|
||||
from Acquisition import aq_inner
|
||||
from DateTime import DateTime
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from datetime import datetime
|
||||
from DateTime import DateTime
|
||||
from plone.app.discussion import _
|
||||
from plone.app.discussion.browser.validator import CaptchaValidator
|
||||
from plone.app.discussion.interfaces import ICaptcha
|
||||
@@ -19,6 +16,9 @@ from plone.registry.interfaces import IRegistry
|
||||
from plone.z3cform import z2
|
||||
from plone.z3cform.fieldsets import extensible
|
||||
from plone.z3cform.interfaces import IWrappedForm
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from urllib import quote as url_quote
|
||||
from z3c.form import button
|
||||
from z3c.form import field
|
||||
@@ -34,32 +34,36 @@ from zope.interface import alsoProvides
|
||||
|
||||
|
||||
COMMENT_DESCRIPTION_PLAIN_TEXT = _(
|
||||
u"comment_description_plain_text",
|
||||
default=u"You can add a comment by filling out the form below. " +
|
||||
u"Plain text formatting.")
|
||||
u'comment_description_plain_text',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting.'
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_MARKDOWN = _(
|
||||
u"comment_description_markdown",
|
||||
default=u"You can add a comment by filling out the form below. " +
|
||||
u"Plain text formatting. You can use the Markdown syntax for " +
|
||||
u"links and images.")
|
||||
u'comment_description_markdown',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting. You can use the Markdown syntax for '
|
||||
u'links and images.'
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _(
|
||||
u"comment_description_intelligent_text",
|
||||
default=u"You can add a comment by filling out the form below. " +
|
||||
u"Plain text formatting. Web and email addresses are " +
|
||||
u"transformed into clickable links.")
|
||||
u'comment_description_intelligent_text',
|
||||
default=u'You can add a comment by filling out the form below. '
|
||||
u'Plain text formatting. Web and email addresses are '
|
||||
u'transformed into clickable links.'
|
||||
)
|
||||
|
||||
COMMENT_DESCRIPTION_MODERATION_ENABLED = _(
|
||||
u"comment_description_moderation_enabled",
|
||||
default=u"Comments are moderated.")
|
||||
u'comment_description_moderation_enabled',
|
||||
default=u'Comments are moderated.'
|
||||
)
|
||||
|
||||
|
||||
class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
ignoreContext = True # don't use context to get widget data
|
||||
id = None
|
||||
label = _(u"Add a comment")
|
||||
label = _(u'Add a comment')
|
||||
fields = field.Fields(IComment).omit('portal_type',
|
||||
'__parent__',
|
||||
'__name__',
|
||||
@@ -81,13 +85,13 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
# Widgets
|
||||
self.widgets['in_reply_to'].mode = interfaces.HIDDEN_MODE
|
||||
self.widgets['text'].addClass("autoresize")
|
||||
self.widgets['user_notification'].label = _(u"")
|
||||
self.widgets['text'].addClass('autoresize')
|
||||
self.widgets['user_notification'].label = _(u'')
|
||||
|
||||
# Rename the id of the text widgets because there can be css-id
|
||||
# clashes with the text field of documents when using and overlay
|
||||
# with TinyMCE.
|
||||
self.widgets['text'].id = "form-widgets-comment-text"
|
||||
self.widgets['text'].id = 'form-widgets-comment-text'
|
||||
|
||||
# Anonymous / Logged-in
|
||||
mtool = getToolByName(self.context, 'portal_membership')
|
||||
@@ -99,7 +103,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if anon:
|
||||
if settings.anonymous_email_enabled:
|
||||
# according to IDiscussionSettings.anonymous_email_enabled:
|
||||
# "If selected, anonymous user will have to give their email."
|
||||
# 'If selected, anonymous user will have to give their email.'
|
||||
self.widgets['author_email'].field.required = True
|
||||
self.widgets['author_email'].required = True
|
||||
else:
|
||||
@@ -121,11 +125,11 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
def updateActions(self):
|
||||
super(CommentForm, self).updateActions()
|
||||
self.actions['cancel'].addClass("standalone")
|
||||
self.actions['cancel'].addClass("hide")
|
||||
self.actions['comment'].addClass("context")
|
||||
self.actions['cancel'].addClass('standalone')
|
||||
self.actions['cancel'].addClass('hide')
|
||||
self.actions['comment'].addClass('context')
|
||||
|
||||
@button.buttonAndHandler(_(u"add_comment_button", default=u"Comment"),
|
||||
@button.buttonAndHandler(_(u'add_comment_button', default=u'Comment'),
|
||||
name='comment')
|
||||
def handleComment(self, action):
|
||||
context = aq_inner(self.context)
|
||||
@@ -134,8 +138,9 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if not self.__parent__.restrictedTraverse(
|
||||
'@@conversation_view'
|
||||
).enabled():
|
||||
raise Unauthorized("Discussion is not enabled for this content "
|
||||
"object.")
|
||||
raise Unauthorized(
|
||||
'Discussion is not enabled for this content object.'
|
||||
)
|
||||
|
||||
# Validation form
|
||||
data, errors = self.extractData()
|
||||
@@ -151,7 +156,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
anon = portal_membership.isAnonymousUser()
|
||||
if captcha_enabled and anonymous_comments and anon:
|
||||
if 'captcha' not in data:
|
||||
data['captcha'] = u""
|
||||
data['captcha'] = u''
|
||||
captcha = CaptchaValidator(self.context,
|
||||
self.request,
|
||||
None,
|
||||
@@ -160,7 +165,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
captcha.validate(data['captcha'])
|
||||
|
||||
# some attributes are not always set
|
||||
author_name = u""
|
||||
author_name = u''
|
||||
|
||||
# Create comment
|
||||
comment = createObject('plone.Comment')
|
||||
@@ -207,14 +212,14 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if email and isinstance(email, str):
|
||||
email = unicode(email, 'utf-8')
|
||||
comment.changeOwnership(user, recursive=False)
|
||||
comment.manage_setLocalRoles(memberid, ["Owner"])
|
||||
comment.manage_setLocalRoles(memberid, ['Owner'])
|
||||
comment.creator = memberid
|
||||
comment.author_username = memberid
|
||||
comment.author_name = fullname
|
||||
|
||||
# XXX: according to IComment interface author_email must not be
|
||||
# set for logged in users, cite:
|
||||
# "for anonymous comments only, set to None for logged in comments"
|
||||
# 'for anonymous comments only, set to None for logged in comments'
|
||||
comment.author_email = email
|
||||
# /XXX
|
||||
|
||||
@@ -223,8 +228,8 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
|
||||
else: # pragma: no cover
|
||||
raise Unauthorized(
|
||||
u"Anonymous user tries to post a comment, but anonymous "
|
||||
u"commenting is disabled. Or user does not have the "
|
||||
u'Anonymous user tries to post a comment, but anonymous '
|
||||
u'commenting is disabled. Or user does not have the '
|
||||
u"'reply to item' permission."
|
||||
)
|
||||
|
||||
@@ -255,14 +260,14 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if comment_review_state == 'pending' and not can_review:
|
||||
# Show info message when comment moderation is enabled
|
||||
IStatusMessage(self.context.REQUEST).addStatusMessage(
|
||||
_("Your comment awaits moderator approval."),
|
||||
type="info")
|
||||
_('Your comment awaits moderator approval.'),
|
||||
type='info')
|
||||
self.request.response.redirect(self.action)
|
||||
else:
|
||||
# Redirect to comment (inside a content object page)
|
||||
self.request.response.redirect(self.action + '#' + str(comment_id))
|
||||
|
||||
@button.buttonAndHandler(_(u"Cancel"))
|
||||
@button.buttonAndHandler(_(u'Cancel'))
|
||||
def handleCancel(self, action):
|
||||
# This method should never be called, it's only there to show
|
||||
# a cancel button that is handled by a jQuery method.
|
||||
@@ -278,9 +283,9 @@ class CommentsViewlet(ViewletBase):
|
||||
super(CommentsViewlet, self).update()
|
||||
discussion_allowed = self.is_discussion_allowed()
|
||||
anonymous_allowed_or_can_reply = (
|
||||
self.is_anonymous()
|
||||
and self.anonymous_discussion_allowed()
|
||||
or self.can_reply()
|
||||
self.is_anonymous() and
|
||||
self.anonymous_discussion_allowed() or
|
||||
self.can_reply()
|
||||
)
|
||||
if discussion_allowed and anonymous_allowed_or_can_reply:
|
||||
z2.switch_on(self, request_layer=IFormLayer)
|
||||
@@ -356,10 +361,10 @@ class CommentsViewlet(ViewletBase):
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
|
||||
# text transform setting
|
||||
if settings.text_transform == "text/x-web-intelligent":
|
||||
if settings.text_transform == 'text/x-web-intelligent':
|
||||
message = translate(Message(COMMENT_DESCRIPTION_INTELLIGENT_TEXT),
|
||||
context=self.request)
|
||||
elif settings.text_transform == "text/x-web-markdown":
|
||||
elif settings.text_transform == 'text/x-web-markdown':
|
||||
message = translate(Message(COMMENT_DESCRIPTION_MARKDOWN),
|
||||
context=self.request)
|
||||
else:
|
||||
@@ -367,7 +372,7 @@ class CommentsViewlet(ViewletBase):
|
||||
context=self.request)
|
||||
|
||||
# comment workflow
|
||||
wftool = getToolByName(context, "portal_workflow", None)
|
||||
wftool = getToolByName(context, 'portal_workflow', None)
|
||||
workflow_chain = wftool.getChainForPortalType('Discussion Item')
|
||||
if workflow_chain:
|
||||
comment_workflow = workflow_chain[0]
|
||||
@@ -375,7 +380,7 @@ class CommentsViewlet(ViewletBase):
|
||||
# check if the current workflow implements a pending state. If this
|
||||
# is true comments are moderated
|
||||
if 'pending' in comment_workflow.states:
|
||||
message = message + " " + \
|
||||
message = message + ' ' + \
|
||||
translate(Message(COMMENT_DESCRIPTION_MODERATION_ENABLED),
|
||||
context=self.request)
|
||||
|
||||
@@ -445,7 +450,7 @@ class CommentsViewlet(ViewletBase):
|
||||
if username is None:
|
||||
return None
|
||||
else:
|
||||
return "%s/author/%s" % (self.context.portal_url(), username)
|
||||
return '{0}/author/{1}'.format(self.context.portal_url(), username)
|
||||
|
||||
def get_commenter_portrait(self, username=None):
|
||||
|
||||
@@ -491,9 +496,10 @@ class CommentsViewlet(ViewletBase):
|
||||
return portal_membership.isAnonymousUser()
|
||||
|
||||
def login_action(self):
|
||||
return '%s/login_form?came_from=%s' % \
|
||||
(self.navigation_root_url,
|
||||
url_quote(self.request.get('URL', '')),)
|
||||
return '{0}/login_form?came_from={1}'.format(
|
||||
self.navigation_root_url,
|
||||
url_quote(self.request.get('URL', '')),
|
||||
)
|
||||
|
||||
def format_time(self, time):
|
||||
# We have to transform Python datetime into Zope DateTime
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from plone.app.controlpanel.interfaces import IConfigurationChangedEvent
|
||||
from plone.app.discussion.interfaces import _
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
@@ -11,6 +6,11 @@ from plone.app.discussion.upgrades import update_registry
|
||||
from plone.app.registry.browser import controlpanel
|
||||
from plone.registry.interfaces import IRecordModifiedEvent
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces.controlpanel import IMailSchema
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from z3c.form import button
|
||||
from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget
|
||||
from zope.component import getMultiAdapter
|
||||
@@ -23,19 +23,19 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
"""Discussion settings form.
|
||||
"""
|
||||
schema = IDiscussionSettings
|
||||
id = "DiscussionSettingsEditForm"
|
||||
label = _(u"Discussion settings")
|
||||
id = 'DiscussionSettingsEditForm'
|
||||
label = _(u'Discussion settings')
|
||||
description = _(
|
||||
u"help_discussion_settings_editform",
|
||||
default=u"Some discussion related settings are not "
|
||||
u"located in the Discussion Control Panel.\n"
|
||||
u"To enable comments for a specific content type, "
|
||||
u"go to the Types Control Panel of this type and "
|
||||
u"choose \"Allow comments\".\n"
|
||||
u"To enable the moderation workflow for comments, "
|
||||
u"go to the Types Control Panel, choose "
|
||||
u"\"Comment\" and set workflow to "
|
||||
u"\"Comment Review Workflow\"."
|
||||
u'help_discussion_settings_editform',
|
||||
default=u'Some discussion related settings are not '
|
||||
u'located in the Discussion Control Panel.\n'
|
||||
u'To enable comments for a specific content type, '
|
||||
u'go to the Types Control Panel of this type and '
|
||||
u'choose "Allow comments".\n'
|
||||
u'To enable the moderation workflow for comments, '
|
||||
u'go to the Types Control Panel, choose '
|
||||
u'"Comment" and set workflow to '
|
||||
u'"Comment Review Workflow".'
|
||||
)
|
||||
|
||||
def updateFields(self):
|
||||
@@ -65,13 +65,15 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
# provide auto-upgrade
|
||||
update_registry(self.context)
|
||||
super(DiscussionSettingsEditForm, self).updateWidgets()
|
||||
self.widgets['globally_enabled'].label = _(u"Enable Comments")
|
||||
self.widgets['anonymous_comments'].label = _(u"Anonymous Comments")
|
||||
self.widgets['show_commenter_image'].label = _(u"Commenter Image")
|
||||
self.widgets['moderator_notification_enabled'].label = \
|
||||
_(u"Moderator Email Notification")
|
||||
self.widgets['user_notification_enabled'].label = \
|
||||
_(u"User Email Notification")
|
||||
self.widgets['globally_enabled'].label = _(u'Enable Comments')
|
||||
self.widgets['anonymous_comments'].label = _(u'Anonymous Comments')
|
||||
self.widgets['show_commenter_image'].label = _(u'Commenter Image')
|
||||
self.widgets['moderator_notification_enabled'].label = _(
|
||||
u'Moderator Email Notification'
|
||||
)
|
||||
self.widgets['user_notification_enabled'].label = _(
|
||||
u'User Email Notification'
|
||||
)
|
||||
|
||||
@button.buttonAndHandler(_('Save'), name=None)
|
||||
def handleSave(self, action):
|
||||
@@ -80,16 +82,20 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
|
||||
self.status = self.formErrorsMessage
|
||||
return
|
||||
self.applyChanges(data)
|
||||
IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
|
||||
"info")
|
||||
self.context.REQUEST.RESPONSE.redirect("@@discussion-controlpanel")
|
||||
IStatusMessage(self.request).addStatusMessage(_(u'Changes saved'),
|
||||
'info')
|
||||
self.context.REQUEST.RESPONSE.redirect('@@discussion-controlpanel')
|
||||
|
||||
@button.buttonAndHandler(_('Cancel'), name='cancel')
|
||||
def handleCancel(self, action):
|
||||
IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"),
|
||||
"info")
|
||||
self.request.response.redirect("%s/%s" % (self.context.absolute_url(),
|
||||
self.control_panel_view))
|
||||
IStatusMessage(self.request).addStatusMessage(_(u'Edit cancelled'),
|
||||
'info')
|
||||
self.request.response.redirect(
|
||||
'{0}/{1}'.format(
|
||||
self.context.absolute_url(),
|
||||
self.control_panel_view
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
||||
@@ -104,38 +110,38 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
||||
"""
|
||||
registry = queryUtility(IRegistry)
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
wftool = getToolByName(self.context, "portal_workflow", None)
|
||||
wftool = getToolByName(self.context, 'portal_workflow', None)
|
||||
workflow_chain = wftool.getChainForPortalType('Discussion Item')
|
||||
output = []
|
||||
|
||||
# Globally enabled
|
||||
if settings.globally_enabled:
|
||||
output.append("globally_enabled")
|
||||
output.append('globally_enabled')
|
||||
|
||||
# Comment moderation
|
||||
one_state_worklow_disabled = 'one_state_workflow' not in workflow_chain
|
||||
comment_review_workflow_disabled = \
|
||||
'comment_review_workflow' not in workflow_chain
|
||||
if one_state_worklow_disabled and comment_review_workflow_disabled:
|
||||
output.append("moderation_custom")
|
||||
output.append('moderation_custom')
|
||||
elif settings.moderation_enabled:
|
||||
output.append("moderation_enabled")
|
||||
output.append('moderation_enabled')
|
||||
|
||||
if settings.edit_comment_enabled:
|
||||
output.append("edit_comment_enabled")
|
||||
output.append('edit_comment_enabled')
|
||||
|
||||
if settings.delete_own_comment_enabled:
|
||||
output.append("delte_own_comment_enabled")
|
||||
output.append('delete_own_comment_enabled')
|
||||
|
||||
# Anonymous comments
|
||||
if settings.anonymous_comments:
|
||||
output.append("anonymous_comments")
|
||||
output.append('anonymous_comments')
|
||||
|
||||
# Invalid mail setting
|
||||
ctrlOverview = getMultiAdapter((self.context, self.request),
|
||||
name='overview-controlpanel')
|
||||
if ctrlOverview.mailhost_warning():
|
||||
output.append("invalid_mail_setup")
|
||||
output.append('invalid_mail_setup')
|
||||
|
||||
# Workflow
|
||||
wftool = getToolByName(self.context, 'portal_workflow', None)
|
||||
@@ -161,7 +167,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
|
||||
def custom_comment_workflow_warning(self):
|
||||
"""Returns a warning string if a custom comment workflow is enabled.
|
||||
"""
|
||||
wftool = getToolByName(self.context, "portal_workflow", None)
|
||||
wftool = getToolByName(self.context, 'portal_workflow', None)
|
||||
workflow_chain = wftool.getChainForPortalType('Discussion Item')
|
||||
one_state_workflow_enabled = 'one_state_workflow' in workflow_chain
|
||||
comment_review_workflow_enabled = \
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Acquisition import aq_base
|
||||
from Acquisition import aq_chain
|
||||
from Acquisition import aq_inner
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from Products.CMFCore.interfaces import IFolderish
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFPlone.interfaces import INonStructuralFolder
|
||||
from Products.CMFPlone.interfaces import IPloneSiteRoot
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
from plone.registry.interfaces import IRegistry
|
||||
from zope.component import queryUtility
|
||||
|
||||
|
||||
try:
|
||||
from plone.dexterity.interfaces import IDexterityContent
|
||||
DEXTERITY_INSTALLED = True
|
||||
except:
|
||||
except ImportError:
|
||||
DEXTERITY_INSTALLED = False
|
||||
|
||||
|
||||
@@ -130,7 +132,7 @@ class ConversationView(object):
|
||||
return False
|
||||
|
||||
# Check if discussion is allowed on the content object
|
||||
if hasattr(context, "allow_discussion"):
|
||||
if hasattr(context, 'allow_discussion'):
|
||||
if context.allow_discussion is not None:
|
||||
return context.allow_discussion
|
||||
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from Acquisition import aq_inner
|
||||
from Acquisition import aq_parent
|
||||
from datetime import datetime
|
||||
from DateTime import DateTime
|
||||
from plone.app.discussion.comment import CommentFactory
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IConversation
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
from Products.CMFCore.interfaces._content import IDiscussionResponse
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from datetime import datetime
|
||||
from plone.app.discussion.comment import CommentFactory
|
||||
from plone.app.discussion.interfaces import IConversation, IReplies, IComment
|
||||
from types import TupleType
|
||||
|
||||
import transaction
|
||||
@@ -35,11 +38,11 @@ class View(BrowserView):
|
||||
self.total_comments_migrated = 0
|
||||
self.total_comments_deleted = 0
|
||||
|
||||
dry_run = "dry_run" in self.request
|
||||
dry_run = 'dry_run' in self.request
|
||||
|
||||
# This is for testing only.
|
||||
# Do not use transactions during a test.
|
||||
test = "test" in self.request
|
||||
test = 'test' in self.request
|
||||
|
||||
if not test:
|
||||
transaction.begin() # pragma: no cover
|
||||
@@ -71,10 +74,10 @@ class View(BrowserView):
|
||||
|
||||
for reply in replies:
|
||||
# log
|
||||
indent = " "
|
||||
indent = ' '
|
||||
for i in range(depth):
|
||||
indent += " "
|
||||
log("%smigrate_reply: '%s'." % (indent, reply.title))
|
||||
indent += ' '
|
||||
log('{0}migrate_reply: "{1}".'.format(indent, reply.title))
|
||||
|
||||
should_migrate = True
|
||||
if filter_callback and not filter_callback(reply):
|
||||
@@ -172,7 +175,7 @@ class View(BrowserView):
|
||||
talkback.deleteReply(reply.id)
|
||||
obj = aq_parent(talkback)
|
||||
obj.talkback = None
|
||||
log("%sremove %s" % (indent, reply.id))
|
||||
log('{0}remove {1}'.format(indent, reply.id))
|
||||
self.total_comments_deleted += 1
|
||||
|
||||
# Return True when all comments on a certain level have been
|
||||
@@ -182,7 +185,7 @@ class View(BrowserView):
|
||||
# Find content
|
||||
brains = catalog.searchResults(
|
||||
object_provides='Products.CMFCore.interfaces._content.IContentish')
|
||||
log("Found %s content objects." % len(brains))
|
||||
log('Found {0} content objects.'.format(len(brains)))
|
||||
|
||||
count_discussion_items = len(
|
||||
catalog.searchResults(Type='Discussion Item')
|
||||
@@ -196,12 +199,20 @@ class View(BrowserView):
|
||||
)
|
||||
)
|
||||
|
||||
log("Found %s Discussion Item objects." % count_discussion_items)
|
||||
log("Found %s old discussion items." % count_comments_old)
|
||||
log("Found %s plone.app.discussion comments." % count_comments_pad)
|
||||
log(
|
||||
'Found {0} Discussion Item objects.'.format(
|
||||
count_discussion_items
|
||||
)
|
||||
)
|
||||
log('Found {0} old discussion items.'.format(count_comments_old))
|
||||
log(
|
||||
'Found {0} plone.app.discussion comments.'.format(
|
||||
count_comments_pad
|
||||
)
|
||||
)
|
||||
|
||||
log("\n")
|
||||
log("Start comment migration.")
|
||||
log('\n')
|
||||
log('Start comment migration.')
|
||||
|
||||
# This loop is necessary to get all contentish objects, but not
|
||||
# the Discussion Items. This wouldn't be necessary if the
|
||||
@@ -219,46 +230,54 @@ class View(BrowserView):
|
||||
replies = talkback.getReplies()
|
||||
if replies:
|
||||
conversation = IConversation(obj)
|
||||
log("\n")
|
||||
log("Migrate '%s' (%s)" % (obj.Title(),
|
||||
obj.absolute_url(relative=1)))
|
||||
log('\n')
|
||||
log(
|
||||
'Migrate "{0}" ({1})'.format(
|
||||
obj.Title(),
|
||||
obj.absolute_url(relative=1)
|
||||
)
|
||||
)
|
||||
migrate_replies(context, 0, replies)
|
||||
obj = aq_parent(talkback)
|
||||
obj.talkback = None
|
||||
|
||||
if self.total_comments_deleted != self.total_comments_migrated:
|
||||
log(
|
||||
"Something went wrong during migration. The number of " +
|
||||
"migrated comments (%s) differs from the number of deleted " +
|
||||
"comments (%s)." % (
|
||||
'Something went wrong during migration. The number of '
|
||||
'migrated comments ({0}) differs from the number of deleted '
|
||||
'comments ({1}).'.format(
|
||||
self.total_comments_migrated,
|
||||
self.total_comments_deleted
|
||||
)
|
||||
)
|
||||
if not test: # pragma: no cover
|
||||
transaction.abort() # pragma: no cover
|
||||
log("Abort transaction") # pragma: no cover
|
||||
log('Abort transaction') # pragma: no cover
|
||||
|
||||
log("\n")
|
||||
log("Comment migration finished.")
|
||||
log("\n")
|
||||
log('\n')
|
||||
log('Comment migration finished.')
|
||||
log('\n')
|
||||
|
||||
log("%s of %s comments migrated."
|
||||
% (self.total_comments_migrated, count_comments_old))
|
||||
log(
|
||||
'{0} of {1} comments migrated.'.format(
|
||||
self.total_comments_migrated,
|
||||
count_comments_old
|
||||
)
|
||||
)
|
||||
|
||||
if self.total_comments_migrated != count_comments_old:
|
||||
log(
|
||||
"%s comments could not be migrated." % (
|
||||
'{0} comments could not be migrated.'.format(
|
||||
count_comments_old - self.total_comments_migrated
|
||||
)
|
||||
) # pragma: no cover
|
||||
log("Please make sure your " +
|
||||
"portal catalog is up-to-date.") # pragma: no cover
|
||||
log('Please make sure your ' +
|
||||
'portal catalog is up-to-date.') # pragma: no cover
|
||||
|
||||
if dry_run and not test:
|
||||
transaction.abort() # pragma: no cover
|
||||
log("Dry run") # pragma: no cover
|
||||
log("Abort transaction") # pragma: no cover
|
||||
log('Dry run') # pragma: no cover
|
||||
log('Abort transaction') # pragma: no cover
|
||||
if not test:
|
||||
transaction.commit() # pragma: no cover
|
||||
return '\n'.join(out)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from AccessControl import Unauthorized
|
||||
from AccessControl import getSecurityManager
|
||||
from AccessControl import Unauthorized
|
||||
from Acquisition import aq_inner
|
||||
from Acquisition import aq_parent
|
||||
from plone.app.discussion.interfaces import _
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.Five.browser import BrowserView
|
||||
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
|
||||
from Products.statusmessages.interfaces import IStatusMessage
|
||||
from plone.app.discussion.interfaces import _
|
||||
from plone.app.discussion.interfaces import IComment
|
||||
from plone.app.discussion.interfaces import IReplies
|
||||
|
||||
|
||||
class View(BrowserView):
|
||||
@@ -101,8 +101,8 @@ class DeleteComment(BrowserView):
|
||||
del conversation[comment.id]
|
||||
content_object.reindexObject()
|
||||
IStatusMessage(self.context.REQUEST).addStatusMessage(
|
||||
_("Comment deleted."),
|
||||
type="info")
|
||||
_('Comment deleted.'),
|
||||
type='info')
|
||||
came_from = self.context.REQUEST.HTTP_REFERER
|
||||
# if the referrer already has a came_from in it, don't redirect back
|
||||
if len(came_from) == 0 or 'came_from=' in came_from:
|
||||
@@ -133,14 +133,17 @@ class DeleteOwnComment(DeleteComment):
|
||||
sm = getSecurityManager()
|
||||
comment = comment or aq_inner(self.context)
|
||||
userid = sm.getUser().getId()
|
||||
return (sm.checkPermission('Delete own comments',
|
||||
comment)
|
||||
and 'Owner' in comment.get_local_roles_for_userid(userid))
|
||||
return (
|
||||
sm.checkPermission('Delete own comments', comment) and
|
||||
'Owner' in comment.get_local_roles_for_userid(userid)
|
||||
)
|
||||
|
||||
def can_delete(self, comment=None):
|
||||
comment = comment or self.context
|
||||
return (len(IReplies(aq_inner(comment))) == 0
|
||||
and self.could_delete(comment=comment))
|
||||
return (
|
||||
len(IReplies(aq_inner(comment))) == 0 and
|
||||
self.could_delete(comment=comment)
|
||||
)
|
||||
|
||||
def __call__(self):
|
||||
if self.can_delete():
|
||||
@@ -179,8 +182,8 @@ class PublishComment(BrowserView):
|
||||
comment.reindexObject()
|
||||
content_object.reindexObject(idxs=['total_comments'])
|
||||
IStatusMessage(self.context.REQUEST).addStatusMessage(
|
||||
_("Comment approved."),
|
||||
type="info")
|
||||
_('Comment approved.'),
|
||||
type='info')
|
||||
came_from = self.context.REQUEST.HTTP_REFERER
|
||||
# if the referrer already has a came_from in it, don't redirect back
|
||||
if len(came_from) == 0 or 'came_from=' in came_from:
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Implement the ++comments++ traversal namespace. This should return the
|
||||
IDiscussion container for the context, from which traversal will continue
|
||||
into an actual comment object.
|
||||
@@ -29,8 +30,8 @@ class ConversationNamespace(object):
|
||||
|
||||
def traverse(self, name, ignore):
|
||||
|
||||
if name == "default":
|
||||
name = u""
|
||||
if name == 'default':
|
||||
name = u''
|
||||
|
||||
conversation = queryAdapter(self.context, IConversation, name=name)
|
||||
if conversation is None:
|
||||
|
||||
Reference in New Issue
Block a user