Move some policy out of the conversation storage adapter into a view,
specifically "enabled()". Prevents having to replace/migrate persistent objects to change policy which really only concerns the context and possibly the request, not the conversation storage. Fixes #11372. svn path=/plone.app.discussion/trunk/; revision=48849
This commit is contained in:
@@ -168,14 +168,15 @@ class CommentForm(extensible.ExtensibleForm, form.Form):
|
||||
if 'user_notification' in data:
|
||||
user_notification = data['user_notification']
|
||||
|
||||
# The add-comment view is called on the conversation object
|
||||
conversation = IConversation(self.__parent__)
|
||||
|
||||
# Check if conversation is enabled on this content object
|
||||
if not conversation.enabled():
|
||||
if not self.__parent__.restrictedTraverse(
|
||||
'@@conversation_view').enabled():
|
||||
raise Unauthorized, "Discussion is not enabled for this content\
|
||||
object."
|
||||
|
||||
# The add-comment view is called on the conversation object
|
||||
conversation = IConversation(self.__parent__)
|
||||
|
||||
if data['in_reply_to']:
|
||||
# Fetch the comment we want to reply to
|
||||
conversation_to_reply_to = conversation.get(data['in_reply_to'])
|
||||
@@ -291,8 +292,7 @@ class CommentsViewlet(ViewletBase):
|
||||
|
||||
def is_discussion_allowed(self):
|
||||
context = aq_inner(self.context)
|
||||
conversation = IConversation(context)
|
||||
return conversation.enabled()
|
||||
return context.restrictedTraverse('@@conversation_view').enabled()
|
||||
|
||||
def comment_transform_message(self):
|
||||
"""Returns the description that shows up above the comment text,
|
||||
|
||||
@@ -100,6 +100,15 @@
|
||||
permission="zope2.View"
|
||||
/>
|
||||
|
||||
<!-- Conversation view -->
|
||||
<browser:page
|
||||
name="conversation_view"
|
||||
for="Products.CMFCore.interfaces.IContentish"
|
||||
layer="..interfaces.IDiscussionLayer"
|
||||
class=".conversation.ConversationView"
|
||||
permission="zope2.View"
|
||||
/>
|
||||
|
||||
<!-- Comment view -->
|
||||
<browser:view
|
||||
name="view"
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
from zope.component import queryUtility
|
||||
|
||||
from plone.registry.interfaces import IRegistry
|
||||
|
||||
from Acquisition import aq_inner
|
||||
from Acquisition import aq_base
|
||||
|
||||
from Products.CMFCore.utils import getToolByName
|
||||
from Products.CMFCore.interfaces import IFolderish
|
||||
|
||||
from Products.CMFPlone.interfaces import IPloneSiteRoot
|
||||
from Products.CMFPlone.interfaces import INonStructuralFolder
|
||||
|
||||
from plone.app.discussion.interfaces import IDiscussionSettings
|
||||
|
||||
|
||||
class ConversationView(object):
|
||||
|
||||
def enabled(self):
|
||||
""" Returns True if discussion is enabled for this conversation.
|
||||
|
||||
This method checks five different settings in order to figure out if
|
||||
discussion is enable on a specific content object:
|
||||
|
||||
1) Check if discussion is enabled globally in the plone.app.discussion
|
||||
registry/control panel.
|
||||
|
||||
2) If the current content object is a folder, always return
|
||||
False, since we don't allow comments on a folder. This
|
||||
setting is used to allow/ disallow comments for all content
|
||||
objects inside a folder, not for the folder itself.
|
||||
|
||||
3) Check if the allow_discussion boolean flag on the content object is
|
||||
set. If it is set to True or False, return the value. If it set to
|
||||
None, try further.
|
||||
|
||||
4) Traverse to a folder with allow_discussion set to either True or
|
||||
False. If allow_discussion is not set (None), traverse further until
|
||||
we reach the PloneSiteRoot.
|
||||
|
||||
5) Check if discussion is allowed for the content type.
|
||||
"""
|
||||
context = aq_inner(self.context)
|
||||
|
||||
# Fetch discussion registry
|
||||
registry = queryUtility(IRegistry)
|
||||
settings = registry.forInterface(IDiscussionSettings, check=False)
|
||||
|
||||
# Check if discussion is allowed globally
|
||||
if not settings.globally_enabled:
|
||||
return False
|
||||
|
||||
# Always return False if object is a folder
|
||||
if (IFolderish.providedBy(context) and
|
||||
not INonStructuralFolder.providedBy(context)):
|
||||
return False
|
||||
|
||||
def traverse_parents(context):
|
||||
# Run through the aq_chain of obj and check if discussion is
|
||||
# enabled in a parent folder.
|
||||
for obj in context.aq_chain:
|
||||
if not IPloneSiteRoot.providedBy(obj):
|
||||
if (IFolderish.providedBy(obj) and
|
||||
not INonStructuralFolder.providedBy(obj)):
|
||||
flag = getattr(obj, 'allow_discussion', None)
|
||||
if flag is not None:
|
||||
return flag
|
||||
return None
|
||||
|
||||
# If discussion is disabled for the object, bail out
|
||||
obj_flag = getattr(aq_base(context), 'allow_discussion', None)
|
||||
if obj_flag is False:
|
||||
return False
|
||||
|
||||
# Check if traversal returned a folder with discussion_allowed set
|
||||
# to True or False.
|
||||
folder_allow_discussion = traverse_parents(context)
|
||||
|
||||
if folder_allow_discussion is True:
|
||||
if not getattr(self, 'allow_discussion', None):
|
||||
return True
|
||||
elif folder_allow_discussion is False:
|
||||
if obj_flag:
|
||||
return True
|
||||
|
||||
# Check if discussion is allowed on the content type
|
||||
portal_types = getToolByName(self, 'portal_types')
|
||||
document_fti = getattr(portal_types, context.portal_type)
|
||||
if not document_fti.getProperty('allow_discussion'):
|
||||
# If discussion is not allowed on the content type,
|
||||
# check if 'allow discussion' is overridden on the content object.
|
||||
if not obj_flag:
|
||||
return False
|
||||
|
||||
return True
|
||||
Reference in New Issue
Block a user