Nuke trailing white space

svn path=/plone.app.discussion/trunk/; revision=46366
This commit is contained in:
Maurits van Rees
2010-12-15 23:52:56 +00:00
parent aff8a3709c
commit a2a17085a3
38 changed files with 507 additions and 505 deletions
+2 -2
View File
@@ -39,7 +39,7 @@ Captcha = factory(Captcha)
class CaptchaExtender(extensible.FormExtender):
"""Extends the comment form with a Captcha. This Captcha extender is only
registered when a plugin is installed that provides the
registered when a plugin is installed that provides the
"plone.app.discussion-captcha" feature.
"""
adapts(Interface, IDefaultBrowserLayer, CommentForm) # context, request, form
@@ -72,4 +72,4 @@ class CaptchaExtender(extensible.FormExtender):
self.form.fields['captcha'].widgetFactory = NorobotsFieldWidget
else:
self.form.fields['captcha'].mode = interfaces.HIDDEN_MODE
+11 -11
View File
@@ -1,15 +1,15 @@
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:meta="http://namespaces.zope.org/meta"
xmlns:meta="http://namespaces.zope.org/meta"
xmlns:zcml="http://namespaces.zope.org/zcml"
i18n_domain="plone.app.discussion">
<!--
<!--
Plone 3 fixes
Plone 3 / Zope 2.10 does not recognize the meta:provides feature.
Plone 3 / Zope 2.10 does not recognize the meta:provides feature.
Therefore we claim to provide this feature when a suitable package is
installed.
installed.
-->
<configure zcml:condition="installed plone.formwidget.captcha">
<meta:provides feature="plone.app.discussion-captcha" />
@@ -21,11 +21,11 @@
<!-- Captcha comment form extender -->
<configure zcml:condition="have plone.app.discussion-captcha">
<!--
<!--
Register the Captcha form extender and validator only if there are
plugins installed that declare to implement a Captcha solution for
plone.app.discussion (e.g. plone.formwidget.captcha and
plone.formwidget.recaptcha).
plone.app.discussion (e.g. plone.formwidget.captcha and
plone.formwidget.recaptcha).
-->
<adapter
factory=".captcha.Captcha"
@@ -44,7 +44,7 @@
<adapter
factory="collective.akismet.validator.AkismetValidator"
provides="z3c.form.interfaces.IValidator"
/>
/>
</configure>
</configure>
</configure>
+5 -5
View File
@@ -5,15 +5,15 @@ from Products.Five.browser import BrowserView
class View(BrowserView):
"""Comment View.
When the view of a comment object is called directly, redirect to the
When the view of a comment object is called directly, redirect to the
the page (content object) and the location (HTML-anchor) where the comment
has been posted.
Redirect from the comment object URL
"/path/to/object/++conversation++default/123456789" to the content object
where the comment has been posted appended by an HTML anchor that points to
where the comment has been posted appended by an HTML anchor that points to
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
the comment has been posted.
@@ -24,4 +24,4 @@ class View(BrowserView):
self.request.response.redirect(
aq_parent(aq_parent(context)).absolute_url() +
'#' + str(context.id)
)
)
+7 -7
View File
@@ -58,7 +58,7 @@
tal:attributes="src portrait_url;
alt reply/Creator" />
</div>
<div class="documentByLine" i18n:domain="plone.app.discussion">
<tal:name>
<a href=""
@@ -72,16 +72,16 @@
<span tal:condition="not: reply/Creator">Anonymous</span>
</tal:name>
<tal:posted i18n:translate="label_says">says:</tal:posted>
<div class="commentDate"
<div class="commentDate"
tal:content="python:view.format_time(reply.modification_date)">
8/23/2001 12:40:44 PM
</div>
</div>
<div class="commentBody">
<span tal:replace="structure python:view.cook(reply.getText())" />
<div class="commentActions">
<form name="delete"
action=""
@@ -96,7 +96,7 @@
i18n:attributes="value label_delete;"
/>
</form>
<!-- Workflow actions (e.g. 'publish') -->
<form name=""
action=""
@@ -115,7 +115,7 @@
/>
</form>
</div>
</div>
<button class="context reply-to-comment-button hide allowMultiSubmit"
+47 -47
View File
@@ -41,10 +41,10 @@ from plone.z3cform import z2
from plone.z3cform.widget import SingleCheckBoxWidget
from plone.z3cform.fieldsets import extensible
# starting from 0.6.0 version plone.z3cform has IWrappedForm interface
# starting from 0.6.0 version plone.z3cform has IWrappedForm interface
try:
from plone.z3cform.interfaces import IWrappedForm
HAS_WRAPPED_FORM = True
from plone.z3cform.interfaces import IWrappedForm
HAS_WRAPPED_FORM = True
except ImportError: # pragma: no cover
HAS_WRAPPED_FORM = False
@@ -87,48 +87,48 @@ 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['user_notification'].label = _(u"")
# Anonymous / Logged-in
portal_membership = getToolByName(self.context, 'portal_membership')
if not portal_membership.isAnonymousUser():
self.widgets['author_name'].mode = interfaces.HIDDEN_MODE
self.widgets['author_email'].mode = interfaces.HIDDEN_MODE
# Todo: Since we are not using the author_email field in the
# current state, we hide it by default. But we keep the field for
# integrators or later use.
# Todo: Since we are not using the author_email field in the
# current state, we hide it by default. But we keep the field for
# integrators or later use.
self.widgets['author_email'].mode = interfaces.HIDDEN_MODE
registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings, check=False)
portal_membership = getToolByName(self.context, 'portal_membership')
if not settings.user_notification_enabled or portal_membership.isAnonymousUser():
self.widgets['user_notification'].mode = interfaces.HIDDEN_MODE
def updateActions(self):
super(CommentForm, self).updateActions()
super(CommentForm, self).updateActions()
self.actions['cancel'].addClass("standalone")
self.actions['cancel'].addClass("hide")
self.actions['comment'].addClass("context")
@button.buttonAndHandler(_(u"add_comment_button", default=u"Comment"),
self.actions['cancel'].addClass("hide")
self.actions['comment'].addClass("context")
@button.buttonAndHandler(_(u"add_comment_button", default=u"Comment"),
name='comment')
def handleComment(self, action):
context = aq_inner(self.context)
wf = getToolByName(context, 'portal_workflow')
data, errors = self.extractData()
if errors:
return
text = u""
author_name = u""
author_email = u""
user_notification = None
# Captcha check for anonymous users (if Captcha is enabled and
# Captcha check for anonymous users (if Captcha is enabled and
# anonymous commenting is allowed)
registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings, check=False)
@@ -138,10 +138,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
portal_membership.isAnonymousUser():
if not 'captcha' in data:
data['captcha'] = u""
captcha = CaptchaValidator(self.context,
self.request,
None,
ICaptcha['captcha'],
captcha = CaptchaValidator(self.context,
self.request,
None,
ICaptcha['captcha'],
None)
captcha.validate(data['captcha'])
@@ -156,10 +156,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
author_email = data['author_email']
if 'user_notification' in data:
user_notification = data['user_notification']
# The add-comment view is called on the conversation object
conversation = IConversation(self.__parent__)
# Check if conversation is enabled on this content object
if not conversation.enabled():
raise Unauthorized, "Discussion is not enabled for this content\
@@ -175,10 +175,10 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
comment.text = text
portal_membership = getToolByName(self.context, 'portal_membership')
can_reply = getSecurityManager().checkPermission('Reply to item',
context)
if portal_membership.isAnonymousUser() and \
settings.anonymous_comments:
# Anonymous Users
@@ -211,7 +211,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
"""Anonymous user tries to post a comment, but
anonymous commenting is disabled. Or user
does not have the 'reply to item' permission.""" # pragma: no cover
# Check if the added comment is a reply to an existing comment
# or just a regular reply to the content object.
if data['in_reply_to']:
@@ -221,11 +221,11 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
# Add a comment to the conversation
comment_id = conversation.addComment(comment)
# If a user posts a comment and moderation is enabled, a message is
# shown to the user that his/her comment awaits moderation. If the user
# has 'review comments' permission, he/she is redirected directly
# If a user posts a comment and moderation is enabled, a message is
# shown to the user that his/her comment awaits moderation. If the user
# has 'review comments' permission, he/she is redirected directly
# to the comment.
can_review = getSecurityManager().checkPermission('Review comments',
can_review = getSecurityManager().checkPermission('Review comments',
context)
comment_review_state = wf.getInfoFor(comment, 'review_state')
if comment_review_state == 'pending' and not can_review:
@@ -254,8 +254,8 @@ class CommentsViewlet(ViewletBase):
super(CommentsViewlet, self).update()
z2.switch_on(self, request_layer=IFormLayer)
self.form = self.form(aq_inner(self.context), self.request)
if HAS_WRAPPED_FORM:
alsoProvides(self.form, IWrappedForm)
if HAS_WRAPPED_FORM:
alsoProvides(self.form, IWrappedForm)
self.form.update()
# view methods
@@ -265,16 +265,16 @@ class CommentsViewlet(ViewletBase):
targetMimetype = 'text/html'
registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings, check=False)
mimetype = settings.text_transform
return transforms.convertTo(targetMimetype,
text,
context=self,
mimetype = settings.text_transform
return transforms.convertTo(targetMimetype,
text,
context=self,
mimetype=mimetype).getData()
def can_reply(self):
"""Returns true if current user has the 'Reply to item' permission.
"""
return getSecurityManager().checkPermission('Reply to item',
return getSecurityManager().checkPermission('Reply to item',
aq_inner(self.context))
def can_manage(self):
@@ -282,13 +282,13 @@ class CommentsViewlet(ViewletBase):
not want any API changes in beta releases.
"""
return self.can_review()
def can_review(self):
"""Returns true if current user has the 'Review comments' permission.
"""
return getSecurityManager().checkPermission('Review comments',
return getSecurityManager().checkPermission('Review comments',
aq_inner(self.context))
def is_discussion_allowed(self):
context = aq_inner(self.context)
conversation = IConversation(context)
@@ -301,7 +301,7 @@ class CommentsViewlet(ViewletBase):
"""
registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings, check=False)
if settings.text_transform == "text/x-web-intelligent":
message = translate(Message(COMMENT_DESCRIPTION_INTELLIGENT_TEXT))
else:
@@ -356,7 +356,7 @@ class CommentsViewlet(ViewletBase):
r = r.copy()
r['workflow_status'] = workflow_status
yield r
# Return all direct replies
if conversation.total_comments > 0:
if workflow_actions:
@@ -395,11 +395,11 @@ class CommentsViewlet(ViewletBase):
return settings.show_commenter_image
def is_anonymous(self):
portal_membership = getToolByName(self.context,
'portal_membership',
portal_membership = getToolByName(self.context,
'portal_membership',
None)
return portal_membership.isAnonymousUser()
def login_action(self):
return '%s/login_form?came_from=%s' % \
(self.navigation_root_url,
+2 -2
View File
@@ -70,7 +70,7 @@
class=".moderation.ModerateCommentsEnabled"
permission="zope2.View"
/>
<!-- Delete comment view -->
<browser:page
for="plone.app.discussion.interfaces.IComment"
@@ -131,4 +131,4 @@
permission="cmf.ManagePortal"
/>
</configure>
</configure>
+8 -8
View File
@@ -5,7 +5,7 @@
lang="en"
metal:use-macro="here/prefs_main_template/macros/master"
i18n:domain="plone">
<metal:block fill-slot="top_slot"
tal:define="dummy python:request.set('disable_border',1)" />
@@ -17,14 +17,14 @@
<body>
<div id="content"
<div id="content"
tal:attributes="class view/settings"
metal:fill-slot="prefs_configlet_content">
<script type="text/javascript"
tal:attributes="src string:${context/portal_url}/++resource++plone.app.discussion.javascripts/controlpanel.js">
</script>
<dl class="portalMessage warning"
tal:condition="view/mailhost_warning">
<dt i18n:translate="">
@@ -63,24 +63,24 @@
to choose a workflow for the 'Discussion Item' type.
</dd>
</dl>
<div metal:use-macro="context/global_statusmessage/macros/portal_message">
Portal status message
</div>
<a href=""
id="setup-link"
tal:attributes="href string:$portal_url/plone_control_panel"
i18n:translate="">
Site Setup
</a> &rsaquo;
<h1 class="documentFirstHeading" tal:content="view/label">View Title</h1>
<div id="layout-contents">
<span tal:replace="structure view/contents" />
</div>
</div>
</body>
</html>
+19 -19
View File
@@ -21,7 +21,7 @@ from zope.component import getMultiAdapter, queryUtility
from z3c.form import button
from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget
from plone.app.discussion.interfaces import IDiscussionSettings, _
@@ -33,7 +33,7 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
description = _(u"help_discussion_settings_editform",
default=u"Some discussion related settings are not located "
"in the Discussion Control Panel.\n"
"To enable comments for a specific content type, "
"To enable comments for a specific content type, "
"go to the Types Control Panel of this type and "
"choose \"Allow comments\".\n"
"To enable the moderation workflow for comments, "
@@ -73,18 +73,18 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
self.status = self.formErrorsMessage
return
changes = self.applyChanges(data)
IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"),
"info")
self.context.REQUEST.RESPONSE.redirect("@@discussion-settings")
@button.buttonAndHandler(_('Cancel'), name='cancel')
def handleCancel(self, action):
IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"),
IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"),
"info")
self.request.response.redirect("%s/%s" % (self.context.absolute_url(),
self.request.response.redirect("%s/%s" % (self.context.absolute_url(),
self.control_panel_view))
class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
"""Discussion settings control panel.
"""
@@ -100,22 +100,22 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
wftool = getToolByName(self.context, "portal_workflow", None)
wf = wftool.getChainForPortalType('Discussion Item')
output = []
# Globally enabled
if settings.globally_enabled:
output.append("globally_enabled")
# Comment moderation
if 'one_state_workflow' not in wf and \
'comment_review_workflow' not in wf:
output.append("moderation_custom")
output.append("moderation_custom")
elif settings.moderation_enabled:
output.append("moderation_enabled")
# Anonymous comments
if settings.anonymous_comments:
output.append("anonymous_comments")
# Invalid mail setting
ctrlOverview = getMultiAdapter((self.context, self.request),
name='overview-controlpanel')
@@ -127,7 +127,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
discussion_workflow = wftool.getChainForPortalType('Discussion Item')[0]
if discussion_workflow:
output.append(discussion_workflow)
# Merge all settings into one string
return ' '.join(output)
@@ -152,27 +152,27 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
if 'one_state_workflow' in wf or 'comment_review_workflow' in wf:
return
return True
def notify_configuration_changed(event):
"""Event subscriber that is called every time the configuration changed.
"""
portal = getSite()
wftool = getToolByName(portal, 'portal_workflow', None)
if IRecordModifiedEvent.providedBy(event):
# Discussion control panel setting changed
if event.record.fieldName == 'moderation_enabled':
# Moderation enabled has changed
if event.record.value == True:
# Enable moderation workflow
wftool.setChainForPortalTypes(('Discussion Item',),
'comment_review_workflow')
wftool.setChainForPortalTypes(('Discussion Item',),
'comment_review_workflow')
else:
# Disable moderation workflow
wftool.setChainForPortalTypes(('Discussion Item',),
wftool.setChainForPortalTypes(('Discussion Item',),
'one_state_workflow')
if IConfigurationChangedEvent.providedBy(event):
# Types control panel setting changed
if 'workflow' in event.data:
+22 -22
View File
@@ -25,22 +25,22 @@ class View(BrowserView):
out = []
self.total_comments_migrated = 0
self.total_comments_deleted = 0
dry_run = self.request.has_key("dry_run")
# This is for testing only.
# Do not use transactions during a test.
test = self.request.has_key("test")
test = self.request.has_key("test")
if not test:
transaction.begin() # pragma: no cover
catalog = getToolByName(context, 'portal_catalog')
def log(msg):
# encode string before sending it to external world
if isinstance(msg, unicode):
msg = msg.encode('utf-8') # pragma: no cover
# encode string before sending it to external world
if isinstance(msg, unicode):
msg = msg.encode('utf-8') # pragma: no cover
context.plone_log(msg)
out.append(msg)
@@ -85,9 +85,9 @@ class View(BrowserView):
# migrate all talkbacks of the reply
talkback = getattr( reply, 'talkback', None )
no_replies_left = migrate_replies(context,
new_in_reply_to,
talkback.getReplies(),
no_replies_left = migrate_replies(context,
new_in_reply_to,
talkback.getReplies(),
depth=depth+1)
if no_replies_left:
# remove reply and talkback
@@ -97,7 +97,7 @@ class View(BrowserView):
log("%sremove %s" % (indent, reply.id))
self.total_comments_deleted += 1
# Return True when all comments on a certain level have been
# Return True when all comments on a certain level have been
# migrated.
return True
@@ -113,14 +113,14 @@ class View(BrowserView):
count_comments_old = len(catalog.searchResults(
object_provides=IDiscussionResponse.\
__identifier__))
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("\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
# zcatalog would support NOT expressions.
@@ -138,7 +138,7 @@ class View(BrowserView):
if replies:
conversation = IConversation(obj)
log("\n")
log("Migrate '%s' (%s)" % (obj.Title(),
log("Migrate '%s' (%s)" % (obj.Title(),
obj.absolute_url(relative=1)))
migrate_replies(context, 0, replies)
obj = aq_parent(talkback)
@@ -152,23 +152,23 @@ class View(BrowserView):
if not test: # pragma: no cover
transaction.abort() # pragma: no cover
log("Abort transaction") # pragma: no cover
log("\n")
log("Comment migration finished.")
log("\n")
log("%s of %s comments migrated."
% (self.total_comments_migrated, count_comments_old))
if self.total_comments_migrated != count_comments_old:
log("%s comments could not be migrated."
log("%s comments could not be migrated."
% (count_comments_old - self.total_comments_migrated)) # 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
if not test:
transaction.commit() # pragma: no cover
transaction.commit() # pragma: no cover
return '\n'.join(out)
+3 -3
View File
@@ -33,11 +33,11 @@
<a i18n:name="enable_comment_workflow"
i18n:translate="message_enable_comment_workflow" href=""
tal:attributes="href string:${context/portal_url}/@@types-controlpanel?type_id=Discussion Item">
enable the 'Comment Review Workflow' for the Comment content
enable the 'Comment Review Workflow' for the Comment content
type</a> before you can moderate comments here.
</dd>
</dl>
<form tal:condition="not:items">
<fieldset id="fieldset-moderate-comments" class="formPanel">
<p id="no-comments-message" i18n:translate="message_nothing_to_moderate">
@@ -114,7 +114,7 @@
<a href=""
tal:attributes="href string:${item/getURL}/getText"
tal:condition="python:item.Description.endswith('[...]')"
i18n:translate="label_show_full_comment_text"
i18n:translate="label_show_full_comment_text"
class="show-full-comment-text">show full comment text</a>
</td>
<td class="actions">
+39 -39
View File
@@ -11,14 +11,14 @@ from Products.statusmessages.interfaces import IStatusMessage
from plone.app.discussion.interfaces import _
from plone.app.discussion.interfaces import IComment
# Begin ugly hack. It works around a ContentProviderLookupError:
# Begin ugly hack. It works around a ContentProviderLookupError:
# plone.htmlhead error caused by Zope 2 permissions.
# This error occured on Plone 3.3.x only!
#
# Source:
# Source:
# http://athenageek.wordpress.com/2008/01/08/
# contentproviderlookuperror-plonehtmlhead/
#
#
# Bug report: https://bugs.launchpad.net/zope2/+bug/176566
#
@@ -27,7 +27,7 @@ def _getContext(self): # pragma: no cover
while getattr(self, '_is_wrapperish', None):
self = self.aq_parent
return self
ZopeTwoPageTemplateFile._getContext = _getContext # pragma: no cover
# End ugly hack.
@@ -61,7 +61,7 @@ class View(BrowserView):
return text
def moderation_enabled(self):
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
content type. A 'review workflow' is characterized by implementing
a 'pending' workflow state.
"""
@@ -78,7 +78,7 @@ class View(BrowserView):
class ModerateCommentsEnabled(BrowserView):
def __call__(self):
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
"""Returns true if a 'review workflow' is enabled on 'Discussion Item'
content type. A 'review workflow' is characterized by implementing
a 'pending' workflow state.
"""
@@ -91,26 +91,26 @@ class ModerateCommentsEnabled(BrowserView):
else:
return
class DeleteComment(BrowserView):
"""Delete a comment from a conversation.
This view is always called directly on the comment object:
http://nohost/front-page/++conversation++default/1286289644723317/\
@@moderate-delete-comment
Each table row (comment) in the moderation view contains a hidden input
field with the absolute URL of the content object:
<input type="hidden"
<input type="hidden"
value="http://nohost/front-page/++conversation++default/\
1286289644723317"
1286289644723317"
name="selected_obj_paths:list">
This absolute URL is called from a jQuery method that is bind to the
'delete' button of the table row. See javascripts/moderation.js for more
details.
details.
"""
def __call__(self):
@@ -132,23 +132,23 @@ class DeleteComment(BrowserView):
class PublishComment(BrowserView):
"""Publish a comment.
This view is always called directly on the comment object:
http://nohost/front-page/++conversation++default/1286289644723317/\
@@moderate-publish-comment
Each table row (comment) in the moderation view contains a hidden input
field with the absolute URL of the content object:
<input type="hidden"
<input type="hidden"
value="http://nohost/front-page/++conversation++default/\
1286289644723317"
1286289644723317"
name="selected_obj_paths:list">
This absolute URL is called from a jQuery method that is bind to the
'delete' button of the table row. See javascripts/moderation.js for more
details.
details.
"""
def __call__(self):
@@ -171,24 +171,24 @@ class PublishComment(BrowserView):
class BulkActionsView(BrowserView):
"""Bulk actions (unapprove, approve, delete, mark as spam).
Each table row of the moderation view has a checkbox with the absolute
Each table row of the moderation view has a checkbox with the absolute
path (without host and port) of the comment objects:
<input type="checkbox"
name="paths:list"
value="/plone/front-page/++conversation++default/\
1286289644723317"
1286289644723317"
id="cb_1286289644723317" />
If checked, the comment path will occur in the 'paths' variable of
the request when the bulk actions view is called. The bulk action
(delete, publish, etc.) will be applied to all comments that are
If checked, the comment path will occur in the 'paths' variable of
the request when the bulk actions view is called. The bulk action
(delete, publish, etc.) will be applied to all comments that are
included.
The paths have to be 'traversable':
/plone/front-page/++conversation++default/1286289644723317
/plone/front-page/++conversation++default/1286289644723317
"""
@@ -219,11 +219,11 @@ class BulkActionsView(BrowserView):
def publish(self):
"""Publishes all comments in the paths variable.
Expects a list of absolute paths (without host and port):
/Plone/startseite/++conversation++default/1286200010610352
"""
context = aq_inner(self.context)
for path in self.paths:
@@ -240,12 +240,12 @@ class BulkActionsView(BrowserView):
def delete(self):
"""Deletes all comments in the paths variable.
Expects a list of absolute paths (without host and port):
/Plone/startseite/++conversation++default/1286200010610352
"""
"""
context = aq_inner(self.context)
for path in self.paths:
comment = context.restrictedTraverse(path)
+6 -6
View File
@@ -18,21 +18,21 @@ class ConversationNamespace(object):
(unnamed) adapter. This is to work around a bug in OFS.Traversable which
does not allow traversal to namespaces with an empty string name.
"""
implements(ITraversable)
adapts(Interface, IBrowserRequest)
def __init__(self, context, request=None):
self.context = context
self.request = request
def traverse(self, name, ignore):
if name == "default":
name = u""
conversation = queryAdapter(self.context, IConversation, name=name)
if conversation is None:
raise TraversalError(name) # pragma: no cover
return conversation
+2 -2
View File
@@ -49,7 +49,7 @@ class CaptchaValidator(validator.SimpleFieldValidator):
settings = registry.forInterface(IDiscussionSettings, check=False)
if settings.captcha in ('captcha', 'recaptcha', 'norobots'):
captcha = getMultiAdapter((aq_inner(self.context), self.request),
captcha = getMultiAdapter((aq_inner(self.context), self.request),
name=settings.captcha)
if not captcha.verify(input=value):
if settings.captcha == 'norobots':
@@ -61,6 +61,6 @@ class CaptchaValidator(validator.SimpleFieldValidator):
# Register Captcha validator for the Captcha field in the ICaptcha Form
validator.WidgetValidatorDiscriminators(CaptchaValidator,
validator.WidgetValidatorDiscriminators(CaptchaValidator,
field=ICaptcha['captcha'])