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:
Ross Patterson
2011-04-15 04:29:46 +00:00
parent 7354ca4298
commit 3708429a37
8 changed files with 146 additions and 104 deletions
+6 -6
View File
@@ -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