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:
Gil Forcada
2016-02-05 01:39:53 +01:00
parent fb71aee6cd
commit cb1bf28c16
33 changed files with 620 additions and 551 deletions
+3 -2
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
+19 -18
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,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)
+54 -48
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
+46 -40
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 = \
+6 -4
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
+51 -32
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)
+16 -13
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:
+3 -2
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: