find -name "*.py" -exec pyupgrade --py3-only --py37-plus {} +

This commit is contained in:
Jens W. Klein 2022-05-01 23:14:41 +02:00
parent 34b758f2bd
commit 75c6a5dcc1
38 changed files with 315 additions and 361 deletions

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# #
# plone.app.discussion documentation build configuration file, created by # plone.app.discussion documentation build configuration file, created by
# sphinx-quickstart on Thu Mar 18 10:17:15 2010. # sphinx-quickstart on Thu Mar 18 10:17:15 2010.
@ -47,8 +46,8 @@ source_suffix = ".txt"
master_doc = "index" master_doc = "index"
# General information about the project. # General information about the project.
project = u"plone.app.discussion" project = "plone.app.discussion"
copyright = u"2010, Timo Stollenwerk - Plone Foundation" copyright = "2010, Timo Stollenwerk - Plone Foundation"
# The version info for the project you're documenting, acts as replacement for # The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the # |version| and |release|, also used in various other places throughout the
@ -185,8 +184,8 @@ latex_documents = [
( (
"index", "index",
"ploneappdiscussion.tex", "ploneappdiscussion.tex",
u"plone.app.discussion Documentation", "plone.app.discussion Documentation",
u"Timo Stollenwerk", "Timo Stollenwerk",
"manual", "manual",
), ),
] ]

View File

@ -1,2 +1 @@
# -*- coding: utf-8 -*-
__import__("pkg_resources").declare_namespace(__name__) __import__("pkg_resources").declare_namespace(__name__)

View File

@ -1,2 +1 @@
# -*- coding: utf-8 -*-
__import__("pkg_resources").declare_namespace(__name__) __import__("pkg_resources").declare_namespace(__name__)

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from zope.i18nmessageid import MessageFactory from zope.i18nmessageid import MessageFactory

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Captcha validator, see captcha.txt for design notes. # Captcha validator, see captcha.txt for design notes.
from persistent import Persistent from persistent import Persistent
from plone.app.discussion.browser.comments import CommentForm from plone.app.discussion.browser.comments import CommentForm
@ -23,7 +22,7 @@ from zope.publisher.interfaces.browser import IDefaultBrowserLayer
class Captcha(Persistent): class Captcha(Persistent):
"""Captcha input field.""" """Captcha input field."""
captcha = u"" captcha = ""
Captcha = factory(Captcha) Captcha = factory(Captcha)

View File

@ -1,4 +1,3 @@
# coding: utf-8
from .comments import CommentForm from .comments import CommentForm
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
from Acquisition import aq_inner from Acquisition import aq_inner
@ -48,9 +47,9 @@ class View(BrowserView):
will redirect right to the binary object, bypassing comments. will redirect right to the binary object, bypassing comments.
""" """
if obj.portal_type in view_action_types: if obj.portal_type in view_action_types:
url = "{0}/view".format(url) url = f"{url}/view"
self.request.response.redirect("{0}#{1}".format(url, context.id)) self.request.response.redirect(f"{url}#{context.id}")
class EditCommentForm(CommentForm): class EditCommentForm(CommentForm):
@ -58,10 +57,10 @@ class EditCommentForm(CommentForm):
ignoreContext = True ignoreContext = True
id = "edit-comment-form" id = "edit-comment-form"
label = _(u"edit_comment_form_title", default=u"Edit comment") label = _("edit_comment_form_title", default="Edit comment")
def updateWidgets(self): def updateWidgets(self):
super(EditCommentForm, self).updateWidgets() super().updateWidgets()
self.widgets["text"].value = self.context.text self.widgets["text"].value = self.context.text
# We have to rename the id, otherwise TinyMCE can't initialize # We have to rename the id, otherwise TinyMCE can't initialize
# because there are two textareas with the same id. # because there are two textareas with the same id.
@ -70,12 +69,12 @@ class EditCommentForm(CommentForm):
def _redirect(self, target=""): def _redirect(self, target=""):
if not target: if not target:
portal_state = getMultiAdapter( portal_state = getMultiAdapter(
(self.context, self.request), name=u"plone_portal_state" (self.context, self.request), name="plone_portal_state"
) )
target = portal_state.portal_url() target = portal_state.portal_url()
self.request.response.redirect(target) self.request.response.redirect(target)
@button.buttonAndHandler(_(u"label_save", default=u"Save"), name="comment") @button.buttonAndHandler(_("label_save", default="Save"), name="comment")
def handleComment(self, action): def handleComment(self, action):
# Validate form # Validate form
@ -96,14 +95,14 @@ class EditCommentForm(CommentForm):
# Redirect to comment # Redirect to comment
IStatusMessage(self.request).add( IStatusMessage(self.request).add(
_(u"comment_edit_notification", default="Comment was edited"), type="info" _("comment_edit_notification", default="Comment was edited"), type="info"
) )
return self._redirect(target=self.action.replace("@@edit-comment", "@@view")) return self._redirect(target=self.action.replace("@@edit-comment", "@@view"))
@button.buttonAndHandler(_(u"cancel_form_button", default=u"Cancel"), name="cancel") @button.buttonAndHandler(_("cancel_form_button", default="Cancel"), name="cancel")
def handle_cancel(self, action): def handle_cancel(self, action):
IStatusMessage(self.request).add( IStatusMessage(self.request).add(
_(u"comment_edit_cancel_notification", default=u"Edit comment cancelled"), _("comment_edit_cancel_notification", default="Edit comment cancelled"),
type="info", type="info",
) )
return self._redirect(target=self.context.absolute_url()) return self._redirect(target=self.context.absolute_url())

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
from AccessControl import Unauthorized from AccessControl import Unauthorized
from Acquisition import aq_inner from Acquisition import aq_inner
@ -35,28 +34,28 @@ from zope.interface import alsoProvides
COMMENT_DESCRIPTION_PLAIN_TEXT = _( COMMENT_DESCRIPTION_PLAIN_TEXT = _(
u"comment_description_plain_text", "comment_description_plain_text",
default=u"You can add a comment by filling out the form below. " default="You can add a comment by filling out the form below. "
u"Plain text formatting.", "Plain text formatting.",
) )
COMMENT_DESCRIPTION_MARKDOWN = _( COMMENT_DESCRIPTION_MARKDOWN = _(
u"comment_description_markdown", "comment_description_markdown",
default=u"You can add a comment by filling out the form below. " default="You can add a comment by filling out the form below. "
u"Plain text formatting. You can use the Markdown syntax for " "Plain text formatting. You can use the Markdown syntax for "
u"links and images.", "links and images.",
) )
COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _( COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _(
u"comment_description_intelligent_text", "comment_description_intelligent_text",
default=u"You can add a comment by filling out the form below. " default="You can add a comment by filling out the form below. "
u"Plain text formatting. Web and email addresses are " "Plain text formatting. Web and email addresses are "
u"transformed into clickable links.", "transformed into clickable links.",
) )
COMMENT_DESCRIPTION_MODERATION_ENABLED = _( COMMENT_DESCRIPTION_MODERATION_ENABLED = _(
u"comment_description_moderation_enabled", "comment_description_moderation_enabled",
default=u"Comments are moderated.", default="Comments are moderated.",
) )
@ -64,7 +63,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
ignoreContext = True # don't use context to get widget data ignoreContext = True # don't use context to get widget data
id = None id = None
label = _(u"Add a comment") label = _("Add a comment")
fields = field.Fields(IComment).omit( fields = field.Fields(IComment).omit(
"portal_type", "portal_type",
"__parent__", "__parent__",
@ -79,16 +78,16 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
) )
def updateFields(self): def updateFields(self):
super(CommentForm, self).updateFields() super().updateFields()
self.fields["user_notification"].widgetFactory = SingleCheckBoxFieldWidget self.fields["user_notification"].widgetFactory = SingleCheckBoxFieldWidget
def updateWidgets(self): def updateWidgets(self):
super(CommentForm, self).updateWidgets() super().updateWidgets()
# Widgets # Widgets
self.widgets["in_reply_to"].mode = interfaces.HIDDEN_MODE self.widgets["in_reply_to"].mode = interfaces.HIDDEN_MODE
self.widgets["text"].addClass("autoresize") self.widgets["text"].addClass("autoresize")
self.widgets["user_notification"].label = _(u"") self.widgets["user_notification"].label = _("")
# Reset widget field settings to their defaults, which may be changed # Reset widget field settings to their defaults, which may be changed
# further on. Otherwise, the email field might get set to required # further on. Otherwise, the email field might get set to required
# when an anonymous user visits, and then remain required when an # when an anonymous user visits, and then remain required when an
@ -140,7 +139,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
self.widgets["user_notification"].mode = interfaces.HIDDEN_MODE self.widgets["user_notification"].mode = interfaces.HIDDEN_MODE
def updateActions(self): def updateActions(self):
super(CommentForm, self).updateActions() super().updateActions()
self.actions["cancel"].addClass("btn btn-secondary") self.actions["cancel"].addClass("btn btn-secondary")
self.actions["cancel"].addClass("hide") self.actions["cancel"].addClass("hide")
self.actions["comment"].addClass("btn btn-primary") self.actions["comment"].addClass("btn btn-primary")
@ -148,7 +147,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
def get_author(self, data): def get_author(self, data):
context = aq_inner(self.context) context = aq_inner(self.context)
# some attributes are not always set # some attributes are not always set
author_name = u"" author_name = ""
# Make sure author_name/ author_email is properly encoded # Make sure author_name/ author_email is properly encoded
if "author_name" in data: if "author_name" in data:
@ -219,16 +218,14 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
else: # pragma: no cover else: # pragma: no cover
raise Unauthorized( raise Unauthorized(
u"Anonymous user tries to post a comment, but anonymous " "Anonymous user tries to post a comment, but anonymous "
u"commenting is disabled. Or user does not have the " "commenting is disabled. Or user does not have the "
u"'reply to item' permission.", "'reply to item' permission.",
) )
return comment return comment
@button.buttonAndHandler( @button.buttonAndHandler(_("add_comment_button", default="Comment"), name="comment")
_(u"add_comment_button", default=u"Comment"), name="comment"
)
def handleComment(self, action): def handleComment(self, action):
context = aq_inner(self.context) context = aq_inner(self.context)
@ -254,7 +251,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
anon = portal_membership.isAnonymousUser() anon = portal_membership.isAnonymousUser()
if captcha_enabled and anonymous_comments and anon: if captcha_enabled and anonymous_comments and anon:
if "captcha" not in data: if "captcha" not in data:
data["captcha"] = u"" data["captcha"] = ""
captcha = CaptchaValidator( captcha = CaptchaValidator(
self.context, self.request, None, ICaptcha["captcha"], None self.context, self.request, None, ICaptcha["captcha"], None
) )
@ -296,7 +293,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
# Redirect to comment (inside a content object page) # Redirect to comment (inside a content object page)
self.request.response.redirect(self.action + "#" + str(comment_id)) self.request.response.redirect(self.action + "#" + str(comment_id))
@button.buttonAndHandler(_(u"Cancel")) @button.buttonAndHandler(_("Cancel"))
def handleCancel(self, action): def handleCancel(self, action):
# This method should never be called, it's only there to show # This method should never be called, it's only there to show
# a cancel button that is handled by a jQuery method. # a cancel button that is handled by a jQuery method.
@ -309,7 +306,7 @@ class CommentsViewlet(ViewletBase):
index = ViewPageTemplateFile("comments.pt") index = ViewPageTemplateFile("comments.pt")
def update(self): def update(self):
super(CommentsViewlet, self).update() super().update()
discussion_allowed = self.is_discussion_allowed() discussion_allowed = self.is_discussion_allowed()
anonymous_allowed_or_can_reply = ( anonymous_allowed_or_can_reply = (
self.is_anonymous() self.is_anonymous()
@ -483,7 +480,7 @@ class CommentsViewlet(ViewletBase):
if username is None: if username is None:
return None return None
else: else:
return "{0}/author/{1}".format(self.context.portal_url(), username) return f"{self.context.portal_url()}/author/{username}"
def get_commenter_portrait(self, username=None): def get_commenter_portrait(self, username=None):
@ -523,7 +520,7 @@ class CommentsViewlet(ViewletBase):
return portal_membership.isAnonymousUser() return portal_membership.isAnonymousUser()
def login_action(self): def login_action(self):
return "{0}/login_form?came_from={1}".format( return "{}/login_form?came_from={}".format(
self.navigation_root_url, self.navigation_root_url,
quote(self.request.get("URL", "")), quote(self.request.get("URL", "")),
) )

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import _ from plone.app.discussion.interfaces import _
from plone.app.discussion.interfaces import IDiscussionSettings from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.upgrades import update_registry from plone.app.discussion.upgrades import update_registry
@ -32,22 +31,22 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
schema = IDiscussionSettings schema = IDiscussionSettings
id = "DiscussionSettingsEditForm" id = "DiscussionSettingsEditForm"
label = _(u"Discussion settings") label = _("Discussion settings")
description = _( description = _(
u"help_discussion_settings_editform", "help_discussion_settings_editform",
default=u"Some discussion related settings are not " default="Some discussion related settings are not "
u"located in the Discussion Control Panel.\n" "located in the Discussion Control Panel.\n"
u"To enable comments for a specific content type, " "To enable comments for a specific content type, "
u"go to the Types Control Panel of this type and " "go to the Types Control Panel of this type and "
u'choose "Allow comments".\n' 'choose "Allow comments".\n'
u"To enable the moderation workflow for comments, " "To enable the moderation workflow for comments, "
u"go to the Types Control Panel, choose " "go to the Types Control Panel, choose "
u'"Comment" and set workflow to ' '"Comment" and set workflow to '
u'"Comment Review Workflow".', '"Comment Review Workflow".',
) )
def updateFields(self): def updateFields(self):
super(DiscussionSettingsEditForm, self).updateFields() super().updateFields()
self.fields["globally_enabled"].widgetFactory = SingleCheckBoxFieldWidget self.fields["globally_enabled"].widgetFactory = SingleCheckBoxFieldWidget
self.fields["moderation_enabled"].widgetFactory = SingleCheckBoxFieldWidget self.fields["moderation_enabled"].widgetFactory = SingleCheckBoxFieldWidget
self.fields["edit_comment_enabled"].widgetFactory = SingleCheckBoxFieldWidget self.fields["edit_comment_enabled"].widgetFactory = SingleCheckBoxFieldWidget
@ -65,20 +64,20 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
def updateWidgets(self): def updateWidgets(self):
try: try:
super(DiscussionSettingsEditForm, self).updateWidgets() super().updateWidgets()
except KeyError: except KeyError:
# upgrade profile not visible in prefs_install_products_form # upgrade profile not visible in prefs_install_products_form
# provide auto-upgrade # provide auto-upgrade
update_registry(self.context) update_registry(self.context)
super(DiscussionSettingsEditForm, self).updateWidgets() super().updateWidgets()
self.widgets["globally_enabled"].label = _(u"Enable Comments") self.widgets["globally_enabled"].label = _("Enable Comments")
self.widgets["anonymous_comments"].label = _(u"Anonymous Comments") self.widgets["anonymous_comments"].label = _("Anonymous Comments")
self.widgets["show_commenter_image"].label = _(u"Commenter Image") self.widgets["show_commenter_image"].label = _("Commenter Image")
self.widgets["moderator_notification_enabled"].label = _( self.widgets["moderator_notification_enabled"].label = _(
u"Moderator Email Notification", "Moderator Email Notification",
) )
self.widgets["user_notification_enabled"].label = _( self.widgets["user_notification_enabled"].label = _(
u"User Email Notification", "User Email Notification",
) )
@button.buttonAndHandler(_("Save"), name=None) @button.buttonAndHandler(_("Save"), name=None)
@ -88,14 +87,14 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
self.status = self.formErrorsMessage self.status = self.formErrorsMessage
return return
self.applyChanges(data) self.applyChanges(data)
IStatusMessage(self.request).addStatusMessage(_(u"Changes saved"), "info") IStatusMessage(self.request).addStatusMessage(_("Changes saved"), "info")
self.context.REQUEST.RESPONSE.redirect("@@discussion-controlpanel") self.context.REQUEST.RESPONSE.redirect("@@discussion-controlpanel")
@button.buttonAndHandler(_("Cancel"), name="cancel") @button.buttonAndHandler(_("Cancel"), name="cancel")
def handleCancel(self, action): def handleCancel(self, action):
IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"), "info") IStatusMessage(self.request).addStatusMessage(_("Edit cancelled"), "info")
self.request.response.redirect( self.request.response.redirect(
"{0}/{1}".format( "{}/{}".format(
self.context.absolute_url(), self.context.absolute_url(),
self.control_panel_view, self.control_panel_view,
), ),
@ -111,7 +110,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
def __call__(self): def __call__(self):
self.mailhost_warning() self.mailhost_warning()
self.custom_comment_workflow_warning() self.custom_comment_workflow_warning()
return super(DiscussionSettingsControlPanel, self).__call__() return super().__call__()
@property @property
def site_url(self): def site_url(self):
@ -180,8 +179,8 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
pass pass
else: else:
message = _( message = _(
u"discussion_text_no_mailhost_configured", "discussion_text_no_mailhost_configured",
default=u"You have not configured a mail host or a site 'From' address, various features including contact forms, email notification and password reset will not work. Go to the E-Mail Settings to fix this.", default="You have not configured a mail host or a site 'From' address, various features including contact forms, email notification and password reset will not work. Go to the E-Mail Settings to fix this.",
) # noqa: E501 ) # noqa: E501
IStatusMessage(self.request).addStatusMessage(message, "warning") IStatusMessage(self.request).addStatusMessage(message, "warning")
@ -195,8 +194,8 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
pass pass
else: else:
message = _( message = _(
u"discussion_text_custom_comment_workflow", "discussion_text_custom_comment_workflow",
default=u"You have configured a custom workflow for the 'Discussion Item' content type. You can enable/disable the comment moderation in this control panel only if you use one of the default 'Discussion Item' workflows. Go to the Types control panel to choose a workflow for the 'Discussion Item' type.", default="You have configured a custom workflow for the 'Discussion Item' content type. You can enable/disable the comment moderation in this control panel only if you use one of the default 'Discussion Item' workflows. Go to the Types control panel to choose a workflow for the 'Discussion Item' type.",
) # noqa: E501 ) # noqa: E501
IStatusMessage(self.request).addStatusMessage(message, "warning") IStatusMessage(self.request).addStatusMessage(message, "warning")

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from Acquisition import aq_base from Acquisition import aq_base
from Acquisition import aq_chain from Acquisition import aq_chain
from Acquisition import aq_inner from Acquisition import aq_inner
@ -34,7 +33,7 @@ def traverse_parents(context):
return None return None
class ConversationView(object): class ConversationView:
def enabled(self): def enabled(self):
if DEXTERITY_INSTALLED and IDexterityContent.providedBy(self.context): if DEXTERITY_INSTALLED and IDexterityContent.providedBy(self.context):
return self._enabled_for_dexterity_types() return self._enabled_for_dexterity_types()

View File

@ -1,4 +1,3 @@
# coding: utf-8
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
from AccessControl import Unauthorized from AccessControl import Unauthorized
from Acquisition import aq_inner from Acquisition import aq_inner
@ -51,7 +50,7 @@ class View(BrowserView):
pass pass
def __init__(self, context, request): def __init__(self, context, request):
super(View, self).__init__(context, request) super().__init__(context, request)
self.workflowTool = getToolByName(self.context, "portal_workflow") self.workflowTool = getToolByName(self.context, "portal_workflow")
self.transitions = [] self.transitions = []
@ -229,7 +228,7 @@ class DeleteOwnComment(DeleteComment):
def __call__(self): def __call__(self):
if self.can_delete(): if self.can_delete():
super(DeleteOwnComment, self).__call__() super().__call__()
else: else:
raise Unauthorized("You're not allowed to delete this comment.") raise Unauthorized("You're not allowed to delete this comment.")
@ -318,7 +317,7 @@ class BulkActionsView(BrowserView):
""" """
def __init__(self, context, request): def __init__(self, context, request):
super(BulkActionsView, self).__init__(context, request) super().__init__(context, request)
self.workflowTool = getToolByName(context, "portal_workflow") self.workflowTool = getToolByName(context, "portal_workflow")
def __call__(self): def __call__(self):

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Implement the ++comments++ traversal namespace. This should return the """Implement the ++comments++ traversal namespace. This should return the
IDiscussion container for the context, from which traversal will continue IDiscussion container for the context, from which traversal will continue
into an actual comment object. into an actual comment object.
@ -15,7 +14,7 @@ from zope.traversing.interfaces import TraversalError
@implementer(ITraversable) @implementer(ITraversable)
@adapter(Interface, IBrowserRequest) @adapter(Interface, IBrowserRequest)
class ConversationNamespace(object): class ConversationNamespace:
"""Allow traversal into a conversation via a ++conversation++name """Allow traversal into a conversation via a ++conversation++name
namespace. The name is the name of an adapter from context to namespace. The name is the name of an adapter from context to
IConversation. The special name 'default' will be taken as the default IConversation. The special name 'default' will be taken as the default
@ -30,7 +29,7 @@ class ConversationNamespace(object):
def traverse(self, name, ignore): def traverse(self, name, ignore):
if name == "default": if name == "default":
name = u"" name = ""
conversation = queryAdapter(self.context, IConversation, name=name) conversation = queryAdapter(self.context, IConversation, name=name)
if conversation is None: if conversation is None:

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Captcha validator, see captcha.txt for design notes. """Captcha validator, see captcha.txt for design notes.
""" """
from Acquisition import aq_inner from Acquisition import aq_inner
@ -39,7 +38,7 @@ class CaptchaValidator(validator.SimpleFieldValidator):
# We adapt the CaptchaValidator class to all form fields (IField) # We adapt the CaptchaValidator class to all form fields (IField)
def validate(self, value): def validate(self, value):
super(CaptchaValidator, self).validate(value) super().validate(value)
registry = queryUtility(IRegistry) registry = queryUtility(IRegistry)
settings = registry.forInterface(IDiscussionSettings, check=False) settings = registry.forInterface(IDiscussionSettings, check=False)

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Catalog indexers, using plone.indexer. These will populate standard catalog """Catalog indexers, using plone.indexer. These will populate standard catalog
indexes with values based on the IComment interface. indexes with values based on the IComment interface.

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""The default comment class and factory. """The default comment class and factory.
""" """
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
@ -44,28 +43,28 @@ import six
COMMENT_TITLE = _( COMMENT_TITLE = _(
u"comment_title", "comment_title",
default=u"${author_name} on ${content}", default="${author_name} on ${content}",
) )
MAIL_NOTIFICATION_MESSAGE = _( MAIL_NOTIFICATION_MESSAGE = _(
u"mail_notification_message", "mail_notification_message",
default=u'A comment on "${title}" ' default='A comment on "${title}" '
u"has been posted here: ${link}\n\n" "has been posted here: ${link}\n\n"
u"---\n" "---\n"
u"${text}\n" "${text}\n"
u"---\n", "---\n",
) )
MAIL_NOTIFICATION_MESSAGE_MODERATOR = _( MAIL_NOTIFICATION_MESSAGE_MODERATOR = _(
u"mail_notification_message_moderator2", "mail_notification_message_moderator2",
default=u'A comment on "${title}" ' default='A comment on "${title}" '
u"has been posted by ${commentator}\n" "has been posted by ${commentator}\n"
u"here: ${link}\n\n" "here: ${link}\n\n"
u"---\n\n" "---\n\n"
u"${text}\n\n" "${text}\n\n"
u"---\n\n" "---\n\n"
u"Log in to moderate.\n\n", "Log in to moderate.\n\n",
) )
logger = logging.getLogger("plone.app.discussion") logger = logging.getLogger("plone.app.discussion")
@ -100,10 +99,10 @@ class Comment(
comment_id = None # long comment_id = None # long
in_reply_to = None # long in_reply_to = None # long
title = u"" title = ""
mime_type = None mime_type = None
text = u"" text = ""
creator = None creator = None
creation_date = None creation_date = None
@ -137,7 +136,7 @@ class Comment(
@property @property
def __name__(self): def __name__(self):
return self.comment_id and six.text_type(self.comment_id) or None return self.comment_id and str(self.comment_id) or None
@property @property
def id(self): def id(self):
@ -162,7 +161,7 @@ class Comment(
text = self.text text = self.text
if text is None: if text is None:
return "" return ""
if six.PY2 and isinstance(text, six.text_type): if six.PY2 and isinstance(text, str):
text = text.encode("utf8") text = text.encode("utf8")
transform = transforms.convertTo( transform = transforms.convertTo(
targetMimetype, text, context=self, mimetype=sourceMimetype targetMimetype, text, context=self, mimetype=sourceMimetype
@ -172,8 +171,8 @@ class Comment(
else: else:
logger = logging.getLogger("plone.app.discussion") logger = logging.getLogger("plone.app.discussion")
msg = ( msg = (
u'Transform "{0}" => "{1}" not available. Failed to ' 'Transform "{0}" => "{1}" not available. Failed to '
u'transform comment "{2}".' 'transform comment "{2}".'
) )
logger.error( logger.error(
msg.format( msg.format(
@ -194,8 +193,8 @@ class Comment(
author_name = translate( author_name = translate(
Message( Message(
_( _(
u"label_anonymous", "label_anonymous",
default=u"Anonymous", default="Anonymous",
), ),
), ),
) )
@ -373,7 +372,7 @@ def notify_user(obj, event):
if not emails: if not emails:
return return
subject = translate(_(u"A comment has been posted."), context=obj.REQUEST) subject = translate(_("A comment has been posted."), context=obj.REQUEST)
message = translate( message = translate(
Message( Message(
MAIL_NOTIFICATION_MESSAGE, MAIL_NOTIFICATION_MESSAGE,
@ -441,7 +440,7 @@ def notify_moderator(obj, event):
content_object = aq_parent(conversation) content_object = aq_parent(conversation)
# Compose email # Compose email
subject = translate(_(u"A comment has been posted."), context=obj.REQUEST) subject = translate(_("A comment has been posted."), context=obj.REQUEST)
message = translate( message = translate(
Message( Message(
MAIL_NOTIFICATION_MESSAGE_MODERATOR, MAIL_NOTIFICATION_MESSAGE_MODERATOR,
@ -453,8 +452,8 @@ def notify_moderator(obj, event):
or translate( or translate(
Message( Message(
_( _(
u"label_anonymous", "label_anonymous",
default=u"Anonymous", default="Anonymous",
), ),
), ),
), ),

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
""" Content rules handlers """ Content rules handlers
""" """
from plone.app.discussion import _ from plone.app.discussion import _
@ -8,7 +7,7 @@ try:
from plone.stringinterp.adapters import BaseSubstitution from plone.stringinterp.adapters import BaseSubstitution
except ImportError: except ImportError:
class BaseSubstitution(object): class BaseSubstitution:
"""Fallback class if plone.stringinterp is not available""" """Fallback class if plone.stringinterp is not available"""
def __init__(self, context, **kwargs): def __init__(self, context, **kwargs):
@ -32,7 +31,7 @@ class CommentSubstitution(BaseSubstitution):
"""Comment string substitution""" """Comment string substitution"""
def __init__(self, context, **kwargs): def __init__(self, context, **kwargs):
super(CommentSubstitution, self).__init__(context, **kwargs) super().__init__(context, **kwargs)
@property @property
def event(self): def event(self):
@ -48,53 +47,53 @@ class CommentSubstitution(BaseSubstitution):
class Id(CommentSubstitution): class Id(CommentSubstitution):
"""Comment id string substitution""" """Comment id string substitution"""
category = _(u"Comments") category = _("Comments")
description = _(u"Comment id") description = _("Comment id")
def safe_call(self): def safe_call(self):
"""Safe call""" """Safe call"""
return getattr(self.comment, "comment_id", u"") return getattr(self.comment, "comment_id", "")
class Text(CommentSubstitution): class Text(CommentSubstitution):
"""Comment text""" """Comment text"""
category = _(u"Comments") category = _("Comments")
description = _(u"Comment text") description = _("Comment text")
def safe_call(self): def safe_call(self):
"""Safe call""" """Safe call"""
return getattr(self.comment, "text", u"") return getattr(self.comment, "text", "")
class AuthorUserName(CommentSubstitution): class AuthorUserName(CommentSubstitution):
"""Comment author user name string substitution""" """Comment author user name string substitution"""
category = _(u"Comments") category = _("Comments")
description = _(u"Comment author user name") description = _("Comment author user name")
def safe_call(self): def safe_call(self):
"""Safe call""" """Safe call"""
return getattr(self.comment, "author_username", u"") return getattr(self.comment, "author_username", "")
class AuthorFullName(CommentSubstitution): class AuthorFullName(CommentSubstitution):
"""Comment author full name string substitution""" """Comment author full name string substitution"""
category = _(u"Comments") category = _("Comments")
description = _(u"Comment author full name") description = _("Comment author full name")
def safe_call(self): def safe_call(self):
"""Safe call""" """Safe call"""
return getattr(self.comment, "author_name", u"") return getattr(self.comment, "author_name", "")
class AuthorEmail(CommentSubstitution): class AuthorEmail(CommentSubstitution):
"""Comment author email string substitution""" """Comment author email string substitution"""
category = _(u"Comments") category = _("Comments")
description = _(u"Comment author email") description = _("Comment author email")
def safe_call(self): def safe_call(self):
"""Safe call""" """Safe call"""
return getattr(self.comment, "author_email", u"") return getattr(self.comment, "author_email", "")

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""The conversation and replies adapters """The conversation and replies adapters
The conversation is responsible for storing all comments. It provides a The conversation is responsible for storing all comments. It provides a
@ -130,8 +129,7 @@ class Conversation(Traversable, Persistent, Explicit):
children = self._children.get(comment_id, None) children = self._children.get(comment_id, None)
if children is not None: if children is not None:
for child_id in children: for child_id in children:
for value in recurse(child_id, d + 1): yield from recurse(child_id, d + 1)
yield value
# Find top level threads # Find top level threads
comments = self._children.get(root, None) comments = self._children.get(root, None)
@ -145,8 +143,7 @@ class Conversation(Traversable, Persistent, Explicit):
return return
# Let the closure recurse # Let the closure recurse
for value in recurse(comment_id): yield from recurse(comment_id)
yield value
def addComment(self, comment): def addComment(self, comment):
"""Add a new comment. The parent id should have been set already. The """Add a new comment. The parent id should have been set already. The
@ -276,14 +273,14 @@ class Conversation(Traversable, Persistent, Explicit):
return [v.__of__(self) for v in self._comments.values()] return [v.__of__(self) for v in self._comments.values()]
def iterkeys(self): def iterkeys(self):
return six.iterkeys(self._comments) return self._comments.keys()
def itervalues(self): def itervalues(self):
for v in six.itervalues(self._comments): for v in self._comments.values():
yield v.__of__(self) yield v.__of__(self)
def iteritems(self): def iteritems(self):
for k, v in six.iteritems(self._comments): for k, v in self._comments.items():
yield ( yield (
k, k,
v.__of__(self), v.__of__(self),
@ -332,7 +329,7 @@ else:
@implementer(IReplies) @implementer(IReplies)
@adapter(Conversation) # relies on implementation details @adapter(Conversation) # relies on implementation details
class ConversationReplies(object): class ConversationReplies:
"""An IReplies adapter for conversations. """An IReplies adapter for conversations.
This makes it easy to work with top-level comments. This makes it easy to work with top-level comments.

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
""" Custom discussion events """ Custom discussion events
""" """
from plone.app.discussion.interfaces import ICommentAddedEvent from plone.app.discussion.interfaces import ICommentAddedEvent
@ -15,7 +14,7 @@ from zope.interface import implementer
@implementer(IDiscussionEvent) @implementer(IDiscussionEvent)
class DiscussionEvent(object): class DiscussionEvent:
"""Custom event""" """Custom event"""
def __init__(self, context, comment, **kwargs): def __init__(self, context, comment, **kwargs):

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Interfaces for plone.app.discussion """Interfaces for plone.app.discussion
""" """
from plone.app.discussion import _ from plone.app.discussion import _
@ -42,24 +41,24 @@ class IConversation(IIterableMapping):
""" """
total_comments = schema.Int( total_comments = schema.Int(
title=_(u"Total number of public comments on this item"), title=_("Total number of public comments on this item"),
min=0, min=0,
readonly=True, readonly=True,
) )
last_comment_date = schema.Date( last_comment_date = schema.Date(
title=_(u"Date of the most recent public comment"), title=_("Date of the most recent public comment"),
readonly=True, readonly=True,
) )
commentators = schema.Set( commentators = schema.Set(
title=_(u"The set of unique commentators (usernames)"), title=_("The set of unique commentators (usernames)"),
readonly=True, readonly=True,
) )
public_commentators = schema.Set( public_commentators = schema.Set(
title=_( title=_(
u"The set of unique commentators (usernames) " u"of published_comments", "The set of unique commentators (usernames) " "of published_comments",
), ),
readonly=True, readonly=True,
) )
@ -138,58 +137,58 @@ class IComment(Interface):
""" """
portal_type = schema.ASCIILine( portal_type = schema.ASCIILine(
title=_(u"Portal type"), title=_("Portal type"),
default="Discussion Item", default="Discussion Item",
) )
__parent__ = schema.Object(title=_(u"Conversation"), schema=Interface) __parent__ = schema.Object(title=_("Conversation"), schema=Interface)
__name__ = schema.TextLine(title=_(u"Name")) __name__ = schema.TextLine(title=_("Name"))
comment_id = schema.Int(title=_(u"A comment id unique to this conversation")) comment_id = schema.Int(title=_("A comment id unique to this conversation"))
in_reply_to = schema.Int( in_reply_to = schema.Int(
title=_(u"Id of comment this comment is in reply to"), title=_("Id of comment this comment is in reply to"),
required=False, required=False,
) )
# for logged in comments - set to None for anonymous # for logged in comments - set to None for anonymous
author_username = schema.TextLine(title=_(u"Name"), required=False) author_username = schema.TextLine(title=_("Name"), required=False)
# for anonymous comments only, set to None for logged in comments # for anonymous comments only, set to None for logged in comments
author_name = schema.TextLine(title=_(u"Name"), required=False) author_name = schema.TextLine(title=_("Name"), required=False)
author_email = schema.TextLine( author_email = schema.TextLine(
title=_(u"Email"), title=_("Email"),
required=False, required=False,
constraint=isEmail, constraint=isEmail,
) )
title = schema.TextLine(title=_(u"label_subject", default=u"Subject")) title = schema.TextLine(title=_("label_subject", default="Subject"))
mime_type = schema.ASCIILine(title=_(u"MIME type"), default="text/plain") mime_type = schema.ASCIILine(title=_("MIME type"), default="text/plain")
text = schema.Text( text = schema.Text(
title=_( title=_(
u"label_comment", "label_comment",
default=u"Comment", default="Comment",
), ),
) )
user_notification = schema.Bool( user_notification = schema.Bool(
title=_( title=_(
u"Notify me of new comments via email.", "Notify me of new comments via email.",
), ),
required=False, required=False,
) )
creator = schema.TextLine(title=_(u"Username of the commenter")) creator = schema.TextLine(title=_("Username of the commenter"))
creation_date = schema.Date(title=_(u"Creation date")) creation_date = schema.Date(title=_("Creation date"))
modification_date = schema.Date(title=_(u"Modification date")) modification_date = schema.Date(title=_("Modification date"))
class ICaptcha(Interface): class ICaptcha(Interface):
"""Captcha/ReCaptcha text field to extend the existing comment form.""" """Captcha/ReCaptcha text field to extend the existing comment form."""
captcha = schema.TextLine(title=_(u"Captcha"), required=False) captcha = schema.TextLine(title=_("Captcha"), required=False)
class IDiscussionSettings(Interface): class IDiscussionSettings(Interface):
@ -204,26 +203,26 @@ class IDiscussionSettings(Interface):
# - Search control panel: Show comments in search results # - Search control panel: Show comments in search results
globally_enabled = schema.Bool( globally_enabled = schema.Bool(
title=_(u"label_globally_enabled", default=u"Globally enable comments"), title=_("label_globally_enabled", default="Globally enable comments"),
description=_( description=_(
u"help_globally_enabled", "help_globally_enabled",
default=u"If selected, users are able to post comments on the " default="If selected, users are able to post comments on the "
u"site. However, you will still need to enable comments " "site. However, you will still need to enable comments "
u"for specific content types, folders or content " "for specific content types, folders or content "
u"objects before users will be able to post comments.", "objects before users will be able to post comments.",
), ),
required=False, required=False,
default=False, default=False,
) )
anonymous_comments = schema.Bool( anonymous_comments = schema.Bool(
title=_(u"label_anonymous_comments", default="Enable anonymous comments"), title=_("label_anonymous_comments", default="Enable anonymous comments"),
description=_( description=_(
u"help_anonymous_comments", "help_anonymous_comments",
default=u"If selected, anonymous users are able to post " default="If selected, anonymous users are able to post "
u"comments without logging in. It is highly " "comments without logging in. It is highly "
u"recommended to use a captcha solution to prevent " "recommended to use a captcha solution to prevent "
u"spam if this setting is enabled.", "spam if this setting is enabled.",
), ),
required=False, required=False,
default=False, default=False,
@ -231,11 +230,11 @@ class IDiscussionSettings(Interface):
anonymous_email_enabled = schema.Bool( anonymous_email_enabled = schema.Bool(
title=_( title=_(
u"label_anonymous_email_enabled", default=u"Enable anonymous email field" "label_anonymous_email_enabled", default="Enable anonymous email field"
), ),
description=_( description=_(
u"help_anonymous_email_enabled", "help_anonymous_email_enabled",
default=u"If selected, anonymous user will have to " u"give their email.", default="If selected, anonymous user will have to " "give their email.",
), ),
required=False, required=False,
default=False, default=False,
@ -243,28 +242,28 @@ class IDiscussionSettings(Interface):
moderation_enabled = schema.Bool( moderation_enabled = schema.Bool(
title=_( title=_(
u"label_moderation_enabled", "label_moderation_enabled",
default="Enable comment moderation", default="Enable comment moderation",
), ),
description=_( description=_(
u"help_moderation_enabled", "help_moderation_enabled",
default=u'If selected, comments will enter a "Pending" state ' default='If selected, comments will enter a "Pending" state '
u"in which they are invisible to the public. A user " "in which they are invisible to the public. A user "
u'with the "Review comments" permission ("Reviewer" ' 'with the "Review comments" permission ("Reviewer" '
u'or "Manager") can approve comments to make them ' 'or "Manager") can approve comments to make them '
u"visible to the public. If you want to enable a " "visible to the public. If you want to enable a "
u"custom comment workflow, you have to go to the " "custom comment workflow, you have to go to the "
u"types control panel.", "types control panel.",
), ),
required=False, required=False,
default=False, default=False,
) )
edit_comment_enabled = schema.Bool( edit_comment_enabled = schema.Bool(
title=_(u"label_edit_comment_enabled", default="Enable editing of comments"), title=_("label_edit_comment_enabled", default="Enable editing of comments"),
description=_( description=_(
u"help_edit_comment_enabled", "help_edit_comment_enabled",
default=u"If selected, supports editing " default="If selected, supports editing "
'of comments for users with the "Edit comments" ' 'of comments for users with the "Edit comments" '
"permission.", "permission.",
), ),
@ -274,11 +273,11 @@ class IDiscussionSettings(Interface):
delete_own_comment_enabled = schema.Bool( delete_own_comment_enabled = schema.Bool(
title=_( title=_(
u"label_delete_own_comment_enabled", default="Enable deleting own comments" "label_delete_own_comment_enabled", default="Enable deleting own comments"
), ),
description=_( description=_(
u"help_delete_own_comment_enabled", "help_delete_own_comment_enabled",
default=u"If selected, supports deleting " default="If selected, supports deleting "
"of own comments for users with the " "of own comments for users with the "
'"Delete own comments" permission.', '"Delete own comments" permission.',
), ),
@ -287,16 +286,16 @@ class IDiscussionSettings(Interface):
) )
text_transform = schema.Choice( text_transform = schema.Choice(
title=_(u"label_text_transform", default="Comment text transform"), title=_("label_text_transform", default="Comment text transform"),
description=_( description=_(
u"help_text_transform", "help_text_transform",
default=u"Use this setting to choose if the comment text " default="Use this setting to choose if the comment text "
u"should be transformed in any way. You can choose " "should be transformed in any way. You can choose "
u'between "Plain text" and "Intelligent text". ' 'between "Plain text" and "Intelligent text". '
u'"Intelligent text" converts plain text into HTML ' '"Intelligent text" converts plain text into HTML '
u"where line breaks and indentation is preserved, " "where line breaks and indentation is preserved, "
u"and web and email addresses are made into " "and web and email addresses are made into "
u"clickable links.", "clickable links.",
), ),
required=True, required=True,
default="text/plain", default="text/plain",
@ -304,15 +303,15 @@ class IDiscussionSettings(Interface):
) )
captcha = schema.Choice( captcha = schema.Choice(
title=_(u"label_captcha", default="Captcha"), title=_("label_captcha", default="Captcha"),
description=_( description=_(
u"help_captcha", "help_captcha",
default=u"Use this setting to enable or disable Captcha " default="Use this setting to enable or disable Captcha "
u"validation for comments. Install " "validation for comments. Install "
u"plone.formwidget.captcha, " "plone.formwidget.captcha, "
u"plone.formwidget.recaptcha, collective.akismet, or " "plone.formwidget.recaptcha, collective.akismet, or "
u"collective.z3cform.norobots if there are no options " "collective.z3cform.norobots if there are no options "
u"available.", "available.",
), ),
required=True, required=True,
default="disabled", default="disabled",
@ -320,11 +319,11 @@ class IDiscussionSettings(Interface):
) )
show_commenter_image = schema.Bool( show_commenter_image = schema.Bool(
title=_(u"label_show_commenter_image", default=u"Show commenter image"), title=_("label_show_commenter_image", default="Show commenter image"),
description=_( description=_(
u"help_show_commenter_image", "help_show_commenter_image",
default=u"If selected, an image of the user is shown next to " default="If selected, an image of the user is shown next to "
u"the comment.", "the comment.",
), ),
required=False, required=False,
default=True, default=True,
@ -332,14 +331,14 @@ class IDiscussionSettings(Interface):
moderator_notification_enabled = schema.Bool( moderator_notification_enabled = schema.Bool(
title=_( title=_(
u"label_moderator_notification_enabled", "label_moderator_notification_enabled",
default=u"Enable moderator email notification", default="Enable moderator email notification",
), ),
description=_( description=_(
u"help_moderator_notification_enabled", "help_moderator_notification_enabled",
default=u"If selected, the moderator is notified if a comment " default="If selected, the moderator is notified if a comment "
u"needs attention. The moderator email address can " "needs attention. The moderator email address can "
u"be set below.", "be set below.",
), ),
required=False, required=False,
default=False, default=False,
@ -347,25 +346,25 @@ class IDiscussionSettings(Interface):
moderator_email = schema.ASCIILine( moderator_email = schema.ASCIILine(
title=_( title=_(
u"label_moderator_email", "label_moderator_email",
default=u"Moderator Email Address", default="Moderator Email Address",
), ),
description=_( description=_(
u"help_moderator_email", "help_moderator_email",
default=u"Address to which moderator notifications " u"will be sent.", default="Address to which moderator notifications " "will be sent.",
), ),
required=False, required=False,
) )
user_notification_enabled = schema.Bool( user_notification_enabled = schema.Bool(
title=_( title=_(
u"label_user_notification_enabled", "label_user_notification_enabled",
default=u"Enable user email notification", default="Enable user email notification",
), ),
description=_( description=_(
u"help_user_notification_enabled", "help_user_notification_enabled",
default=u"If selected, users can choose to be notified " default="If selected, users can choose to be notified "
u"of new comments by email.", "of new comments by email.",
), ),
required=False, required=False,
default=False, default=False,

View File

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

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FIXTURE from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FIXTURE
from plone.app.discussion.interfaces import IDiscussionSettings from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.robotframework.testing import REMOTE_LIBRARY_ROBOT_TESTING from plone.app.robotframework.testing import REMOTE_LIBRARY_ROBOT_TESTING

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Test the plone.app.discussion catalog indexes """Test the plone.app.discussion catalog indexes
""" """
from datetime import datetime from datetime import datetime
@ -98,7 +97,7 @@ class ConversationCatalogTest(unittest.TestCase):
new_comment2_id = self.conversation.addComment(comment2) new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_comment2_id), f"++conversation++default/{new_comment2_id}",
) )
comment2.reindexObject() comment2.reindexObject()
brains = self.catalog.searchResults( brains = self.catalog.searchResults(
@ -128,7 +127,7 @@ class ConversationCatalogTest(unittest.TestCase):
new_comment2_id = self.conversation.addComment(comment2) new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_comment2_id), f"++conversation++default/{new_comment2_id}",
) )
comment2.reindexObject() comment2.reindexObject()
brains = self.catalog.searchResults( brains = self.catalog.searchResults(
@ -188,7 +187,7 @@ class ConversationCatalogTest(unittest.TestCase):
new_comment2_id = self.conversation.addComment(comment2) new_comment2_id = self.conversation.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_comment2_id), f"++conversation++default/{new_comment2_id}",
) )
comment2.reindexObject() comment2.reindexObject()
@ -283,7 +282,7 @@ class CommentCatalogTest(unittest.TestCase):
# Comment brain # Comment brain
self.comment = self.portal.doc1.restrictedTraverse( self.comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_comment1_id), f"++conversation++default/{new_comment1_id}",
) )
brains = self.catalog.searchResults( brains = self.catalog.searchResults(
dict( dict(
@ -304,7 +303,7 @@ class CommentCatalogTest(unittest.TestCase):
# Comment brain # Comment brain
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(cid), f"++conversation++default/{cid}",
) )
brains = self.catalog.searchResults( brains = self.catalog.searchResults(
dict( dict(
@ -503,7 +502,7 @@ class CommentCatalogTest(unittest.TestCase):
brains = self.catalog.searchResults({"portal_type": "Discussion Item"}) brains = self.catalog.searchResults({"portal_type": "Discussion Item"})
self.assertTrue(brains) self.assertTrue(brains)
comment_brain = brains[0] comment_brain = brains[0]
self.assertEqual(comment_brain.Title, u"Jim on Document 1") self.assertEqual(comment_brain.Title, "Jim on Document 1")
self.assertEqual( self.assertEqual(
comment_brain.getPath(), comment_brain.getPath(),
"/plone/doc1/++conversation++default/" + str(self.comment_id), "/plone/doc1/++conversation++default/" + str(self.comment_id),

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.browser.comment import View from plone.app.discussion.browser.comment import View
from plone.app.discussion.interfaces import IComment from plone.app.discussion.interfaces import IComment
from plone.app.discussion.interfaces import IConversation from plone.app.discussion.interfaces import IConversation
@ -64,7 +63,7 @@ class CommentTest(unittest.TestCase):
comment1.comment_id = 123 comment1.comment_id = 123
self.assertEqual("123", comment1.id) self.assertEqual("123", comment1.id)
self.assertEqual("123", comment1.getId()) self.assertEqual("123", comment1.getId())
self.assertEqual(u"123", comment1.__name__) self.assertEqual("123", comment1.__name__)
def test_uid(self): def test_uid(self):
conversation = IConversation(self.portal.doc1) conversation = IConversation(self.portal.doc1)
@ -111,14 +110,14 @@ class CommentTest(unittest.TestCase):
def test_title_special_characters(self): def test_title_special_characters(self):
self.portal.invokeFactory( self.portal.invokeFactory(
id="doc_sp_chars", id="doc_sp_chars",
title=u"Document äüö", title="Document äüö",
type_name="Document", type_name="Document",
) )
conversation = IConversation(self.portal.doc_sp_chars) conversation = IConversation(self.portal.doc_sp_chars)
comment1 = createObject("plone.Comment") comment1 = createObject("plone.Comment")
comment1.author_name = u"Tarek Ziadé" comment1.author_name = "Tarek Ziadé"
conversation.addComment(comment1) conversation.addComment(comment1)
self.assertEqual(u"Tarek Ziadé on Document äüö", comment1.Title()) self.assertEqual("Tarek Ziadé on Document äüö", comment1.Title())
def test_title_special_characters_utf8(self): def test_title_special_characters_utf8(self):
self.portal.invokeFactory( self.portal.invokeFactory(
@ -130,7 +129,7 @@ class CommentTest(unittest.TestCase):
comment1 = createObject("plone.Comment") comment1 = createObject("plone.Comment")
comment1.author_name = "Hüüb Bôûmä" comment1.author_name = "Hüüb Bôûmä"
conversation.addComment(comment1) conversation.addComment(comment1)
self.assertEqual(u"Hüüb Bôûmä on Document ëïû", comment1.Title()) self.assertEqual("Hüüb Bôûmä on Document ëïû", comment1.Title())
def test_creator(self): def test_creator(self):
comment1 = createObject("plone.Comment") comment1 = createObject("plone.Comment")
@ -174,11 +173,8 @@ class CommentTest(unittest.TestCase):
def test_getText_with_non_ascii_characters(self): def test_getText_with_non_ascii_characters(self):
comment1 = createObject("plone.Comment") comment1 = createObject("plone.Comment")
comment1.text = u"Umlaute sind ä, ö und ü." comment1.text = "Umlaute sind ä, ö und ü."
out = b"<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>" out = b"<p>Umlaute sind \xc3\xa4, \xc3\xb6 und \xc3\xbc.</p>"
if six.PY2:
self.assertEqual(comment1.getText(), out)
else:
self.assertEqual(comment1.getText(), out.decode("utf8")) self.assertEqual(comment1.getText(), out.decode("utf8"))
def test_getText_doesnt_link(self): def test_getText_doesnt_link(self):
@ -233,7 +229,7 @@ class CommentTest(unittest.TestCase):
new_comment1_id = conversation.addComment(comment1) new_comment1_id = conversation.addComment(comment1)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_comment1_id), f"++conversation++default/{new_comment1_id}",
) )
self.assertTrue(IComment.providedBy(comment)) self.assertTrue(IComment.providedBy(comment))
@ -268,7 +264,7 @@ class CommentTest(unittest.TestCase):
comment1.text = "Comment text" comment1.text = "Comment text"
new_comment1_id = conversation.addComment(comment1) new_comment1_id = conversation.addComment(comment1)
comment = self.portal.image1.restrictedTraverse( comment = self.portal.image1.restrictedTraverse(
"++conversation++default/{0}".format(new_comment1_id), f"++conversation++default/{new_comment1_id}",
) )
view = View(comment, self.request) view = View(comment, self.request)
@ -336,7 +332,7 @@ class CommentTest(unittest.TestCase):
new_comment1_id = conversation.addComment(comment1) new_comment1_id = conversation.addComment(comment1)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_comment1_id), f"++conversation++default/{new_comment1_id}",
) )
# make sure the view is there # make sure the view is there
@ -381,7 +377,7 @@ class RepliesTest(unittest.TestCase):
comment.text = "Comment text" comment.text = "Comment text"
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id), f"++conversation++default/{new_id}",
) )
# Add a reply to the CommentReplies adapter of the first comment # Add a reply to the CommentReplies adapter of the first comment
@ -418,7 +414,7 @@ class RepliesTest(unittest.TestCase):
comment.text = "Comment text" comment.text = "Comment text"
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id), f"++conversation++default/{new_id}",
) )
# Add a reply to the CommentReplies adapter of the first comment # Add a reply to the CommentReplies adapter of the first comment
@ -454,7 +450,7 @@ class RepliesTest(unittest.TestCase):
comment.text = "Comment text" comment.text = "Comment text"
new_id = conversation.addComment(comment) new_id = conversation.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id), f"++conversation++default/{new_id}",
) )
# Add a reply to the CommentReplies adapter of the first comment # Add a reply to the CommentReplies adapter of the first comment
@ -463,7 +459,7 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(comment) replies = IReplies(comment)
new_re_id = replies.addComment(re_comment) new_re_id = replies.addComment(re_comment)
re_comment = self.portal.doc1.restrictedTraverse( re_comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_re_id), f"++conversation++default/{new_re_id}",
) )
# Add a reply to the reply # Add a reply to the reply
@ -472,7 +468,7 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(re_comment) replies = IReplies(re_comment)
new_re_re_id = replies.addComment(re_re_comment) new_re_re_id = replies.addComment(re_re_comment)
re_re_comment = self.portal.doc1.restrictedTraverse( re_re_comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_re_re_id), f"++conversation++default/{new_re_re_id}",
) )
# Add a reply to the replies reply # Add a reply to the replies reply
@ -481,7 +477,7 @@ class RepliesTest(unittest.TestCase):
replies = IReplies(re_re_comment) replies = IReplies(re_re_comment)
new_re_re_re_id = replies.addComment(re_re_re_comment) new_re_re_re_id = replies.addComment(re_re_re_comment)
re_re_re_comment = self.portal.doc1.restrictedTraverse( re_re_re_comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_re_re_re_id), f"++conversation++default/{new_re_re_re_id}",
) )
self.assertEqual( self.assertEqual(

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from AccessControl import Unauthorized from AccessControl import Unauthorized
from datetime import datetime from datetime import datetime
from OFS.Image import Image from OFS.Image import Image
@ -81,7 +80,7 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u"comment-form", name="comment-form",
) )
# The form should return an error if the comment text field is empty # The form should return an error if the comment text field is empty
@ -89,7 +88,7 @@ class TestCommentForm(unittest.TestCase):
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u"comment-form", name="comment-form",
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -99,11 +98,11 @@ class TestCommentForm(unittest.TestCase):
# The form is submitted successfully, if the required text field is # The form is submitted successfully, if the required text field is
# filled out # filled out
request = make_request(form={"form.widgets.text": u"bar"}) request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u"comment-form", name="comment-form",
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -116,7 +115,7 @@ class TestCommentForm(unittest.TestCase):
self.assertEqual(len(comments), 1) self.assertEqual(len(comments), 1)
for comment in comments: for comment in comments:
self.assertEqual(comment.text, u"bar") self.assertEqual(comment.text, "bar")
self.assertEqual(comment.creator, "test_user_1_") 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() local_roles = comment.get_local_roles()
@ -144,23 +143,23 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u"comment-form", name="comment-form",
) )
provideAdapter( provideAdapter(
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=EditCommentForm, factory=EditCommentForm,
name=u"edit-comment-form", name="edit-comment-form",
) )
# The form is submitted successfully, if the required text field is # The form is submitted successfully, if the required text field is
# filled out # filled out
request = make_request(form={"form.widgets.text": u"bar"}) request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u"comment-form", name="comment-form",
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -171,10 +170,10 @@ class TestCommentForm(unittest.TestCase):
# Edit the last comment # Edit the last comment
conversation = IConversation(self.context) conversation = IConversation(self.context)
comment = [x for x in conversation.getComments()][-1] comment = [x for x in conversation.getComments()][-1]
request = make_request(form={"form.widgets.text": u"foobar"}) request = make_request(form={"form.widgets.text": "foobar"})
editForm = getMultiAdapter( editForm = getMultiAdapter(
(comment, request), (comment, request),
name=u"edit-comment-form", name="edit-comment-form",
) )
editForm.update() editForm.update()
data, errors = editForm.extractData() # pylint: disable-msg=W0612 data, errors = editForm.extractData() # pylint: disable-msg=W0612
@ -182,14 +181,14 @@ class TestCommentForm(unittest.TestCase):
self.assertEqual(len(errors), 0) 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] comment = [x for x in conversation.getComments()][-1]
self.assertEqual(comment.text, u"foobar") self.assertEqual(comment.text, "foobar")
comments = IConversation(commentForm.context).getComments() comments = IConversation(commentForm.context).getComments()
comments = [c for c in comments] # consume iterator comments = [c for c in comments] # consume iterator
self.assertEqual(len(comments), 1) self.assertEqual(len(comments), 1)
for comment in comments: for comment in comments:
self.assertEqual(comment.text, u"foobar") self.assertEqual(comment.text, "foobar")
self.assertEqual(comment.creator, "test_user_1_") self.assertEqual(comment.creator, "test_user_1_")
self.assertEqual(comment.getOwner().getUserName(), "test-user") self.assertEqual(comment.getOwner().getUserName(), "test-user")
@ -218,16 +217,16 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u"comment-form", name="comment-form",
) )
# The form is submitted successfully, if the required text field is # The form is submitted successfully, if the required text field is
# filled out # filled out
form_request = make_request(form={"form.widgets.text": u"bar"}) form_request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, form_request), (self.context, form_request),
name=u"comment-form", name="comment-form",
) )
commentForm.update() commentForm.update()
@ -240,7 +239,7 @@ class TestCommentForm(unittest.TestCase):
comment = [x for x in conversation.getComments()][-1] comment = [x for x in conversation.getComments()][-1]
deleteView = getMultiAdapter( deleteView = getMultiAdapter(
(comment, self.request), (comment, self.request),
name=u"moderate-delete-comment", name="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"]) setRoles(self.portal, TEST_USER_ID, ["Member"])
@ -275,16 +274,16 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u"comment-form", name="comment-form",
) )
# The form is submitted successfully, if the required text field is # The form is submitted successfully, if the required text field is
# filled out # filled out
form_request = make_request(form={"form.widgets.text": u"bar"}) form_request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, form_request), (self.context, form_request),
name=u"comment-form", name="comment-form",
) )
commentForm.update() commentForm.update()
@ -297,7 +296,7 @@ class TestCommentForm(unittest.TestCase):
comment = [x for x in conversation.getComments()][-1] comment = [x for x in conversation.getComments()][-1]
deleteView = getMultiAdapter( deleteView = getMultiAdapter(
(comment, self.request), (comment, self.request),
name=u"delete-own-comment", name="delete-own-comment",
) )
# try to delete last comment with johndoe # try to delete last comment with johndoe
setRoles(self.portal, "johndoe", ["Member"]) setRoles(self.portal, "johndoe", ["Member"])
@ -337,20 +336,20 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u"comment-form", name="comment-form",
) )
# Post an anonymous comment and provide a name # Post an anonymous comment and provide a name
request = make_request( request = make_request(
form={ form={
"form.widgets.name": u"john doe", "form.widgets.name": "john doe",
"form.widgets.text": u"bar", "form.widgets.text": "bar",
} }
) )
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u"comment-form", name="comment-form",
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -363,7 +362,7 @@ class TestCommentForm(unittest.TestCase):
self.assertEqual(len(comments), 1) self.assertEqual(len(comments), 1)
for comment in IConversation(commentForm.context).getComments(): for comment in IConversation(commentForm.context).getComments():
self.assertEqual(comment.text, u"bar") self.assertEqual(comment.text, "bar")
self.assertIsNone(comment.creator) self.assertIsNone(comment.creator)
roles = comment.get_local_roles() roles = comment.get_local_roles()
self.assertEqual(len(roles), 0) self.assertEqual(len(roles), 0)
@ -387,14 +386,14 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u"comment-form", name="comment-form",
) )
request = make_request(form={"form.widgets.text": u"bar"}) request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter( commentForm = getMultiAdapter(
(self.context, request), (self.context, request),
name=u"comment-form", name="comment-form",
) )
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612
@ -425,12 +424,12 @@ class TestCommentForm(unittest.TestCase):
adapts=(Interface, IBrowserRequest), adapts=(Interface, IBrowserRequest),
provides=Interface, provides=Interface,
factory=CommentForm, factory=CommentForm,
name=u"comment-form", name="comment-form",
) )
request = make_request(form={"form.widgets.text": u"bar"}) request = make_request(form={"form.widgets.text": "bar"})
commentForm = getMultiAdapter((self.context, request), name=u"comment-form") commentForm = getMultiAdapter((self.context, request), name="comment-form")
commentForm.update() commentForm.update()
data, errors = commentForm.extractData() # pylint: disable-msg=W0612 data, errors = commentForm.extractData() # pylint: disable-msg=W0612

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import ICommentAddedEvent from plone.app.discussion.interfaces import ICommentAddedEvent
from plone.app.discussion.interfaces import ICommentRemovedEvent from plone.app.discussion.interfaces import ICommentRemovedEvent
from plone.app.discussion.interfaces import IConversation from plone.app.discussion.interfaces import IConversation
@ -56,32 +55,32 @@ class CommentContentRulesTest(unittest.TestCase):
self.assertTrue(IRuleEventType.providedBy(IReplyRemovedEvent)) self.assertTrue(IRuleEventType.providedBy(IReplyRemovedEvent))
def testCommentIdStringSubstitution(self): def testCommentIdStringSubstitution(self):
comment_id = getAdapter(self.document, IStringSubstitution, name=u"comment_id") comment_id = getAdapter(self.document, IStringSubstitution, name="comment_id")
self.assertIsInstance(comment_id(), int) self.assertIsInstance(comment_id(), int)
def testCommentTextStringSubstitution(self): def testCommentTextStringSubstitution(self):
comment_text = getAdapter( comment_text = getAdapter(
self.document, IStringSubstitution, name=u"comment_text" self.document, IStringSubstitution, name="comment_text"
) )
self.assertEqual(comment_text(), u"This is a comment") self.assertEqual(comment_text(), "This is a comment")
def testCommentUserIdStringSubstitution(self): def testCommentUserIdStringSubstitution(self):
comment_user_id = getAdapter( comment_user_id = getAdapter(
self.document, IStringSubstitution, name=u"comment_user_id" self.document, IStringSubstitution, name="comment_user_id"
) )
self.assertEqual(comment_user_id(), u"jim") self.assertEqual(comment_user_id(), "jim")
def testCommentUserFullNameStringSubstitution(self): def testCommentUserFullNameStringSubstitution(self):
comment_user_fullname = getAdapter( comment_user_fullname = getAdapter(
self.document, IStringSubstitution, name=u"comment_user_fullname" self.document, IStringSubstitution, name="comment_user_fullname"
) )
self.assertEqual(comment_user_fullname(), u"Jim") self.assertEqual(comment_user_fullname(), "Jim")
def testCommentUserEmailStringSubstitution(self): def testCommentUserEmailStringSubstitution(self):
comment_user_email = getAdapter( comment_user_email = getAdapter(
self.document, IStringSubstitution, name=u"comment_user_email" self.document, IStringSubstitution, name="comment_user_email"
) )
self.assertEqual(comment_user_email(), u"jim@example.com") self.assertEqual(comment_user_email(), "jim@example.com")
class ReplyContentRulesTest(unittest.TestCase): class ReplyContentRulesTest(unittest.TestCase):
@ -103,7 +102,7 @@ class ReplyContentRulesTest(unittest.TestCase):
comment.text = "This is a comment" comment.text = "This is a comment"
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.document.restrictedTraverse( comment = self.document.restrictedTraverse(
"++conversation++default/{0}".format(new_id), f"++conversation++default/{new_id}",
) )
re_comment = createObject("plone.Comment") re_comment = createObject("plone.Comment")
@ -119,7 +118,7 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_id = getAdapter( reply_id = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u"comment_id", name="comment_id",
) )
self.assertIsInstance(reply_id(), int) self.assertIsInstance(reply_id(), int)
@ -127,30 +126,30 @@ class ReplyContentRulesTest(unittest.TestCase):
reply_text = getAdapter( reply_text = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u"comment_text", name="comment_text",
) )
self.assertEqual(reply_text(), u"This is a reply") self.assertEqual(reply_text(), "This is a reply")
def testReplyUserIdStringSubstitution(self): def testReplyUserIdStringSubstitution(self):
reply_user_id = getAdapter( reply_user_id = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u"comment_user_id", name="comment_user_id",
) )
self.assertEqual(reply_user_id(), u"julia") self.assertEqual(reply_user_id(), "julia")
def testReplyUserFullNameStringSubstitution(self): def testReplyUserFullNameStringSubstitution(self):
reply_user_fullname = getAdapter( reply_user_fullname = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u"comment_user_fullname", name="comment_user_fullname",
) )
self.assertEqual(reply_user_fullname(), u"Juliana") self.assertEqual(reply_user_fullname(), "Juliana")
def testReplyUserEmailStringSubstitution(self): def testReplyUserEmailStringSubstitution(self):
reply_user_email = getAdapter( reply_user_email = getAdapter(
self.document, self.document,
IStringSubstitution, IStringSubstitution,
name=u"comment_user_email", name="comment_user_email",
) )
self.assertEqual(reply_user_email(), u"julia@example.com") self.assertEqual(reply_user_email(), "julia@example.com")

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import IDiscussionSettings from plone.app.discussion.interfaces import IDiscussionSettings
from plone.app.discussion.testing import ( # noqa from plone.app.discussion.testing import ( # noqa
PLONE_APP_DISCUSSION_INTEGRATION_TESTING, PLONE_APP_DISCUSSION_INTEGRATION_TESTING,

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from Acquisition import aq_base from Acquisition import aq_base
from Acquisition import aq_parent from Acquisition import aq_parent
from datetime import datetime from datetime import datetime
@ -387,17 +386,17 @@ class ConversationTest(unittest.TestCase):
self.assertTrue(comment2 in conversation.values()) self.assertTrue(comment2 in conversation.values())
# check if comment ids are in iterkeys # check if comment ids are in iterkeys
self.assertTrue(new_id1 in six.iterkeys(conversation)) self.assertTrue(new_id1 in conversation.keys())
self.assertTrue(new_id2 in six.iterkeys(conversation)) self.assertTrue(new_id2 in conversation.keys())
self.assertFalse(123 in six.iterkeys(conversation)) self.assertFalse(123 in conversation.keys())
# check if comment objects are in itervalues # check if comment objects are in itervalues
self.assertTrue(comment1 in six.itervalues(conversation)) self.assertTrue(comment1 in conversation.values())
self.assertTrue(comment2 in six.itervalues(conversation)) self.assertTrue(comment2 in conversation.values())
# check if iteritems returns (key, comment object) pairs # check if iteritems returns (key, comment object) pairs
self.assertTrue((new_id1, comment1) in six.iteritems(conversation)) self.assertTrue((new_id1, comment1) in conversation.items())
self.assertTrue((new_id2, comment2) in six.iteritems(conversation)) self.assertTrue((new_id2, comment2) in conversation.items())
# TODO test acquisition wrapping # noqa T000 # TODO test acquisition wrapping # noqa T000
# self.assertTrue(aq_base(aq_parent(comment1)) is conversation) # self.assertTrue(aq_base(aq_parent(comment1)) is conversation)
@ -852,18 +851,18 @@ class RepliesTest(unittest.TestCase):
# Create the nested comment structure # Create the nested comment structure
new_id_1 = replies.addComment(comment1) new_id_1 = replies.addComment(comment1)
comment1 = self.portal.doc1.restrictedTraverse( comment1 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_1), f"++conversation++default/{new_id_1}",
) )
replies_to_comment1 = IReplies(comment1) replies_to_comment1 = IReplies(comment1)
new_id_2 = replies.addComment(comment2) new_id_2 = replies.addComment(comment2)
comment2 = self.portal.doc1.restrictedTraverse( comment2 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_2), f"++conversation++default/{new_id_2}",
) )
replies_to_comment2 = IReplies(comment2) replies_to_comment2 = IReplies(comment2)
new_id_1_1 = replies_to_comment1.addComment(comment1_1) new_id_1_1 = replies_to_comment1.addComment(comment1_1)
comment1_1 = self.portal.doc1.restrictedTraverse( comment1_1 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_1_1), f"++conversation++default/{new_id_1_1}",
) )
replies_to_comment1_1 = IReplies(comment1_1) replies_to_comment1_1 = IReplies(comment1_1)
replies_to_comment1_1.addComment(comment1_1_1) replies_to_comment1_1.addComment(comment1_1_1)

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import IConversation from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.interfaces import IReplies from plone.app.discussion.interfaces import IReplies
from plone.app.discussion.testing import ( # noqa from plone.app.discussion.testing import ( # noqa
@ -20,7 +19,7 @@ import unittest
# #
class EventsRegistry(object): class EventsRegistry:
"""Fake registry to be used while testing discussion events""" """Fake registry to be used while testing discussion events"""
commentAdded = False commentAdded = False
@ -123,7 +122,7 @@ class CommentEventsTest(unittest.TestCase):
conversation = IConversation(self.document) conversation = IConversation(self.document)
new_id = conversation.addComment(comment) new_id = conversation.addComment(comment)
comment = self.document.restrictedTraverse( comment = self.document.restrictedTraverse(
"++conversation++default/{0}".format(new_id), f"++conversation++default/{new_id}",
) )
comment.text = "foo" comment.text = "foo"
notify(ObjectModifiedEvent(comment)) notify(ObjectModifiedEvent(comment))
@ -191,7 +190,7 @@ class RepliesEventsTest(unittest.TestCase):
comment.text = "Comment text" comment.text = "Comment text"
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.document.restrictedTraverse( comment = self.document.restrictedTraverse(
"++conversation++default/{0}".format(new_id), f"++conversation++default/{new_id}",
) )
re_comment = createObject("plone.Comment") re_comment = createObject("plone.Comment")
@ -211,7 +210,7 @@ class RepliesEventsTest(unittest.TestCase):
comment.text = "Comment text" comment.text = "Comment text"
comment_id = replies.addComment(comment) comment_id = replies.addComment(comment)
comment = self.document.restrictedTraverse( comment = self.document.restrictedTraverse(
"++conversation++default/{0}".format(comment_id), f"++conversation++default/{comment_id}",
) )
re_comment = createObject("plone.Comment") re_comment = createObject("plone.Comment")
re_comment.text = "Comment text" re_comment.text = "Comment text"
@ -232,7 +231,7 @@ class RepliesEventsTest(unittest.TestCase):
comment.text = "Comment text" comment.text = "Comment text"
new_id = replies.addComment(comment) new_id = replies.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id), f"++conversation++default/{new_id}",
) )
re_comment = createObject("plone.Comment") re_comment = createObject("plone.Comment")

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Functional Doctests for plone.app.discussion. """Functional Doctests for plone.app.discussion.
These test are only triggered when Plone 4 (and plone.testing) is installed. These test are only triggered when Plone 4 (and plone.testing) is installed.

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Test for the plone.app.discussion indexers """Test for the plone.app.discussion indexers
""" """
from datetime import datetime from datetime import datetime

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.browser.moderation import BulkActionsView from plone.app.discussion.browser.moderation import BulkActionsView
from plone.app.discussion.browser.moderation import CommentTransition from plone.app.discussion.browser.moderation import CommentTransition
from plone.app.discussion.browser.moderation import DeleteComment from plone.app.discussion.browser.moderation import DeleteComment
@ -42,7 +41,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment1.Creator = "Jim" comment1.Creator = "Jim"
new_id_1 = conversation.addComment(comment1) new_id_1 = conversation.addComment(comment1)
self.comment1 = self.portal.doc1.restrictedTraverse( self.comment1 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_1), f"++conversation++default/{new_id_1}",
) )
comment2 = createObject("plone.Comment") comment2 = createObject("plone.Comment")
comment2.title = "Comment 2" comment2.title = "Comment 2"
@ -50,7 +49,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment2.Creator = "Joe" comment2.Creator = "Joe"
new_id_2 = conversation.addComment(comment2) new_id_2 = conversation.addComment(comment2)
self.comment2 = self.portal.doc1.restrictedTraverse( self.comment2 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_2), f"++conversation++default/{new_id_2}",
) )
comment3 = createObject("plone.Comment") comment3 = createObject("plone.Comment")
comment3.title = "Comment 3" comment3.title = "Comment 3"
@ -58,7 +57,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment3.Creator = "Emma" comment3.Creator = "Emma"
new_id_3 = conversation.addComment(comment3) new_id_3 = conversation.addComment(comment3)
self.comment3 = self.portal.doc1.restrictedTraverse( self.comment3 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_3), f"++conversation++default/{new_id_3}",
) )
self.conversation = conversation self.conversation = conversation

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.browser.moderation import BulkActionsView from plone.app.discussion.browser.moderation import BulkActionsView
from plone.app.discussion.browser.moderation import CommentTransition from plone.app.discussion.browser.moderation import CommentTransition
from plone.app.discussion.browser.moderation import DeleteComment from plone.app.discussion.browser.moderation import DeleteComment
@ -81,7 +80,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment1.Creator = "Jim" comment1.Creator = "Jim"
new_id_1 = conversation.addComment(comment1) new_id_1 = conversation.addComment(comment1)
self.comment1 = self.portal.doc1.restrictedTraverse( self.comment1 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_1), f"++conversation++default/{new_id_1}",
) )
comment2 = createObject("plone.Comment") comment2 = createObject("plone.Comment")
comment2.title = "Comment 2" comment2.title = "Comment 2"
@ -89,7 +88,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment2.Creator = "Joe" comment2.Creator = "Joe"
new_id_2 = conversation.addComment(comment2) new_id_2 = conversation.addComment(comment2)
self.comment2 = self.portal.doc1.restrictedTraverse( self.comment2 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_2), f"++conversation++default/{new_id_2}",
) )
comment3 = createObject("plone.Comment") comment3 = createObject("plone.Comment")
comment3.title = "Comment 3" comment3.title = "Comment 3"
@ -97,7 +96,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
comment3.Creator = "Emma" comment3.Creator = "Emma"
new_id_3 = conversation.addComment(comment3) new_id_3 = conversation.addComment(comment3)
self.comment3 = self.portal.doc1.restrictedTraverse( self.comment3 = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(new_id_3), f"++conversation++default/{new_id_3}",
) )
self.conversation = conversation self.conversation = conversation

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from Acquisition import aq_base from Acquisition import aq_base
from plone.app.discussion.interfaces import IConversation from plone.app.discussion.interfaces import IConversation
from plone.app.discussion.testing import ( # noqa from plone.app.discussion.testing import ( # noqa
@ -80,7 +79,7 @@ class TestUserNotificationUnit(unittest.TestCase):
# you may get lines separated by '\n' or '\r\n' in here. # you may get lines separated by '\n' or '\r\n' in here.
msg = msg.replace("\r\n", "\n") msg = msg.replace("\r\n", "\n")
self.assertIn('A comment on "K=C3=B6lle Alaaf" has been posted here:', msg) self.assertIn('A comment on "K=C3=B6lle Alaaf" has been posted here:', msg)
self.assertIn("http://nohost/plone/d=\noc1/view#{0}".format(comment_id), msg) self.assertIn(f"http://nohost/plone/d=\noc1/view#{comment_id}", msg)
self.assertIn("Comment text", msg) self.assertIn("Comment text", msg)
self.assertNotIn("Approve comment", msg) self.assertNotIn("Approve comment", msg)
self.assertNotIn("Delete comment", msg) self.assertNotIn("Delete comment", msg)
@ -215,7 +214,7 @@ class TestModeratorNotificationUnit(unittest.TestCase):
# The output should be encoded in a reasonable manner # The output should be encoded in a reasonable manner
# (in this case quoted-printable): # (in this case quoted-printable):
self.assertTrue('A comment on "K=C3=B6lle Alaaf" has been posted' in msg) self.assertTrue('A comment on "K=C3=B6lle Alaaf" has been posted' in msg)
self.assertIn("http://nohost/plone/doc1/view#{0}".format(comment_id), msg) self.assertIn(f"http://nohost/plone/doc1/view#{comment_id}", msg)
self.assertIn(comment.author_email, msg) self.assertIn(comment.author_email, msg)
self.assertIn(comment.text, msg) self.assertIn(comment.text, msg)

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_ROBOT_TESTING from plone.app.discussion.testing import PLONE_APP_DISCUSSION_ROBOT_TESTING
from plone.app.testing import ROBOT_TEST_LEVEL from plone.app.testing import ROBOT_TEST_LEVEL
from plone.testing import layered from plone.testing import layered

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""Test plone.app.discussion workflow and permissions. """Test plone.app.discussion workflow and permissions.
""" """
from AccessControl import Unauthorized from AccessControl import Unauthorized
@ -128,7 +127,7 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
cid = conversation.addComment(comment) cid = conversation.addComment(comment)
self.comment = self.folder.doc1.restrictedTraverse( self.comment = self.folder.doc1.restrictedTraverse(
"++conversation++default/{0}".format(cid), f"++conversation++default/{cid}",
) )
self.portal.acl_users._doAddUser("member", "secret", ["Member"], []) self.portal.acl_users._doAddUser("member", "secret", ["Member"], [])
@ -223,7 +222,7 @@ class CommentReviewWorkflowTest(unittest.TestCase):
comment.text = "Comment text" comment.text = "Comment text"
comment_id = conversation.addComment(comment) comment_id = conversation.addComment(comment)
comment = self.portal.doc1.restrictedTraverse( comment = self.portal.doc1.restrictedTraverse(
"++conversation++default/{0}".format(comment_id), f"++conversation++default/{comment_id}",
) )
self.conversation = conversation self.conversation = conversation

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""The portal_discussion tool, usually accessed via """The portal_discussion tool, usually accessed via
queryUtility(ICommentingTool). The default implementation delegates to the queryUtility(ICommentingTool). The default implementation delegates to the
standard portal_catalog for indexing comments. standard portal_catalog for indexing comments.

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import IDiscussionSettings from plone.app.discussion.interfaces import IDiscussionSettings
from plone.registry.interfaces import IRegistry from plone.registry.interfaces import IRegistry
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
@ -63,7 +62,7 @@ def upgrade_comment_workflows_apply_rolemapping(context):
wf.updateRoleMappingsFor(comment) wf.updateRoleMappingsFor(comment)
comment.reindexObjectSecurity() comment.reindexObjectSecurity()
except (AttributeError, KeyError): except (AttributeError, KeyError):
logger.info("Could not reindex comment {0}".format(brain.getURL())) logger.info(f"Could not reindex comment {brain.getURL()}")
def upgrade_comment_workflows(context): def upgrade_comment_workflows(context):

View File

@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
from plone.app.discussion.interfaces import _ from plone.app.discussion.interfaces import _
from zope.schema.vocabulary import SimpleTerm from zope.schema.vocabulary import SimpleTerm
from zope.schema.vocabulary import SimpleVocabulary from zope.schema.vocabulary import SimpleVocabulary
@ -40,7 +39,7 @@ except ImportError:
def captcha_vocabulary(context): def captcha_vocabulary(context):
"""Vocabulary with all available captcha implementations.""" """Vocabulary with all available captcha implementations."""
terms = [] terms = []
terms.append(SimpleTerm(value="disabled", token="disabled", title=_(u"Disabled"))) terms.append(SimpleTerm(value="disabled", token="disabled", title=_("Disabled")))
if HAS_CAPTCHA: # pragma: no cover if HAS_CAPTCHA: # pragma: no cover
terms.append(SimpleTerm(value="captcha", token="captcha", title="Captcha")) terms.append(SimpleTerm(value="captcha", token="captcha", title="Captcha"))

View File

@ -1,5 +1,3 @@
# encoding: utf-8
from setuptools import find_packages from setuptools import find_packages
from setuptools import setup from setuptools import setup