from ..interfaces import _ from ..interfaces import IDiscussionSettings from ..upgrades import update_registry from plone.app.registry.browser import controlpanel from plone.base.interfaces.controlpanel import IConfigurationChangedEvent from plone.base.interfaces.controlpanel import IMailSchema from plone.registry.interfaces import IRecordModifiedEvent from plone.registry.interfaces import IRegistry from Products.CMFCore.utils import getToolByName from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile from Products.statusmessages.interfaces import IStatusMessage from z3c.form import button from z3c.form.browser.checkbox import SingleCheckBoxFieldWidget from zope.component import getMultiAdapter from zope.component import getUtility from zope.component import queryUtility from zope.component.hooks import getSite class DiscussionSettingsEditForm(controlpanel.RegistryEditForm): """Discussion settings form.""" schema = IDiscussionSettings id = "DiscussionSettingsEditForm" label = _("Discussion settings") description = _( "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().updateFields() self.fields["globally_enabled"].widgetFactory = SingleCheckBoxFieldWidget self.fields["moderation_enabled"].widgetFactory = SingleCheckBoxFieldWidget self.fields["edit_comment_enabled"].widgetFactory = SingleCheckBoxFieldWidget self.fields[ "delete_own_comment_enabled" ].widgetFactory = SingleCheckBoxFieldWidget self.fields["anonymous_comments"].widgetFactory = SingleCheckBoxFieldWidget self.fields["show_commenter_image"].widgetFactory = SingleCheckBoxFieldWidget self.fields[ "moderator_notification_enabled" ].widgetFactory = SingleCheckBoxFieldWidget self.fields[ "user_notification_enabled" ].widgetFactory = SingleCheckBoxFieldWidget def updateWidgets(self): try: super().updateWidgets() except KeyError: # upgrade profile not visible in prefs_install_products_form # provide auto-upgrade update_registry(self.context) 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 = _( "Moderator Email Notification", ) self.widgets["user_notification_enabled"].label = _( "User Email Notification", ) @button.buttonAndHandler(_("Save"), name=None) def handleSave(self, action): data, errors = self.extractData() if errors: self.status = self.formErrorsMessage return self.applyChanges(data) 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(_("Edit cancelled"), "info") self.request.response.redirect( "{}/{}".format( self.context.absolute_url(), self.control_panel_view, ), ) class DiscussionSettingsControlPanel(controlpanel.ControlPanelFormWrapper): """Discussion settings control panel.""" form = DiscussionSettingsEditForm index = ViewPageTemplateFile("controlpanel.pt") def __call__(self): self.mailhost_warning() self.custom_comment_workflow_warning() return super().__call__() @property def site_url(self): """Return the absolute URL to the current site, which is likely not necessarily the portal root. """ return getSite().absolute_url() def settings(self): """Compose a string that contains all registry settings that are needed for the discussion control panel. """ registry = queryUtility(IRegistry) settings = registry.forInterface(IDiscussionSettings, check=False) wftool = getToolByName(self.context, "portal_workflow", None) workflow_chain = wftool.getChainForPortalType("Discussion Item") output = [] # Globally enabled if settings.globally_enabled: output.append("globally_enabled") # Comment moderation one_state_worklow_disabled = "comment_one_state_workflow" not in workflow_chain comment_review_workflow_disabled = ( "comment_review_workflow" not in workflow_chain ) if one_state_worklow_disabled and comment_review_workflow_disabled: output.append("moderation_custom") elif settings.moderation_enabled: output.append("moderation_enabled") if settings.edit_comment_enabled: output.append("edit_comment_enabled") if settings.delete_own_comment_enabled: output.append("delete_own_comment_enabled") # Anonymous comments if settings.anonymous_comments: output.append("anonymous_comments") # Invalid mail setting ctrlOverview = getMultiAdapter( (self.context, self.request), name="overview-controlpanel" ) if ctrlOverview.mailhost_warning(): output.append("invalid_mail_setup") # Workflow if workflow_chain: discussion_workflow = workflow_chain[0] output.append(discussion_workflow) # Merge all settings into one string return " ".join(output) def mailhost_warning(self): """Returns true if mailhost is not configured properly.""" # Copied from Products.CMFPlone/controlpanel/browser/overview.py registry = getUtility(IRegistry) mail_settings = registry.forInterface(IMailSchema, prefix="plone") mailhost = mail_settings.smtp_host email = mail_settings.email_from_address if mailhost and email: pass else: message = _( "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") def custom_comment_workflow_warning(self): """Return True if a custom comment workflow is enabled.""" wftool = getToolByName(self.context, "portal_workflow", None) workflow_chain = wftool.getChainForPortalType("Discussion Item") one_state_workflow_enabled = "comment_one_state_workflow" in workflow_chain comment_review_workflow_enabled = "comment_review_workflow" in workflow_chain if one_state_workflow_enabled or comment_review_workflow_enabled: pass else: message = _( "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") def notify_configuration_changed(event): """Event subscriber that is called every time the configuration changed.""" portal = getSite() wftool = getToolByName(portal, "portal_workflow", None) if IRecordModifiedEvent.providedBy(event): # Discussion control panel setting changed if event.record.fieldName == "moderation_enabled": # Moderation enabled has changed if event.record.value is True: # Enable moderation workflow wftool.setChainForPortalTypes( ("Discussion Item",), "comment_review_workflow" ) else: # Disable moderation workflow wftool.setChainForPortalTypes( ("Discussion Item",), "comment_one_state_workflow" ) if IConfigurationChangedEvent.providedBy(event): # Types control panel setting changed if "workflow" in event.data: registry = queryUtility(IRegistry) settings = registry.forInterface(IDiscussionSettings, check=False) workflow_chain = wftool.getChainForPortalType("Discussion Item") if workflow_chain: workflow = workflow_chain[0] if workflow == "comment_one_state_workflow": settings.moderation_enabled = False elif workflow == "comment_review_workflow": settings.moderation_enabled = True else: # Custom workflow pass