find -name "*.py" -exec pyupgrade --py3-only --py37-plus {} +
This commit is contained in:
		
							parent
							
								
									34b758f2bd
								
							
						
					
					
						commit
						75c6a5dcc1
					
				@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
#
 | 
			
		||||
# plone.app.discussion documentation build configuration file, created by
 | 
			
		||||
# sphinx-quickstart on Thu Mar 18 10:17:15 2010.
 | 
			
		||||
@ -47,8 +46,8 @@ source_suffix = ".txt"
 | 
			
		||||
master_doc = "index"
 | 
			
		||||
 | 
			
		||||
# General information about the project.
 | 
			
		||||
project = u"plone.app.discussion"
 | 
			
		||||
copyright = u"2010, Timo Stollenwerk - Plone Foundation"
 | 
			
		||||
project = "plone.app.discussion"
 | 
			
		||||
copyright = "2010, Timo Stollenwerk - Plone Foundation"
 | 
			
		||||
 | 
			
		||||
# The version info for the project you're documenting, acts as replacement for
 | 
			
		||||
# |version| and |release|, also used in various other places throughout the
 | 
			
		||||
@ -185,8 +184,8 @@ latex_documents = [
 | 
			
		||||
    (
 | 
			
		||||
        "index",
 | 
			
		||||
        "ploneappdiscussion.tex",
 | 
			
		||||
        u"plone.app.discussion Documentation",
 | 
			
		||||
        u"Timo Stollenwerk",
 | 
			
		||||
        "plone.app.discussion Documentation",
 | 
			
		||||
        "Timo Stollenwerk",
 | 
			
		||||
        "manual",
 | 
			
		||||
    ),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1,2 +1 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
__import__("pkg_resources").declare_namespace(__name__)
 | 
			
		||||
 | 
			
		||||
@ -1,2 +1 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
__import__("pkg_resources").declare_namespace(__name__)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from zope.i18nmessageid import MessageFactory
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
# Captcha validator, see captcha.txt for design notes.
 | 
			
		||||
from persistent import Persistent
 | 
			
		||||
from plone.app.discussion.browser.comments import CommentForm
 | 
			
		||||
@ -23,7 +22,7 @@ from zope.publisher.interfaces.browser import IDefaultBrowserLayer
 | 
			
		||||
class Captcha(Persistent):
 | 
			
		||||
    """Captcha input field."""
 | 
			
		||||
 | 
			
		||||
    captcha = u""
 | 
			
		||||
    captcha = ""
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Captcha = factory(Captcha)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# coding: utf-8
 | 
			
		||||
from .comments import CommentForm
 | 
			
		||||
from AccessControl import getSecurityManager
 | 
			
		||||
from Acquisition import aq_inner
 | 
			
		||||
@ -48,9 +47,9 @@ class View(BrowserView):
 | 
			
		||||
        will redirect right to the binary object, bypassing comments.
 | 
			
		||||
        """
 | 
			
		||||
        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):
 | 
			
		||||
@ -58,10 +57,10 @@ class EditCommentForm(CommentForm):
 | 
			
		||||
 | 
			
		||||
    ignoreContext = True
 | 
			
		||||
    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):
 | 
			
		||||
        super(EditCommentForm, self).updateWidgets()
 | 
			
		||||
        super().updateWidgets()
 | 
			
		||||
        self.widgets["text"].value = self.context.text
 | 
			
		||||
        # We have to rename the id, otherwise TinyMCE can't initialize
 | 
			
		||||
        # because there are two textareas with the same id.
 | 
			
		||||
@ -70,12 +69,12 @@ class EditCommentForm(CommentForm):
 | 
			
		||||
    def _redirect(self, target=""):
 | 
			
		||||
        if not target:
 | 
			
		||||
            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()
 | 
			
		||||
        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):
 | 
			
		||||
 | 
			
		||||
        # Validate form
 | 
			
		||||
@ -96,14 +95,14 @@ class EditCommentForm(CommentForm):
 | 
			
		||||
 | 
			
		||||
        # Redirect to comment
 | 
			
		||||
        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"))
 | 
			
		||||
 | 
			
		||||
    @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):
 | 
			
		||||
        IStatusMessage(self.request).add(
 | 
			
		||||
            _(u"comment_edit_cancel_notification", default=u"Edit comment cancelled"),
 | 
			
		||||
            _("comment_edit_cancel_notification", default="Edit comment cancelled"),
 | 
			
		||||
            type="info",
 | 
			
		||||
        )
 | 
			
		||||
        return self._redirect(target=self.context.absolute_url())
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from AccessControl import getSecurityManager
 | 
			
		||||
from AccessControl import Unauthorized
 | 
			
		||||
from Acquisition import aq_inner
 | 
			
		||||
@ -35,28 +34,28 @@ from zope.interface import alsoProvides
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
COMMENT_DESCRIPTION_PLAIN_TEXT = _(
 | 
			
		||||
    u"comment_description_plain_text",
 | 
			
		||||
    default=u"You can add a comment by filling out the form below. "
 | 
			
		||||
    u"Plain text formatting.",
 | 
			
		||||
    "comment_description_plain_text",
 | 
			
		||||
    default="You can add a comment by filling out the form below. "
 | 
			
		||||
    "Plain text formatting.",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
COMMENT_DESCRIPTION_MARKDOWN = _(
 | 
			
		||||
    u"comment_description_markdown",
 | 
			
		||||
    default=u"You can add a comment by filling out the form below. "
 | 
			
		||||
    u"Plain text formatting. You can use the Markdown syntax for "
 | 
			
		||||
    u"links and images.",
 | 
			
		||||
    "comment_description_markdown",
 | 
			
		||||
    default="You can add a comment by filling out the form below. "
 | 
			
		||||
    "Plain text formatting. You can use the Markdown syntax for "
 | 
			
		||||
    "links and images.",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
COMMENT_DESCRIPTION_INTELLIGENT_TEXT = _(
 | 
			
		||||
    u"comment_description_intelligent_text",
 | 
			
		||||
    default=u"You can add a comment by filling out the form below. "
 | 
			
		||||
    u"Plain text formatting. Web and email addresses are "
 | 
			
		||||
    u"transformed into clickable links.",
 | 
			
		||||
    "comment_description_intelligent_text",
 | 
			
		||||
    default="You can add a comment by filling out the form below. "
 | 
			
		||||
    "Plain text formatting. Web and email addresses are "
 | 
			
		||||
    "transformed into clickable links.",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
COMMENT_DESCRIPTION_MODERATION_ENABLED = _(
 | 
			
		||||
    u"comment_description_moderation_enabled",
 | 
			
		||||
    default=u"Comments are moderated.",
 | 
			
		||||
    "comment_description_moderation_enabled",
 | 
			
		||||
    default="Comments are moderated.",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -64,7 +63,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
 | 
			
		||||
 | 
			
		||||
    ignoreContext = True  # don't use context to get widget data
 | 
			
		||||
    id = None
 | 
			
		||||
    label = _(u"Add a comment")
 | 
			
		||||
    label = _("Add a comment")
 | 
			
		||||
    fields = field.Fields(IComment).omit(
 | 
			
		||||
        "portal_type",
 | 
			
		||||
        "__parent__",
 | 
			
		||||
@ -79,16 +78,16 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def updateFields(self):
 | 
			
		||||
        super(CommentForm, self).updateFields()
 | 
			
		||||
        super().updateFields()
 | 
			
		||||
        self.fields["user_notification"].widgetFactory = SingleCheckBoxFieldWidget
 | 
			
		||||
 | 
			
		||||
    def updateWidgets(self):
 | 
			
		||||
        super(CommentForm, self).updateWidgets()
 | 
			
		||||
        super().updateWidgets()
 | 
			
		||||
 | 
			
		||||
        # 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 = _("")
 | 
			
		||||
        # Reset widget field settings to their defaults, which may be changed
 | 
			
		||||
        # further on.  Otherwise, the email field might get set to required
 | 
			
		||||
        # 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
 | 
			
		||||
 | 
			
		||||
    def updateActions(self):
 | 
			
		||||
        super(CommentForm, self).updateActions()
 | 
			
		||||
        super().updateActions()
 | 
			
		||||
        self.actions["cancel"].addClass("btn btn-secondary")
 | 
			
		||||
        self.actions["cancel"].addClass("hide")
 | 
			
		||||
        self.actions["comment"].addClass("btn btn-primary")
 | 
			
		||||
@ -148,7 +147,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
 | 
			
		||||
    def get_author(self, data):
 | 
			
		||||
        context = aq_inner(self.context)
 | 
			
		||||
        # some attributes are not always set
 | 
			
		||||
        author_name = u""
 | 
			
		||||
        author_name = ""
 | 
			
		||||
 | 
			
		||||
        # Make sure author_name/ author_email is properly encoded
 | 
			
		||||
        if "author_name" in data:
 | 
			
		||||
@ -219,16 +218,14 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
 | 
			
		||||
 | 
			
		||||
        else:  # pragma: no cover
 | 
			
		||||
            raise Unauthorized(
 | 
			
		||||
                u"Anonymous user tries to post a comment, but anonymous "
 | 
			
		||||
                u"commenting is disabled. Or user does not have the "
 | 
			
		||||
                u"'reply to item' permission.",
 | 
			
		||||
                "Anonymous user tries to post a comment, but anonymous "
 | 
			
		||||
                "commenting is disabled. Or user does not have the "
 | 
			
		||||
                "'reply to item' permission.",
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        return comment
 | 
			
		||||
 | 
			
		||||
    @button.buttonAndHandler(
 | 
			
		||||
        _(u"add_comment_button", default=u"Comment"), name="comment"
 | 
			
		||||
    )
 | 
			
		||||
    @button.buttonAndHandler(_("add_comment_button", default="Comment"), name="comment")
 | 
			
		||||
    def handleComment(self, action):
 | 
			
		||||
        context = aq_inner(self.context)
 | 
			
		||||
 | 
			
		||||
@ -254,7 +251,7 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
 | 
			
		||||
        anon = portal_membership.isAnonymousUser()
 | 
			
		||||
        if captcha_enabled and anonymous_comments and anon:
 | 
			
		||||
            if "captcha" not in data:
 | 
			
		||||
                data["captcha"] = u""
 | 
			
		||||
                data["captcha"] = ""
 | 
			
		||||
            captcha = CaptchaValidator(
 | 
			
		||||
                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)
 | 
			
		||||
            self.request.response.redirect(self.action + "#" + str(comment_id))
 | 
			
		||||
 | 
			
		||||
    @button.buttonAndHandler(_(u"Cancel"))
 | 
			
		||||
    @button.buttonAndHandler(_("Cancel"))
 | 
			
		||||
    def handleCancel(self, action):
 | 
			
		||||
        # This method should never be called, it's only there to show
 | 
			
		||||
        # a cancel button that is handled by a jQuery method.
 | 
			
		||||
@ -309,7 +306,7 @@ class CommentsViewlet(ViewletBase):
 | 
			
		||||
    index = ViewPageTemplateFile("comments.pt")
 | 
			
		||||
 | 
			
		||||
    def update(self):
 | 
			
		||||
        super(CommentsViewlet, self).update()
 | 
			
		||||
        super().update()
 | 
			
		||||
        discussion_allowed = self.is_discussion_allowed()
 | 
			
		||||
        anonymous_allowed_or_can_reply = (
 | 
			
		||||
            self.is_anonymous()
 | 
			
		||||
@ -483,7 +480,7 @@ class CommentsViewlet(ViewletBase):
 | 
			
		||||
        if username is None:
 | 
			
		||||
            return None
 | 
			
		||||
        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):
 | 
			
		||||
 | 
			
		||||
@ -523,7 +520,7 @@ class CommentsViewlet(ViewletBase):
 | 
			
		||||
        return portal_membership.isAnonymousUser()
 | 
			
		||||
 | 
			
		||||
    def login_action(self):
 | 
			
		||||
        return "{0}/login_form?came_from={1}".format(
 | 
			
		||||
        return "{}/login_form?came_from={}".format(
 | 
			
		||||
            self.navigation_root_url,
 | 
			
		||||
            quote(self.request.get("URL", "")),
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.interfaces import _
 | 
			
		||||
from plone.app.discussion.interfaces import IDiscussionSettings
 | 
			
		||||
from plone.app.discussion.upgrades import update_registry
 | 
			
		||||
@ -32,22 +31,22 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
 | 
			
		||||
 | 
			
		||||
    schema = IDiscussionSettings
 | 
			
		||||
    id = "DiscussionSettingsEditForm"
 | 
			
		||||
    label = _(u"Discussion settings")
 | 
			
		||||
    label = _("Discussion settings")
 | 
			
		||||
    description = _(
 | 
			
		||||
        u"help_discussion_settings_editform",
 | 
			
		||||
        default=u"Some discussion related settings are not "
 | 
			
		||||
        u"located in the Discussion Control Panel.\n"
 | 
			
		||||
        u"To enable comments for a specific content type, "
 | 
			
		||||
        u"go to the Types Control Panel of this type and "
 | 
			
		||||
        u'choose "Allow comments".\n'
 | 
			
		||||
        u"To enable the moderation workflow for comments, "
 | 
			
		||||
        u"go to the Types Control Panel, choose "
 | 
			
		||||
        u'"Comment" and set workflow to '
 | 
			
		||||
        u'"Comment Review Workflow".',
 | 
			
		||||
        "help_discussion_settings_editform",
 | 
			
		||||
        default="Some discussion related settings are not "
 | 
			
		||||
        "located in the Discussion Control Panel.\n"
 | 
			
		||||
        "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, "
 | 
			
		||||
        "go to the Types Control Panel, choose "
 | 
			
		||||
        '"Comment" and set workflow to '
 | 
			
		||||
        '"Comment Review Workflow".',
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def updateFields(self):
 | 
			
		||||
        super(DiscussionSettingsEditForm, self).updateFields()
 | 
			
		||||
        super().updateFields()
 | 
			
		||||
        self.fields["globally_enabled"].widgetFactory = SingleCheckBoxFieldWidget
 | 
			
		||||
        self.fields["moderation_enabled"].widgetFactory = SingleCheckBoxFieldWidget
 | 
			
		||||
        self.fields["edit_comment_enabled"].widgetFactory = SingleCheckBoxFieldWidget
 | 
			
		||||
@ -65,20 +64,20 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
 | 
			
		||||
 | 
			
		||||
    def updateWidgets(self):
 | 
			
		||||
        try:
 | 
			
		||||
            super(DiscussionSettingsEditForm, self).updateWidgets()
 | 
			
		||||
            super().updateWidgets()
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            # upgrade profile not visible in prefs_install_products_form
 | 
			
		||||
            # provide auto-upgrade
 | 
			
		||||
            update_registry(self.context)
 | 
			
		||||
            super(DiscussionSettingsEditForm, self).updateWidgets()
 | 
			
		||||
        self.widgets["globally_enabled"].label = _(u"Enable Comments")
 | 
			
		||||
        self.widgets["anonymous_comments"].label = _(u"Anonymous Comments")
 | 
			
		||||
        self.widgets["show_commenter_image"].label = _(u"Commenter Image")
 | 
			
		||||
            super().updateWidgets()
 | 
			
		||||
        self.widgets["globally_enabled"].label = _("Enable Comments")
 | 
			
		||||
        self.widgets["anonymous_comments"].label = _("Anonymous Comments")
 | 
			
		||||
        self.widgets["show_commenter_image"].label = _("Commenter Image")
 | 
			
		||||
        self.widgets["moderator_notification_enabled"].label = _(
 | 
			
		||||
            u"Moderator Email Notification",
 | 
			
		||||
            "Moderator Email Notification",
 | 
			
		||||
        )
 | 
			
		||||
        self.widgets["user_notification_enabled"].label = _(
 | 
			
		||||
            u"User Email Notification",
 | 
			
		||||
            "User Email Notification",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    @button.buttonAndHandler(_("Save"), name=None)
 | 
			
		||||
@ -88,14 +87,14 @@ class DiscussionSettingsEditForm(controlpanel.RegistryEditForm):
 | 
			
		||||
            self.status = self.formErrorsMessage
 | 
			
		||||
            return
 | 
			
		||||
        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")
 | 
			
		||||
 | 
			
		||||
    @button.buttonAndHandler(_("Cancel"), name="cancel")
 | 
			
		||||
    def handleCancel(self, action):
 | 
			
		||||
        IStatusMessage(self.request).addStatusMessage(_(u"Edit cancelled"), "info")
 | 
			
		||||
        IStatusMessage(self.request).addStatusMessage(_("Edit cancelled"), "info")
 | 
			
		||||
        self.request.response.redirect(
 | 
			
		||||
            "{0}/{1}".format(
 | 
			
		||||
            "{}/{}".format(
 | 
			
		||||
                self.context.absolute_url(),
 | 
			
		||||
                self.control_panel_view,
 | 
			
		||||
            ),
 | 
			
		||||
@ -111,7 +110,7 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
 | 
			
		||||
    def __call__(self):
 | 
			
		||||
        self.mailhost_warning()
 | 
			
		||||
        self.custom_comment_workflow_warning()
 | 
			
		||||
        return super(DiscussionSettingsControlPanel, self).__call__()
 | 
			
		||||
        return super().__call__()
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def site_url(self):
 | 
			
		||||
@ -180,8 +179,8 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
 | 
			
		||||
            pass
 | 
			
		||||
        else:
 | 
			
		||||
            message = _(
 | 
			
		||||
                u"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.",
 | 
			
		||||
                "discussion_text_no_mailhost_configured",
 | 
			
		||||
                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
 | 
			
		||||
            IStatusMessage(self.request).addStatusMessage(message, "warning")
 | 
			
		||||
 | 
			
		||||
@ -195,8 +194,8 @@ class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper):
 | 
			
		||||
            pass
 | 
			
		||||
        else:
 | 
			
		||||
            message = _(
 | 
			
		||||
                u"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.",
 | 
			
		||||
                "discussion_text_custom_comment_workflow",
 | 
			
		||||
                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
 | 
			
		||||
            IStatusMessage(self.request).addStatusMessage(message, "warning")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from Acquisition import aq_base
 | 
			
		||||
from Acquisition import aq_chain
 | 
			
		||||
from Acquisition import aq_inner
 | 
			
		||||
@ -34,7 +33,7 @@ def traverse_parents(context):
 | 
			
		||||
    return None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConversationView(object):
 | 
			
		||||
class ConversationView:
 | 
			
		||||
    def enabled(self):
 | 
			
		||||
        if DEXTERITY_INSTALLED and IDexterityContent.providedBy(self.context):
 | 
			
		||||
            return self._enabled_for_dexterity_types()
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# coding: utf-8
 | 
			
		||||
from AccessControl import getSecurityManager
 | 
			
		||||
from AccessControl import Unauthorized
 | 
			
		||||
from Acquisition import aq_inner
 | 
			
		||||
@ -51,7 +50,7 @@ class View(BrowserView):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    def __init__(self, context, request):
 | 
			
		||||
        super(View, self).__init__(context, request)
 | 
			
		||||
        super().__init__(context, request)
 | 
			
		||||
        self.workflowTool = getToolByName(self.context, "portal_workflow")
 | 
			
		||||
        self.transitions = []
 | 
			
		||||
 | 
			
		||||
@ -229,7 +228,7 @@ class DeleteOwnComment(DeleteComment):
 | 
			
		||||
 | 
			
		||||
    def __call__(self):
 | 
			
		||||
        if self.can_delete():
 | 
			
		||||
            super(DeleteOwnComment, self).__call__()
 | 
			
		||||
            super().__call__()
 | 
			
		||||
        else:
 | 
			
		||||
            raise Unauthorized("You're not allowed to delete this comment.")
 | 
			
		||||
 | 
			
		||||
@ -318,7 +317,7 @@ class BulkActionsView(BrowserView):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    def __init__(self, context, request):
 | 
			
		||||
        super(BulkActionsView, self).__init__(context, request)
 | 
			
		||||
        super().__init__(context, request)
 | 
			
		||||
        self.workflowTool = getToolByName(context, "portal_workflow")
 | 
			
		||||
 | 
			
		||||
    def __call__(self):
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Implement the ++comments++ traversal namespace. This should return the
 | 
			
		||||
IDiscussion container for the context, from which traversal will continue
 | 
			
		||||
into an actual comment object.
 | 
			
		||||
@ -15,7 +14,7 @@ from zope.traversing.interfaces import TraversalError
 | 
			
		||||
 | 
			
		||||
@implementer(ITraversable)
 | 
			
		||||
@adapter(Interface, IBrowserRequest)
 | 
			
		||||
class ConversationNamespace(object):
 | 
			
		||||
class ConversationNamespace:
 | 
			
		||||
    """Allow traversal into a conversation via a ++conversation++name
 | 
			
		||||
    namespace. The name is the name of an adapter from context to
 | 
			
		||||
    IConversation. The special name 'default' will be taken as the default
 | 
			
		||||
@ -30,7 +29,7 @@ class ConversationNamespace(object):
 | 
			
		||||
    def traverse(self, name, ignore):
 | 
			
		||||
 | 
			
		||||
        if name == "default":
 | 
			
		||||
            name = u""
 | 
			
		||||
            name = ""
 | 
			
		||||
 | 
			
		||||
        conversation = queryAdapter(self.context, IConversation, name=name)
 | 
			
		||||
        if conversation is None:
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Captcha validator, see captcha.txt for design notes.
 | 
			
		||||
"""
 | 
			
		||||
from Acquisition import aq_inner
 | 
			
		||||
@ -39,7 +38,7 @@ class CaptchaValidator(validator.SimpleFieldValidator):
 | 
			
		||||
    # We adapt the CaptchaValidator class to all form fields (IField)
 | 
			
		||||
 | 
			
		||||
    def validate(self, value):
 | 
			
		||||
        super(CaptchaValidator, self).validate(value)
 | 
			
		||||
        super().validate(value)
 | 
			
		||||
 | 
			
		||||
        registry = queryUtility(IRegistry)
 | 
			
		||||
        settings = registry.forInterface(IDiscussionSettings, check=False)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Catalog indexers, using plone.indexer. These will populate standard catalog
 | 
			
		||||
indexes with values based on the IComment interface.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""The default comment class and factory.
 | 
			
		||||
"""
 | 
			
		||||
from AccessControl import ClassSecurityInfo
 | 
			
		||||
@ -44,28 +43,28 @@ import six
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
COMMENT_TITLE = _(
 | 
			
		||||
    u"comment_title",
 | 
			
		||||
    default=u"${author_name} on ${content}",
 | 
			
		||||
    "comment_title",
 | 
			
		||||
    default="${author_name} on ${content}",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
MAIL_NOTIFICATION_MESSAGE = _(
 | 
			
		||||
    u"mail_notification_message",
 | 
			
		||||
    default=u'A comment on "${title}" '
 | 
			
		||||
    u"has been posted here: ${link}\n\n"
 | 
			
		||||
    u"---\n"
 | 
			
		||||
    u"${text}\n"
 | 
			
		||||
    u"---\n",
 | 
			
		||||
    "mail_notification_message",
 | 
			
		||||
    default='A comment on "${title}" '
 | 
			
		||||
    "has been posted here: ${link}\n\n"
 | 
			
		||||
    "---\n"
 | 
			
		||||
    "${text}\n"
 | 
			
		||||
    "---\n",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
MAIL_NOTIFICATION_MESSAGE_MODERATOR = _(
 | 
			
		||||
    u"mail_notification_message_moderator2",
 | 
			
		||||
    default=u'A comment on "${title}" '
 | 
			
		||||
    u"has been posted by ${commentator}\n"
 | 
			
		||||
    u"here: ${link}\n\n"
 | 
			
		||||
    u"---\n\n"
 | 
			
		||||
    u"${text}\n\n"
 | 
			
		||||
    u"---\n\n"
 | 
			
		||||
    u"Log in to moderate.\n\n",
 | 
			
		||||
    "mail_notification_message_moderator2",
 | 
			
		||||
    default='A comment on "${title}" '
 | 
			
		||||
    "has been posted by ${commentator}\n"
 | 
			
		||||
    "here: ${link}\n\n"
 | 
			
		||||
    "---\n\n"
 | 
			
		||||
    "${text}\n\n"
 | 
			
		||||
    "---\n\n"
 | 
			
		||||
    "Log in to moderate.\n\n",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger("plone.app.discussion")
 | 
			
		||||
@ -100,10 +99,10 @@ class Comment(
 | 
			
		||||
    comment_id = None  # long
 | 
			
		||||
    in_reply_to = None  # long
 | 
			
		||||
 | 
			
		||||
    title = u""
 | 
			
		||||
    title = ""
 | 
			
		||||
 | 
			
		||||
    mime_type = None
 | 
			
		||||
    text = u""
 | 
			
		||||
    text = ""
 | 
			
		||||
 | 
			
		||||
    creator = None
 | 
			
		||||
    creation_date = None
 | 
			
		||||
@ -137,7 +136,7 @@ class Comment(
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    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
 | 
			
		||||
    def id(self):
 | 
			
		||||
@ -162,7 +161,7 @@ class Comment(
 | 
			
		||||
        text = self.text
 | 
			
		||||
        if text is None:
 | 
			
		||||
            return ""
 | 
			
		||||
        if six.PY2 and isinstance(text, six.text_type):
 | 
			
		||||
        if six.PY2 and isinstance(text, str):
 | 
			
		||||
            text = text.encode("utf8")
 | 
			
		||||
        transform = transforms.convertTo(
 | 
			
		||||
            targetMimetype, text, context=self, mimetype=sourceMimetype
 | 
			
		||||
@ -172,8 +171,8 @@ class Comment(
 | 
			
		||||
        else:
 | 
			
		||||
            logger = logging.getLogger("plone.app.discussion")
 | 
			
		||||
            msg = (
 | 
			
		||||
                u'Transform "{0}" => "{1}" not available. Failed to '
 | 
			
		||||
                u'transform comment "{2}".'
 | 
			
		||||
                'Transform "{0}" => "{1}" not available. Failed to '
 | 
			
		||||
                'transform comment "{2}".'
 | 
			
		||||
            )
 | 
			
		||||
            logger.error(
 | 
			
		||||
                msg.format(
 | 
			
		||||
@ -194,8 +193,8 @@ class Comment(
 | 
			
		||||
            author_name = translate(
 | 
			
		||||
                Message(
 | 
			
		||||
                    _(
 | 
			
		||||
                        u"label_anonymous",
 | 
			
		||||
                        default=u"Anonymous",
 | 
			
		||||
                        "label_anonymous",
 | 
			
		||||
                        default="Anonymous",
 | 
			
		||||
                    ),
 | 
			
		||||
                ),
 | 
			
		||||
            )
 | 
			
		||||
@ -373,7 +372,7 @@ def notify_user(obj, event):
 | 
			
		||||
    if not emails:
 | 
			
		||||
        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(
 | 
			
		||||
            MAIL_NOTIFICATION_MESSAGE,
 | 
			
		||||
@ -441,7 +440,7 @@ def notify_moderator(obj, event):
 | 
			
		||||
    content_object = aq_parent(conversation)
 | 
			
		||||
 | 
			
		||||
    # Compose email
 | 
			
		||||
    subject = translate(_(u"A comment has been posted."), context=obj.REQUEST)
 | 
			
		||||
    subject = translate(_("A comment has been posted."), context=obj.REQUEST)
 | 
			
		||||
    message = translate(
 | 
			
		||||
        Message(
 | 
			
		||||
            MAIL_NOTIFICATION_MESSAGE_MODERATOR,
 | 
			
		||||
@ -453,8 +452,8 @@ def notify_moderator(obj, event):
 | 
			
		||||
                or translate(
 | 
			
		||||
                    Message(
 | 
			
		||||
                        _(
 | 
			
		||||
                            u"label_anonymous",
 | 
			
		||||
                            default=u"Anonymous",
 | 
			
		||||
                            "label_anonymous",
 | 
			
		||||
                            default="Anonymous",
 | 
			
		||||
                        ),
 | 
			
		||||
                    ),
 | 
			
		||||
                ),
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
""" Content rules handlers
 | 
			
		||||
"""
 | 
			
		||||
from plone.app.discussion import _
 | 
			
		||||
@ -8,7 +7,7 @@ try:
 | 
			
		||||
    from plone.stringinterp.adapters import BaseSubstitution
 | 
			
		||||
except ImportError:
 | 
			
		||||
 | 
			
		||||
    class BaseSubstitution(object):
 | 
			
		||||
    class BaseSubstitution:
 | 
			
		||||
        """Fallback class if plone.stringinterp is not available"""
 | 
			
		||||
 | 
			
		||||
        def __init__(self, context, **kwargs):
 | 
			
		||||
@ -32,7 +31,7 @@ class CommentSubstitution(BaseSubstitution):
 | 
			
		||||
    """Comment string substitution"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, context, **kwargs):
 | 
			
		||||
        super(CommentSubstitution, self).__init__(context, **kwargs)
 | 
			
		||||
        super().__init__(context, **kwargs)
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def event(self):
 | 
			
		||||
@ -48,53 +47,53 @@ class CommentSubstitution(BaseSubstitution):
 | 
			
		||||
class Id(CommentSubstitution):
 | 
			
		||||
    """Comment id string substitution"""
 | 
			
		||||
 | 
			
		||||
    category = _(u"Comments")
 | 
			
		||||
    description = _(u"Comment id")
 | 
			
		||||
    category = _("Comments")
 | 
			
		||||
    description = _("Comment id")
 | 
			
		||||
 | 
			
		||||
    def safe_call(self):
 | 
			
		||||
        """Safe call"""
 | 
			
		||||
        return getattr(self.comment, "comment_id", u"")
 | 
			
		||||
        return getattr(self.comment, "comment_id", "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Text(CommentSubstitution):
 | 
			
		||||
    """Comment text"""
 | 
			
		||||
 | 
			
		||||
    category = _(u"Comments")
 | 
			
		||||
    description = _(u"Comment text")
 | 
			
		||||
    category = _("Comments")
 | 
			
		||||
    description = _("Comment text")
 | 
			
		||||
 | 
			
		||||
    def safe_call(self):
 | 
			
		||||
        """Safe call"""
 | 
			
		||||
        return getattr(self.comment, "text", u"")
 | 
			
		||||
        return getattr(self.comment, "text", "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AuthorUserName(CommentSubstitution):
 | 
			
		||||
    """Comment author user name string substitution"""
 | 
			
		||||
 | 
			
		||||
    category = _(u"Comments")
 | 
			
		||||
    description = _(u"Comment author user name")
 | 
			
		||||
    category = _("Comments")
 | 
			
		||||
    description = _("Comment author user name")
 | 
			
		||||
 | 
			
		||||
    def safe_call(self):
 | 
			
		||||
        """Safe call"""
 | 
			
		||||
        return getattr(self.comment, "author_username", u"")
 | 
			
		||||
        return getattr(self.comment, "author_username", "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AuthorFullName(CommentSubstitution):
 | 
			
		||||
    """Comment author full name string substitution"""
 | 
			
		||||
 | 
			
		||||
    category = _(u"Comments")
 | 
			
		||||
    description = _(u"Comment author full name")
 | 
			
		||||
    category = _("Comments")
 | 
			
		||||
    description = _("Comment author full name")
 | 
			
		||||
 | 
			
		||||
    def safe_call(self):
 | 
			
		||||
        """Safe call"""
 | 
			
		||||
        return getattr(self.comment, "author_name", u"")
 | 
			
		||||
        return getattr(self.comment, "author_name", "")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AuthorEmail(CommentSubstitution):
 | 
			
		||||
    """Comment author email string substitution"""
 | 
			
		||||
 | 
			
		||||
    category = _(u"Comments")
 | 
			
		||||
    description = _(u"Comment author email")
 | 
			
		||||
    category = _("Comments")
 | 
			
		||||
    description = _("Comment author email")
 | 
			
		||||
 | 
			
		||||
    def safe_call(self):
 | 
			
		||||
        """Safe call"""
 | 
			
		||||
        return getattr(self.comment, "author_email", u"")
 | 
			
		||||
        return getattr(self.comment, "author_email", "")
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""The conversation and replies adapters
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
                if children is not None:
 | 
			
		||||
                    for child_id in children:
 | 
			
		||||
                        for value in recurse(child_id, d + 1):
 | 
			
		||||
                            yield value
 | 
			
		||||
                        yield from recurse(child_id, d + 1)
 | 
			
		||||
 | 
			
		||||
        # Find top level threads
 | 
			
		||||
        comments = self._children.get(root, None)
 | 
			
		||||
@ -145,8 +143,7 @@ class Conversation(Traversable, Persistent, Explicit):
 | 
			
		||||
                    return
 | 
			
		||||
 | 
			
		||||
                # Let the closure recurse
 | 
			
		||||
                for value in recurse(comment_id):
 | 
			
		||||
                    yield value
 | 
			
		||||
                yield from recurse(comment_id)
 | 
			
		||||
 | 
			
		||||
    def addComment(self, comment):
 | 
			
		||||
        """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()]
 | 
			
		||||
 | 
			
		||||
    def iterkeys(self):
 | 
			
		||||
        return six.iterkeys(self._comments)
 | 
			
		||||
        return self._comments.keys()
 | 
			
		||||
 | 
			
		||||
    def itervalues(self):
 | 
			
		||||
        for v in six.itervalues(self._comments):
 | 
			
		||||
        for v in self._comments.values():
 | 
			
		||||
            yield v.__of__(self)
 | 
			
		||||
 | 
			
		||||
    def iteritems(self):
 | 
			
		||||
        for k, v in six.iteritems(self._comments):
 | 
			
		||||
        for k, v in self._comments.items():
 | 
			
		||||
            yield (
 | 
			
		||||
                k,
 | 
			
		||||
                v.__of__(self),
 | 
			
		||||
@ -332,7 +329,7 @@ else:
 | 
			
		||||
 | 
			
		||||
@implementer(IReplies)
 | 
			
		||||
@adapter(Conversation)  # relies on implementation details
 | 
			
		||||
class ConversationReplies(object):
 | 
			
		||||
class ConversationReplies:
 | 
			
		||||
    """An IReplies adapter for conversations.
 | 
			
		||||
 | 
			
		||||
    This makes it easy to work with top-level comments.
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
""" Custom discussion events
 | 
			
		||||
"""
 | 
			
		||||
from plone.app.discussion.interfaces import ICommentAddedEvent
 | 
			
		||||
@ -15,7 +14,7 @@ from zope.interface import implementer
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@implementer(IDiscussionEvent)
 | 
			
		||||
class DiscussionEvent(object):
 | 
			
		||||
class DiscussionEvent:
 | 
			
		||||
    """Custom event"""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, context, comment, **kwargs):
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Interfaces for plone.app.discussion
 | 
			
		||||
"""
 | 
			
		||||
from plone.app.discussion import _
 | 
			
		||||
@ -42,24 +41,24 @@ class IConversation(IIterableMapping):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    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,
 | 
			
		||||
        readonly=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    last_comment_date = schema.Date(
 | 
			
		||||
        title=_(u"Date of the most recent public comment"),
 | 
			
		||||
        title=_("Date of the most recent public comment"),
 | 
			
		||||
        readonly=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    commentators = schema.Set(
 | 
			
		||||
        title=_(u"The set of unique commentators (usernames)"),
 | 
			
		||||
        title=_("The set of unique commentators (usernames)"),
 | 
			
		||||
        readonly=True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    public_commentators = schema.Set(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"The set of unique commentators (usernames) " u"of published_comments",
 | 
			
		||||
            "The set of unique commentators (usernames) " "of published_comments",
 | 
			
		||||
        ),
 | 
			
		||||
        readonly=True,
 | 
			
		||||
    )
 | 
			
		||||
@ -138,58 +137,58 @@ class IComment(Interface):
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    portal_type = schema.ASCIILine(
 | 
			
		||||
        title=_(u"Portal type"),
 | 
			
		||||
        title=_("Portal type"),
 | 
			
		||||
        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(
 | 
			
		||||
        title=_(u"Id of comment this comment is in reply to"),
 | 
			
		||||
        title=_("Id of comment this comment is in reply to"),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    # for logged in comments - set to None for anonymous
 | 
			
		||||
    author_username = schema.TextLine(title=_(u"Name"), required=False)
 | 
			
		||||
    author_username = schema.TextLine(title=_("Name"), required=False)
 | 
			
		||||
 | 
			
		||||
    # 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(
 | 
			
		||||
        title=_(u"Email"),
 | 
			
		||||
        title=_("Email"),
 | 
			
		||||
        required=False,
 | 
			
		||||
        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(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"label_comment",
 | 
			
		||||
            default=u"Comment",
 | 
			
		||||
            "label_comment",
 | 
			
		||||
            default="Comment",
 | 
			
		||||
        ),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    user_notification = schema.Bool(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"Notify me of new comments via email.",
 | 
			
		||||
            "Notify me of new comments via email.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    creator = schema.TextLine(title=_(u"Username of the commenter"))
 | 
			
		||||
    creation_date = schema.Date(title=_(u"Creation date"))
 | 
			
		||||
    modification_date = schema.Date(title=_(u"Modification date"))
 | 
			
		||||
    creator = schema.TextLine(title=_("Username of the commenter"))
 | 
			
		||||
    creation_date = schema.Date(title=_("Creation date"))
 | 
			
		||||
    modification_date = schema.Date(title=_("Modification date"))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ICaptcha(Interface):
 | 
			
		||||
    """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):
 | 
			
		||||
@ -204,26 +203,26 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
    # - Search control panel: Show comments in search results
 | 
			
		||||
 | 
			
		||||
    globally_enabled = schema.Bool(
 | 
			
		||||
        title=_(u"label_globally_enabled", default=u"Globally enable comments"),
 | 
			
		||||
        title=_("label_globally_enabled", default="Globally enable comments"),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_globally_enabled",
 | 
			
		||||
            default=u"If selected, users are able to post comments on the "
 | 
			
		||||
            u"site. However, you will still need to enable comments "
 | 
			
		||||
            u"for specific content types, folders or content "
 | 
			
		||||
            u"objects before users will be able to post comments.",
 | 
			
		||||
            "help_globally_enabled",
 | 
			
		||||
            default="If selected, users are able to post comments on the "
 | 
			
		||||
            "site. However, you will still need to enable comments "
 | 
			
		||||
            "for specific content types, folders or content "
 | 
			
		||||
            "objects before users will be able to post comments.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
        default=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    anonymous_comments = schema.Bool(
 | 
			
		||||
        title=_(u"label_anonymous_comments", default="Enable anonymous comments"),
 | 
			
		||||
        title=_("label_anonymous_comments", default="Enable anonymous comments"),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_anonymous_comments",
 | 
			
		||||
            default=u"If selected, anonymous users are able to post "
 | 
			
		||||
            u"comments without logging in. It is highly "
 | 
			
		||||
            u"recommended to use a captcha solution to prevent "
 | 
			
		||||
            u"spam if this setting is enabled.",
 | 
			
		||||
            "help_anonymous_comments",
 | 
			
		||||
            default="If selected, anonymous users are able to post "
 | 
			
		||||
            "comments without logging in. It is highly "
 | 
			
		||||
            "recommended to use a captcha solution to prevent "
 | 
			
		||||
            "spam if this setting is enabled.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
        default=False,
 | 
			
		||||
@ -231,11 +230,11 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
 | 
			
		||||
    anonymous_email_enabled = schema.Bool(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"label_anonymous_email_enabled", default=u"Enable anonymous email field"
 | 
			
		||||
            "label_anonymous_email_enabled", default="Enable anonymous email field"
 | 
			
		||||
        ),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_anonymous_email_enabled",
 | 
			
		||||
            default=u"If selected, anonymous user will have to " u"give their email.",
 | 
			
		||||
            "help_anonymous_email_enabled",
 | 
			
		||||
            default="If selected, anonymous user will have to " "give their email.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
        default=False,
 | 
			
		||||
@ -243,28 +242,28 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
 | 
			
		||||
    moderation_enabled = schema.Bool(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"label_moderation_enabled",
 | 
			
		||||
            "label_moderation_enabled",
 | 
			
		||||
            default="Enable comment moderation",
 | 
			
		||||
        ),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_moderation_enabled",
 | 
			
		||||
            default=u'If selected, comments will enter a "Pending" state '
 | 
			
		||||
            u"in which they are invisible to the public. A user "
 | 
			
		||||
            u'with the "Review comments" permission ("Reviewer" '
 | 
			
		||||
            u'or "Manager") can approve comments to make them '
 | 
			
		||||
            u"visible to the public. If you want to enable a "
 | 
			
		||||
            u"custom comment workflow, you have to go to the "
 | 
			
		||||
            u"types control panel.",
 | 
			
		||||
            "help_moderation_enabled",
 | 
			
		||||
            default='If selected, comments will enter a "Pending" state '
 | 
			
		||||
            "in which they are invisible to the public. A user "
 | 
			
		||||
            'with the "Review comments" permission ("Reviewer" '
 | 
			
		||||
            'or "Manager") can approve comments to make them '
 | 
			
		||||
            "visible to the public. If you want to enable a "
 | 
			
		||||
            "custom comment workflow, you have to go to the "
 | 
			
		||||
            "types control panel.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
        default=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    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=_(
 | 
			
		||||
            u"help_edit_comment_enabled",
 | 
			
		||||
            default=u"If selected, supports editing "
 | 
			
		||||
            "help_edit_comment_enabled",
 | 
			
		||||
            default="If selected, supports editing "
 | 
			
		||||
            'of comments for users with the "Edit comments" '
 | 
			
		||||
            "permission.",
 | 
			
		||||
        ),
 | 
			
		||||
@ -274,11 +273,11 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
 | 
			
		||||
    delete_own_comment_enabled = schema.Bool(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"label_delete_own_comment_enabled", default="Enable deleting own comments"
 | 
			
		||||
            "label_delete_own_comment_enabled", default="Enable deleting own comments"
 | 
			
		||||
        ),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_delete_own_comment_enabled",
 | 
			
		||||
            default=u"If selected, supports deleting "
 | 
			
		||||
            "help_delete_own_comment_enabled",
 | 
			
		||||
            default="If selected, supports deleting "
 | 
			
		||||
            "of own comments for users with the "
 | 
			
		||||
            '"Delete own comments" permission.',
 | 
			
		||||
        ),
 | 
			
		||||
@ -287,16 +286,16 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    text_transform = schema.Choice(
 | 
			
		||||
        title=_(u"label_text_transform", default="Comment text transform"),
 | 
			
		||||
        title=_("label_text_transform", default="Comment text transform"),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_text_transform",
 | 
			
		||||
            default=u"Use this setting to choose if the comment text "
 | 
			
		||||
            u"should be transformed in any way. You can choose "
 | 
			
		||||
            u'between "Plain text" and "Intelligent text". '
 | 
			
		||||
            u'"Intelligent text" converts plain text into HTML '
 | 
			
		||||
            u"where line breaks and indentation is preserved, "
 | 
			
		||||
            u"and web and email addresses are made into "
 | 
			
		||||
            u"clickable links.",
 | 
			
		||||
            "help_text_transform",
 | 
			
		||||
            default="Use this setting to choose if the comment text "
 | 
			
		||||
            "should be transformed in any way. You can choose "
 | 
			
		||||
            'between "Plain text" and "Intelligent text". '
 | 
			
		||||
            '"Intelligent text" converts plain text into HTML '
 | 
			
		||||
            "where line breaks and indentation is preserved, "
 | 
			
		||||
            "and web and email addresses are made into "
 | 
			
		||||
            "clickable links.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=True,
 | 
			
		||||
        default="text/plain",
 | 
			
		||||
@ -304,15 +303,15 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    captcha = schema.Choice(
 | 
			
		||||
        title=_(u"label_captcha", default="Captcha"),
 | 
			
		||||
        title=_("label_captcha", default="Captcha"),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_captcha",
 | 
			
		||||
            default=u"Use this setting to enable or disable Captcha "
 | 
			
		||||
            u"validation for comments. Install "
 | 
			
		||||
            u"plone.formwidget.captcha, "
 | 
			
		||||
            u"plone.formwidget.recaptcha, collective.akismet, or "
 | 
			
		||||
            u"collective.z3cform.norobots if there are no options "
 | 
			
		||||
            u"available.",
 | 
			
		||||
            "help_captcha",
 | 
			
		||||
            default="Use this setting to enable or disable Captcha "
 | 
			
		||||
            "validation for comments. Install "
 | 
			
		||||
            "plone.formwidget.captcha, "
 | 
			
		||||
            "plone.formwidget.recaptcha, collective.akismet, or "
 | 
			
		||||
            "collective.z3cform.norobots if there are no options "
 | 
			
		||||
            "available.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=True,
 | 
			
		||||
        default="disabled",
 | 
			
		||||
@ -320,11 +319,11 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    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=_(
 | 
			
		||||
            u"help_show_commenter_image",
 | 
			
		||||
            default=u"If selected, an image of the user is shown next to "
 | 
			
		||||
            u"the comment.",
 | 
			
		||||
            "help_show_commenter_image",
 | 
			
		||||
            default="If selected, an image of the user is shown next to "
 | 
			
		||||
            "the comment.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
        default=True,
 | 
			
		||||
@ -332,14 +331,14 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
 | 
			
		||||
    moderator_notification_enabled = schema.Bool(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"label_moderator_notification_enabled",
 | 
			
		||||
            default=u"Enable moderator email notification",
 | 
			
		||||
            "label_moderator_notification_enabled",
 | 
			
		||||
            default="Enable moderator email notification",
 | 
			
		||||
        ),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_moderator_notification_enabled",
 | 
			
		||||
            default=u"If selected, the moderator is notified if a comment "
 | 
			
		||||
            u"needs attention. The moderator email address can "
 | 
			
		||||
            u"be set below.",
 | 
			
		||||
            "help_moderator_notification_enabled",
 | 
			
		||||
            default="If selected, the moderator is notified if a comment "
 | 
			
		||||
            "needs attention. The moderator email address can "
 | 
			
		||||
            "be set below.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
        default=False,
 | 
			
		||||
@ -347,25 +346,25 @@ class IDiscussionSettings(Interface):
 | 
			
		||||
 | 
			
		||||
    moderator_email = schema.ASCIILine(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"label_moderator_email",
 | 
			
		||||
            default=u"Moderator Email Address",
 | 
			
		||||
            "label_moderator_email",
 | 
			
		||||
            default="Moderator Email Address",
 | 
			
		||||
        ),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_moderator_email",
 | 
			
		||||
            default=u"Address to which moderator notifications " u"will be sent.",
 | 
			
		||||
            "help_moderator_email",
 | 
			
		||||
            default="Address to which moderator notifications " "will be sent.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    user_notification_enabled = schema.Bool(
 | 
			
		||||
        title=_(
 | 
			
		||||
            u"label_user_notification_enabled",
 | 
			
		||||
            default=u"Enable user email notification",
 | 
			
		||||
            "label_user_notification_enabled",
 | 
			
		||||
            default="Enable user email notification",
 | 
			
		||||
        ),
 | 
			
		||||
        description=_(
 | 
			
		||||
            u"help_user_notification_enabled",
 | 
			
		||||
            default=u"If selected, users can choose to be notified "
 | 
			
		||||
            u"of new comments by email.",
 | 
			
		||||
            "help_user_notification_enabled",
 | 
			
		||||
            default="If selected, users can choose to be notified "
 | 
			
		||||
            "of new comments by email.",
 | 
			
		||||
        ),
 | 
			
		||||
        required=False,
 | 
			
		||||
        default=False,
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from Products.CMFCore.utils import getToolByName
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.contenttypes.testing import PLONE_APP_CONTENTTYPES_FIXTURE
 | 
			
		||||
from plone.app.discussion.interfaces import IDiscussionSettings
 | 
			
		||||
from plone.app.robotframework.testing import REMOTE_LIBRARY_ROBOT_TESTING
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Test the plone.app.discussion catalog indexes
 | 
			
		||||
"""
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
@ -98,7 +97,7 @@ class ConversationCatalogTest(unittest.TestCase):
 | 
			
		||||
        new_comment2_id = self.conversation.addComment(comment2)
 | 
			
		||||
 | 
			
		||||
        comment2 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_comment2_id),
 | 
			
		||||
            f"++conversation++default/{new_comment2_id}",
 | 
			
		||||
        )
 | 
			
		||||
        comment2.reindexObject()
 | 
			
		||||
        brains = self.catalog.searchResults(
 | 
			
		||||
@ -128,7 +127,7 @@ class ConversationCatalogTest(unittest.TestCase):
 | 
			
		||||
        new_comment2_id = self.conversation.addComment(comment2)
 | 
			
		||||
 | 
			
		||||
        comment2 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_comment2_id),
 | 
			
		||||
            f"++conversation++default/{new_comment2_id}",
 | 
			
		||||
        )
 | 
			
		||||
        comment2.reindexObject()
 | 
			
		||||
        brains = self.catalog.searchResults(
 | 
			
		||||
@ -188,7 +187,7 @@ class ConversationCatalogTest(unittest.TestCase):
 | 
			
		||||
        new_comment2_id = self.conversation.addComment(comment2)
 | 
			
		||||
 | 
			
		||||
        comment2 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_comment2_id),
 | 
			
		||||
            f"++conversation++default/{new_comment2_id}",
 | 
			
		||||
        )
 | 
			
		||||
        comment2.reindexObject()
 | 
			
		||||
 | 
			
		||||
@ -283,7 +282,7 @@ class CommentCatalogTest(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
        # Comment brain
 | 
			
		||||
        self.comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_comment1_id),
 | 
			
		||||
            f"++conversation++default/{new_comment1_id}",
 | 
			
		||||
        )
 | 
			
		||||
        brains = self.catalog.searchResults(
 | 
			
		||||
            dict(
 | 
			
		||||
@ -304,7 +303,7 @@ class CommentCatalogTest(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
        # Comment brain
 | 
			
		||||
        comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(cid),
 | 
			
		||||
            f"++conversation++default/{cid}",
 | 
			
		||||
        )
 | 
			
		||||
        brains = self.catalog.searchResults(
 | 
			
		||||
            dict(
 | 
			
		||||
@ -503,7 +502,7 @@ class CommentCatalogTest(unittest.TestCase):
 | 
			
		||||
        brains = self.catalog.searchResults({"portal_type": "Discussion Item"})
 | 
			
		||||
        self.assertTrue(brains)
 | 
			
		||||
        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(
 | 
			
		||||
            comment_brain.getPath(),
 | 
			
		||||
            "/plone/doc1/++conversation++default/" + str(self.comment_id),
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.browser.comment import View
 | 
			
		||||
from plone.app.discussion.interfaces import IComment
 | 
			
		||||
from plone.app.discussion.interfaces import IConversation
 | 
			
		||||
@ -64,7 +63,7 @@ class CommentTest(unittest.TestCase):
 | 
			
		||||
        comment1.comment_id = 123
 | 
			
		||||
        self.assertEqual("123", comment1.id)
 | 
			
		||||
        self.assertEqual("123", comment1.getId())
 | 
			
		||||
        self.assertEqual(u"123", comment1.__name__)
 | 
			
		||||
        self.assertEqual("123", comment1.__name__)
 | 
			
		||||
 | 
			
		||||
    def test_uid(self):
 | 
			
		||||
        conversation = IConversation(self.portal.doc1)
 | 
			
		||||
@ -111,14 +110,14 @@ class CommentTest(unittest.TestCase):
 | 
			
		||||
    def test_title_special_characters(self):
 | 
			
		||||
        self.portal.invokeFactory(
 | 
			
		||||
            id="doc_sp_chars",
 | 
			
		||||
            title=u"Document äüö",
 | 
			
		||||
            title="Document äüö",
 | 
			
		||||
            type_name="Document",
 | 
			
		||||
        )
 | 
			
		||||
        conversation = IConversation(self.portal.doc_sp_chars)
 | 
			
		||||
        comment1 = createObject("plone.Comment")
 | 
			
		||||
        comment1.author_name = u"Tarek Ziadé"
 | 
			
		||||
        comment1.author_name = "Tarek Ziadé"
 | 
			
		||||
        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):
 | 
			
		||||
        self.portal.invokeFactory(
 | 
			
		||||
@ -130,7 +129,7 @@ class CommentTest(unittest.TestCase):
 | 
			
		||||
        comment1 = createObject("plone.Comment")
 | 
			
		||||
        comment1.author_name = "Hüüb Bôûmä"
 | 
			
		||||
        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):
 | 
			
		||||
        comment1 = createObject("plone.Comment")
 | 
			
		||||
@ -174,12 +173,9 @@ class CommentTest(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
    def test_getText_with_non_ascii_characters(self):
 | 
			
		||||
        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>"
 | 
			
		||||
        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):
 | 
			
		||||
        comment1 = createObject("plone.Comment")
 | 
			
		||||
@ -233,7 +229,7 @@ class CommentTest(unittest.TestCase):
 | 
			
		||||
        new_comment1_id = conversation.addComment(comment1)
 | 
			
		||||
 | 
			
		||||
        comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_comment1_id),
 | 
			
		||||
            f"++conversation++default/{new_comment1_id}",
 | 
			
		||||
        )
 | 
			
		||||
        self.assertTrue(IComment.providedBy(comment))
 | 
			
		||||
 | 
			
		||||
@ -268,7 +264,7 @@ class CommentTest(unittest.TestCase):
 | 
			
		||||
        comment1.text = "Comment text"
 | 
			
		||||
        new_comment1_id = conversation.addComment(comment1)
 | 
			
		||||
        comment = self.portal.image1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_comment1_id),
 | 
			
		||||
            f"++conversation++default/{new_comment1_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        view = View(comment, self.request)
 | 
			
		||||
@ -336,7 +332,7 @@ class CommentTest(unittest.TestCase):
 | 
			
		||||
        new_comment1_id = conversation.addComment(comment1)
 | 
			
		||||
 | 
			
		||||
        comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_comment1_id),
 | 
			
		||||
            f"++conversation++default/{new_comment1_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # make sure the view is there
 | 
			
		||||
@ -381,7 +377,7 @@ class RepliesTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "Comment text"
 | 
			
		||||
        new_id = replies.addComment(comment)
 | 
			
		||||
        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
 | 
			
		||||
@ -418,7 +414,7 @@ class RepliesTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "Comment text"
 | 
			
		||||
        new_id = replies.addComment(comment)
 | 
			
		||||
        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
 | 
			
		||||
@ -454,7 +450,7 @@ class RepliesTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "Comment text"
 | 
			
		||||
        new_id = conversation.addComment(comment)
 | 
			
		||||
        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
 | 
			
		||||
@ -463,7 +459,7 @@ class RepliesTest(unittest.TestCase):
 | 
			
		||||
        replies = IReplies(comment)
 | 
			
		||||
        new_re_id = replies.addComment(re_comment)
 | 
			
		||||
        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
 | 
			
		||||
@ -472,7 +468,7 @@ class RepliesTest(unittest.TestCase):
 | 
			
		||||
        replies = IReplies(re_comment)
 | 
			
		||||
        new_re_re_id = replies.addComment(re_re_comment)
 | 
			
		||||
        re_re_comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_re_re_id),
 | 
			
		||||
            f"++conversation++default/{new_re_re_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # Add a reply to the replies reply
 | 
			
		||||
@ -481,7 +477,7 @@ class RepliesTest(unittest.TestCase):
 | 
			
		||||
        replies = IReplies(re_re_comment)
 | 
			
		||||
        new_re_re_re_id = replies.addComment(re_re_re_comment)
 | 
			
		||||
        re_re_re_comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_re_re_re_id),
 | 
			
		||||
            f"++conversation++default/{new_re_re_re_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.assertEqual(
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from AccessControl import Unauthorized
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from OFS.Image import Image
 | 
			
		||||
@ -81,7 +80,7 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            factory=CommentForm,
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # The form should return an error if the comment text field is empty
 | 
			
		||||
@ -89,7 +88,7 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
 | 
			
		||||
        commentForm = getMultiAdapter(
 | 
			
		||||
            (self.context, request),
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
        commentForm.update()
 | 
			
		||||
        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
 | 
			
		||||
        # filled out
 | 
			
		||||
        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",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
        commentForm.update()
 | 
			
		||||
        data, errors = commentForm.extractData()  # pylint: disable-msg=W0612
 | 
			
		||||
@ -116,7 +115,7 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
        self.assertEqual(len(comments), 1)
 | 
			
		||||
 | 
			
		||||
        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.getOwner().getUserName(), "test-user")
 | 
			
		||||
            local_roles = comment.get_local_roles()
 | 
			
		||||
@ -144,23 +143,23 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            factory=CommentForm,
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        provideAdapter(
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            factory=EditCommentForm,
 | 
			
		||||
            name=u"edit-comment-form",
 | 
			
		||||
            name="edit-comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # The form is submitted successfully, if the required text field is
 | 
			
		||||
        # filled out
 | 
			
		||||
        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",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
        commentForm.update()
 | 
			
		||||
        data, errors = commentForm.extractData()  # pylint: disable-msg=W0612
 | 
			
		||||
@ -171,10 +170,10 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
        # Edit the last comment
 | 
			
		||||
        conversation = IConversation(self.context)
 | 
			
		||||
        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(
 | 
			
		||||
            (comment, request),
 | 
			
		||||
            name=u"edit-comment-form",
 | 
			
		||||
            name="edit-comment-form",
 | 
			
		||||
        )
 | 
			
		||||
        editForm.update()
 | 
			
		||||
        data, errors = editForm.extractData()  # pylint: disable-msg=W0612
 | 
			
		||||
@ -182,14 +181,14 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
        self.assertEqual(len(errors), 0)
 | 
			
		||||
        self.assertFalse(editForm.handleComment(editForm, "foo"))
 | 
			
		||||
        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 = [c for c in comments]  # consume iterator
 | 
			
		||||
        self.assertEqual(len(comments), 1)
 | 
			
		||||
 | 
			
		||||
        for comment in comments:
 | 
			
		||||
            self.assertEqual(comment.text, u"foobar")
 | 
			
		||||
            self.assertEqual(comment.text, "foobar")
 | 
			
		||||
            self.assertEqual(comment.creator, "test_user_1_")
 | 
			
		||||
 | 
			
		||||
            self.assertEqual(comment.getOwner().getUserName(), "test-user")
 | 
			
		||||
@ -218,16 +217,16 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            factory=CommentForm,
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # The form is submitted successfully, if the required text field is
 | 
			
		||||
        # filled out
 | 
			
		||||
        form_request = make_request(form={"form.widgets.text": u"bar"})
 | 
			
		||||
        form_request = make_request(form={"form.widgets.text": "bar"})
 | 
			
		||||
 | 
			
		||||
        commentForm = getMultiAdapter(
 | 
			
		||||
            (self.context, form_request),
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        commentForm.update()
 | 
			
		||||
@ -240,7 +239,7 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
        comment = [x for x in conversation.getComments()][-1]
 | 
			
		||||
        deleteView = getMultiAdapter(
 | 
			
		||||
            (comment, self.request),
 | 
			
		||||
            name=u"moderate-delete-comment",
 | 
			
		||||
            name="moderate-delete-comment",
 | 
			
		||||
        )
 | 
			
		||||
        # try to delete last comment without 'Delete comments' permission
 | 
			
		||||
        setRoles(self.portal, TEST_USER_ID, ["Member"])
 | 
			
		||||
@ -275,16 +274,16 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            factory=CommentForm,
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # The form is submitted successfully, if the required text field is
 | 
			
		||||
        # filled out
 | 
			
		||||
        form_request = make_request(form={"form.widgets.text": u"bar"})
 | 
			
		||||
        form_request = make_request(form={"form.widgets.text": "bar"})
 | 
			
		||||
 | 
			
		||||
        commentForm = getMultiAdapter(
 | 
			
		||||
            (self.context, form_request),
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        commentForm.update()
 | 
			
		||||
@ -297,7 +296,7 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
        comment = [x for x in conversation.getComments()][-1]
 | 
			
		||||
        deleteView = getMultiAdapter(
 | 
			
		||||
            (comment, self.request),
 | 
			
		||||
            name=u"delete-own-comment",
 | 
			
		||||
            name="delete-own-comment",
 | 
			
		||||
        )
 | 
			
		||||
        # try to delete last comment with johndoe
 | 
			
		||||
        setRoles(self.portal, "johndoe", ["Member"])
 | 
			
		||||
@ -337,20 +336,20 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            factory=CommentForm,
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        # Post an anonymous comment and provide a name
 | 
			
		||||
        request = make_request(
 | 
			
		||||
            form={
 | 
			
		||||
                "form.widgets.name": u"john doe",
 | 
			
		||||
                "form.widgets.text": u"bar",
 | 
			
		||||
                "form.widgets.name": "john doe",
 | 
			
		||||
                "form.widgets.text": "bar",
 | 
			
		||||
            }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        commentForm = getMultiAdapter(
 | 
			
		||||
            (self.context, request),
 | 
			
		||||
            name=u"comment-form",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
        commentForm.update()
 | 
			
		||||
        data, errors = commentForm.extractData()  # pylint: disable-msg=W0612
 | 
			
		||||
@ -363,7 +362,7 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
        self.assertEqual(len(comments), 1)
 | 
			
		||||
 | 
			
		||||
        for comment in IConversation(commentForm.context).getComments():
 | 
			
		||||
            self.assertEqual(comment.text, u"bar")
 | 
			
		||||
            self.assertEqual(comment.text, "bar")
 | 
			
		||||
            self.assertIsNone(comment.creator)
 | 
			
		||||
            roles = comment.get_local_roles()
 | 
			
		||||
            self.assertEqual(len(roles), 0)
 | 
			
		||||
@ -387,14 +386,14 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            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",
 | 
			
		||||
            name="comment-form",
 | 
			
		||||
        )
 | 
			
		||||
        commentForm.update()
 | 
			
		||||
        data, errors = commentForm.extractData()  # pylint: disable-msg=W0612
 | 
			
		||||
@ -425,12 +424,12 @@ class TestCommentForm(unittest.TestCase):
 | 
			
		||||
            adapts=(Interface, IBrowserRequest),
 | 
			
		||||
            provides=Interface,
 | 
			
		||||
            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()
 | 
			
		||||
        data, errors = commentForm.extractData()  # pylint: disable-msg=W0612
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.interfaces import ICommentAddedEvent
 | 
			
		||||
from plone.app.discussion.interfaces import ICommentRemovedEvent
 | 
			
		||||
from plone.app.discussion.interfaces import IConversation
 | 
			
		||||
@ -56,32 +55,32 @@ class CommentContentRulesTest(unittest.TestCase):
 | 
			
		||||
        self.assertTrue(IRuleEventType.providedBy(IReplyRemovedEvent))
 | 
			
		||||
 | 
			
		||||
    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)
 | 
			
		||||
 | 
			
		||||
    def testCommentTextStringSubstitution(self):
 | 
			
		||||
        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):
 | 
			
		||||
        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):
 | 
			
		||||
        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):
 | 
			
		||||
        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):
 | 
			
		||||
@ -103,7 +102,7 @@ class ReplyContentRulesTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "This is a comment"
 | 
			
		||||
        new_id = replies.addComment(comment)
 | 
			
		||||
        comment = self.document.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id),
 | 
			
		||||
            f"++conversation++default/{new_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        re_comment = createObject("plone.Comment")
 | 
			
		||||
@ -119,7 +118,7 @@ class ReplyContentRulesTest(unittest.TestCase):
 | 
			
		||||
        reply_id = getAdapter(
 | 
			
		||||
            self.document,
 | 
			
		||||
            IStringSubstitution,
 | 
			
		||||
            name=u"comment_id",
 | 
			
		||||
            name="comment_id",
 | 
			
		||||
        )
 | 
			
		||||
        self.assertIsInstance(reply_id(), int)
 | 
			
		||||
 | 
			
		||||
@ -127,30 +126,30 @@ class ReplyContentRulesTest(unittest.TestCase):
 | 
			
		||||
        reply_text = getAdapter(
 | 
			
		||||
            self.document,
 | 
			
		||||
            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):
 | 
			
		||||
        reply_user_id = getAdapter(
 | 
			
		||||
            self.document,
 | 
			
		||||
            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):
 | 
			
		||||
        reply_user_fullname = getAdapter(
 | 
			
		||||
            self.document,
 | 
			
		||||
            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):
 | 
			
		||||
        reply_user_email = getAdapter(
 | 
			
		||||
            self.document,
 | 
			
		||||
            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")
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.interfaces import IDiscussionSettings
 | 
			
		||||
from plone.app.discussion.testing import (  # noqa
 | 
			
		||||
    PLONE_APP_DISCUSSION_INTEGRATION_TESTING,
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from Acquisition import aq_base
 | 
			
		||||
from Acquisition import aq_parent
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
@ -387,17 +386,17 @@ class ConversationTest(unittest.TestCase):
 | 
			
		||||
        self.assertTrue(comment2 in conversation.values())
 | 
			
		||||
 | 
			
		||||
        # check if comment ids are in iterkeys
 | 
			
		||||
        self.assertTrue(new_id1 in six.iterkeys(conversation))
 | 
			
		||||
        self.assertTrue(new_id2 in six.iterkeys(conversation))
 | 
			
		||||
        self.assertFalse(123 in six.iterkeys(conversation))
 | 
			
		||||
        self.assertTrue(new_id1 in conversation.keys())
 | 
			
		||||
        self.assertTrue(new_id2 in conversation.keys())
 | 
			
		||||
        self.assertFalse(123 in conversation.keys())
 | 
			
		||||
 | 
			
		||||
        # check if comment objects are in itervalues
 | 
			
		||||
        self.assertTrue(comment1 in six.itervalues(conversation))
 | 
			
		||||
        self.assertTrue(comment2 in six.itervalues(conversation))
 | 
			
		||||
        self.assertTrue(comment1 in conversation.values())
 | 
			
		||||
        self.assertTrue(comment2 in conversation.values())
 | 
			
		||||
 | 
			
		||||
        # check if iteritems returns (key, comment object) pairs
 | 
			
		||||
        self.assertTrue((new_id1, comment1) in six.iteritems(conversation))
 | 
			
		||||
        self.assertTrue((new_id2, comment2) in six.iteritems(conversation))
 | 
			
		||||
        self.assertTrue((new_id1, comment1) in conversation.items())
 | 
			
		||||
        self.assertTrue((new_id2, comment2) in conversation.items())
 | 
			
		||||
 | 
			
		||||
        # TODO test acquisition wrapping  # noqa T000
 | 
			
		||||
        # self.assertTrue(aq_base(aq_parent(comment1)) is conversation)
 | 
			
		||||
@ -852,18 +851,18 @@ class RepliesTest(unittest.TestCase):
 | 
			
		||||
        # Create the nested comment structure
 | 
			
		||||
        new_id_1 = replies.addComment(comment1)
 | 
			
		||||
        comment1 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_1),
 | 
			
		||||
            f"++conversation++default/{new_id_1}",
 | 
			
		||||
        )
 | 
			
		||||
        replies_to_comment1 = IReplies(comment1)
 | 
			
		||||
        new_id_2 = replies.addComment(comment2)
 | 
			
		||||
        comment2 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_2),
 | 
			
		||||
            f"++conversation++default/{new_id_2}",
 | 
			
		||||
        )
 | 
			
		||||
        replies_to_comment2 = IReplies(comment2)
 | 
			
		||||
 | 
			
		||||
        new_id_1_1 = replies_to_comment1.addComment(comment1_1)
 | 
			
		||||
        comment1_1 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_1_1),
 | 
			
		||||
            f"++conversation++default/{new_id_1_1}",
 | 
			
		||||
        )
 | 
			
		||||
        replies_to_comment1_1 = IReplies(comment1_1)
 | 
			
		||||
        replies_to_comment1_1.addComment(comment1_1_1)
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.interfaces import IConversation
 | 
			
		||||
from plone.app.discussion.interfaces import IReplies
 | 
			
		||||
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"""
 | 
			
		||||
 | 
			
		||||
    commentAdded = False
 | 
			
		||||
@ -123,7 +122,7 @@ class CommentEventsTest(unittest.TestCase):
 | 
			
		||||
        conversation = IConversation(self.document)
 | 
			
		||||
        new_id = conversation.addComment(comment)
 | 
			
		||||
        comment = self.document.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id),
 | 
			
		||||
            f"++conversation++default/{new_id}",
 | 
			
		||||
        )
 | 
			
		||||
        comment.text = "foo"
 | 
			
		||||
        notify(ObjectModifiedEvent(comment))
 | 
			
		||||
@ -191,7 +190,7 @@ class RepliesEventsTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "Comment text"
 | 
			
		||||
        new_id = replies.addComment(comment)
 | 
			
		||||
        comment = self.document.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id),
 | 
			
		||||
            f"++conversation++default/{new_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        re_comment = createObject("plone.Comment")
 | 
			
		||||
@ -211,7 +210,7 @@ class RepliesEventsTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "Comment text"
 | 
			
		||||
        comment_id = replies.addComment(comment)
 | 
			
		||||
        comment = self.document.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(comment_id),
 | 
			
		||||
            f"++conversation++default/{comment_id}",
 | 
			
		||||
        )
 | 
			
		||||
        re_comment = createObject("plone.Comment")
 | 
			
		||||
        re_comment.text = "Comment text"
 | 
			
		||||
@ -232,7 +231,7 @@ class RepliesEventsTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "Comment text"
 | 
			
		||||
        new_id = replies.addComment(comment)
 | 
			
		||||
        comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id),
 | 
			
		||||
            f"++conversation++default/{new_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        re_comment = createObject("plone.Comment")
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Functional Doctests for plone.app.discussion.
 | 
			
		||||
 | 
			
		||||
   These test are only triggered when Plone 4 (and plone.testing) is installed.
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Test for the plone.app.discussion indexers
 | 
			
		||||
"""
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.browser.moderation import BulkActionsView
 | 
			
		||||
from plone.app.discussion.browser.moderation import CommentTransition
 | 
			
		||||
from plone.app.discussion.browser.moderation import DeleteComment
 | 
			
		||||
@ -42,7 +41,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
 | 
			
		||||
        comment1.Creator = "Jim"
 | 
			
		||||
        new_id_1 = conversation.addComment(comment1)
 | 
			
		||||
        self.comment1 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_1),
 | 
			
		||||
            f"++conversation++default/{new_id_1}",
 | 
			
		||||
        )
 | 
			
		||||
        comment2 = createObject("plone.Comment")
 | 
			
		||||
        comment2.title = "Comment 2"
 | 
			
		||||
@ -50,7 +49,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
 | 
			
		||||
        comment2.Creator = "Joe"
 | 
			
		||||
        new_id_2 = conversation.addComment(comment2)
 | 
			
		||||
        self.comment2 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_2),
 | 
			
		||||
            f"++conversation++default/{new_id_2}",
 | 
			
		||||
        )
 | 
			
		||||
        comment3 = createObject("plone.Comment")
 | 
			
		||||
        comment3.title = "Comment 3"
 | 
			
		||||
@ -58,7 +57,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
 | 
			
		||||
        comment3.Creator = "Emma"
 | 
			
		||||
        new_id_3 = conversation.addComment(comment3)
 | 
			
		||||
        self.comment3 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_3),
 | 
			
		||||
            f"++conversation++default/{new_id_3}",
 | 
			
		||||
        )
 | 
			
		||||
        self.conversation = conversation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.browser.moderation import BulkActionsView
 | 
			
		||||
from plone.app.discussion.browser.moderation import CommentTransition
 | 
			
		||||
from plone.app.discussion.browser.moderation import DeleteComment
 | 
			
		||||
@ -81,7 +80,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
 | 
			
		||||
        comment1.Creator = "Jim"
 | 
			
		||||
        new_id_1 = conversation.addComment(comment1)
 | 
			
		||||
        self.comment1 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_1),
 | 
			
		||||
            f"++conversation++default/{new_id_1}",
 | 
			
		||||
        )
 | 
			
		||||
        comment2 = createObject("plone.Comment")
 | 
			
		||||
        comment2.title = "Comment 2"
 | 
			
		||||
@ -89,7 +88,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
 | 
			
		||||
        comment2.Creator = "Joe"
 | 
			
		||||
        new_id_2 = conversation.addComment(comment2)
 | 
			
		||||
        self.comment2 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_2),
 | 
			
		||||
            f"++conversation++default/{new_id_2}",
 | 
			
		||||
        )
 | 
			
		||||
        comment3 = createObject("plone.Comment")
 | 
			
		||||
        comment3.title = "Comment 3"
 | 
			
		||||
@ -97,7 +96,7 @@ class ModerationBulkActionsViewTest(unittest.TestCase):
 | 
			
		||||
        comment3.Creator = "Emma"
 | 
			
		||||
        new_id_3 = conversation.addComment(comment3)
 | 
			
		||||
        self.comment3 = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(new_id_3),
 | 
			
		||||
            f"++conversation++default/{new_id_3}",
 | 
			
		||||
        )
 | 
			
		||||
        self.conversation = conversation
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from Acquisition import aq_base
 | 
			
		||||
from plone.app.discussion.interfaces import IConversation
 | 
			
		||||
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.
 | 
			
		||||
        msg = msg.replace("\r\n", "\n")
 | 
			
		||||
        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.assertNotIn("Approve comment", msg)
 | 
			
		||||
        self.assertNotIn("Delete comment", msg)
 | 
			
		||||
@ -215,7 +214,7 @@ class TestModeratorNotificationUnit(unittest.TestCase):
 | 
			
		||||
        # The output should be encoded in a reasonable manner
 | 
			
		||||
        # (in this case quoted-printable):
 | 
			
		||||
        self.assertTrue('A comment on "K=C3=B6lle Alaaf" has been posted' 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.text, msg)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.testing import PLONE_APP_DISCUSSION_ROBOT_TESTING
 | 
			
		||||
from plone.app.testing import ROBOT_TEST_LEVEL
 | 
			
		||||
from plone.testing import layered
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""Test plone.app.discussion workflow and permissions.
 | 
			
		||||
"""
 | 
			
		||||
from AccessControl import Unauthorized
 | 
			
		||||
@ -128,7 +127,7 @@ class CommentOneStateWorkflowTest(unittest.TestCase):
 | 
			
		||||
        cid = conversation.addComment(comment)
 | 
			
		||||
 | 
			
		||||
        self.comment = self.folder.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(cid),
 | 
			
		||||
            f"++conversation++default/{cid}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.portal.acl_users._doAddUser("member", "secret", ["Member"], [])
 | 
			
		||||
@ -223,7 +222,7 @@ class CommentReviewWorkflowTest(unittest.TestCase):
 | 
			
		||||
        comment.text = "Comment text"
 | 
			
		||||
        comment_id = conversation.addComment(comment)
 | 
			
		||||
        comment = self.portal.doc1.restrictedTraverse(
 | 
			
		||||
            "++conversation++default/{0}".format(comment_id),
 | 
			
		||||
            f"++conversation++default/{comment_id}",
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        self.conversation = conversation
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
"""The portal_discussion tool, usually accessed via
 | 
			
		||||
queryUtility(ICommentingTool). The default implementation delegates to the
 | 
			
		||||
standard portal_catalog for indexing comments.
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.interfaces import IDiscussionSettings
 | 
			
		||||
from plone.registry.interfaces import IRegistry
 | 
			
		||||
from Products.CMFCore.utils import getToolByName
 | 
			
		||||
@ -63,7 +62,7 @@ def upgrade_comment_workflows_apply_rolemapping(context):
 | 
			
		||||
                wf.updateRoleMappingsFor(comment)
 | 
			
		||||
            comment.reindexObjectSecurity()
 | 
			
		||||
        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):
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
# -*- coding: utf-8 -*-
 | 
			
		||||
from plone.app.discussion.interfaces import _
 | 
			
		||||
from zope.schema.vocabulary import SimpleTerm
 | 
			
		||||
from zope.schema.vocabulary import SimpleVocabulary
 | 
			
		||||
@ -40,7 +39,7 @@ except ImportError:
 | 
			
		||||
def captcha_vocabulary(context):
 | 
			
		||||
    """Vocabulary with all available captcha implementations."""
 | 
			
		||||
    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
 | 
			
		||||
        terms.append(SimpleTerm(value="captcha", token="captcha", title="Captcha"))
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user