src/pyams_content/shared/common/zmi/__init__.py
changeset 1358 c682811fa1ea
parent 1146 2477f95cf149
child 1394 ed31bfceddda
--- a/src/pyams_content/shared/common/zmi/__init__.py	Tue Oct 01 08:31:43 2019 +0200
+++ b/src/pyams_content/shared/common/zmi/__init__.py	Tue Oct 01 12:04:20 2019 +0200
@@ -10,8 +10,6 @@
 # FOR A PARTICULAR PURPOSE.
 #
 
-__docformat__ = 'restructuredtext'
-
 from datetime import datetime
 from uuid import uuid4
 
@@ -24,10 +22,10 @@
 from zope.location import locate
 
 from pyams_content.features.review.interfaces import IReviewComments
-from pyams_content.interfaces import CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION, MANAGE_SITE_ROOT_PERMISSION, \
-    PUBLISH_CONTENT_PERMISSION
-from pyams_content.shared.common.interfaces import IBaseSharedTool, IManagerRestrictions, ISharedContent, \
-    IWfSharedContent
+from pyams_content.interfaces import CREATE_CONTENT_PERMISSION, MANAGE_CONTENT_PERMISSION, \
+    MANAGE_SITE_ROOT_PERMISSION, PUBLISH_CONTENT_PERMISSION
+from pyams_content.shared.common.interfaces import IBaseSharedTool, IContributorRestrictions, \
+    IManagerRestrictions, ISharedContent, IWfSharedContent
 from pyams_form.form import AJAXAddForm, ajax_config
 from pyams_form.interfaces.form import IFormContextPermissionChecker, IWidgetsPrefixViewletsManager
 from pyams_form.schema import CloseButton
@@ -44,20 +42,24 @@
 from pyams_skin.viewlet.breadcrumb import BreadcrumbAdminLayerItem
 from pyams_skin.viewlet.toolbar import ToolbarMenuDivider, ToolbarMenuItem
 from pyams_template.template import template_config
-from pyams_utils.adapter import ContextAdapter, ContextRequestAdapter, ContextRequestViewAdapter, adapter_config
+from pyams_utils.adapter import ContextAdapter, ContextRequestAdapter, ContextRequestViewAdapter, \
+    adapter_config
 from pyams_utils.interfaces import FORBIDDEN_PERMISSION
 from pyams_utils.registry import get_utility
 from pyams_utils.request import check_request
 from pyams_utils.traversing import get_parent
 from pyams_utils.url import absolute_url, generate_url
 from pyams_viewlet.viewlet import Viewlet, viewlet_config
-from pyams_workflow.interfaces import IWorkflow, IWorkflowCommentInfo, IWorkflowInfo, IWorkflowPublicationInfo, \
-    IWorkflowState, IWorkflowVersions
+from pyams_workflow.interfaces import IWorkflow, IWorkflowCommentInfo, IWorkflowInfo, \
+    IWorkflowPublicationInfo, IWorkflowState, IWorkflowVersions
 from pyams_workflow.versions import WorkflowHistoryItem
 from pyams_zmi.form import AdminDialogAddForm
 from pyams_zmi.interfaces.menu import ISiteManagementMenu
 from pyams_zmi.layer import IAdminLayer
 
+
+__docformat__ = 'restructuredtext'
+
 from pyams_content import _
 
 
@@ -108,7 +110,8 @@
         IWorkflowInfo(wf_content).fire_transition('init', comment=wf_content.notepad)
 
     def nextURL(self):
-        return absolute_url(self.context, self.request, '{0}/++versions++/1/admin#properties.html'.format(self.__uuid))
+        return absolute_url(self.context, self.request,
+                            '{0}/++versions++/1/admin#properties.html'.format(self.__uuid))
 
 
 class SharedContentAJAXAddForm(AJAXAddForm):
@@ -121,7 +124,8 @@
         }
 
 
-@viewlet_config(name='wf-create-message', context=Interface, layer=IPyAMSLayer, view=SharedContentAddForm,
+@viewlet_config(name='wf-create-message', context=Interface, layer=IPyAMSLayer,
+                view=SharedContentAddForm,
                 manager=IWidgetsPrefixViewletsManager, weight=20)
 @template_config(template='templates/wf-create-message.pt')
 class SharedContentAddFormMessage(Viewlet):
@@ -153,16 +157,20 @@
     def edit_permission(self):
         workflow = IWorkflow(self.context)
         state = IWorkflowState(self.context).state
-        if state in workflow.readonly_states:  # access forbidden to all for archived contents
+        if state in workflow.readonly_states:
+            # forbidden access to all for archived contents
             return FORBIDDEN_PERMISSION
-        elif state in workflow.protected_states:  # webmaster can update published contents
+        elif state in workflow.protected_states:
+            # webmaster can update published contents
             return MANAGE_SITE_ROOT_PERMISSION
         else:
             request = check_request()
-            if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, self.context):  # webmaster access
+            if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, self.context):
+                # webmaster access
                 return MANAGE_SITE_ROOT_PERMISSION
             principal_id = request.principal.id
-            if state in workflow.manager_states:  # restricted manager access
+            if state in workflow.manager_states:
+                # restricted manager access
                 if principal_id in self.context.managers:
                     return PUBLISH_CONTENT_PERMISSION
                 for parent in lineage(self.context):
@@ -177,8 +185,27 @@
                             else:
                                 return FORBIDDEN_PERMISSION
             else:
-                if principal_id in self.context.owner | self.context.contributors | self.context.managers:
+                # access is granted  to content's owner and designated contributors or managers
+                if principal_id in self.context.owner | \
+                                   self.context.contributors | \
+                                   self.context.managers:
                     return MANAGE_CONTENT_PERMISSION
+                # check if current principal can manage owner's contents
+                for parent in lineage(self.context):
+                    contrib_restrictions = IContributorRestrictions(parent, None)
+                    if contrib_restrictions is not None:
+                        user_restrictions = contrib_restrictions.get_restrictions(principal_id)
+                        if user_restrictions:
+                            if user_restrictions.check_access(self.context,
+                                                              permission=MANAGE_CONTENT_PERMISSION,
+                                                              request=request):
+                                return MANAGE_CONTENT_PERMISSION
+                restrictions = IContributorRestrictions(self.context).get_restrictions(principal_id)
+                if restrictions and restrictions.check_access(self.context,
+                                                              permission=MANAGE_CONTENT_PERMISSION,
+                                                              request=request):
+                    return MANAGE_CONTENT_PERMISSION
+                # check if current principal can manage content's due to manager restrictions
                 for parent in lineage(self.context):
                     manager_restrictions = IManagerRestrictions(parent, None)
                     if manager_restrictions is not None:
@@ -188,8 +215,6 @@
                                                               permission=MANAGE_CONTENT_PERMISSION,
                                                               request=request):
                                 return MANAGE_CONTENT_PERMISSION
-                            else:
-                                return FORBIDDEN_PERMISSION
                 restrictions = IManagerRestrictions(self.context).get_restrictions(principal_id)
                 if restrictions and restrictions.check_access(self.context,
                                                               permission=MANAGE_CONTENT_PERMISSION,
@@ -249,13 +274,15 @@
 #
 
 @viewlet_config(name='duplication.divider', context=IWfSharedContent, layer=IPyAMSLayer,
-                view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION, weight=49)
+                view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION,
+                weight=49)
 class WfSharedContentDuplicationMenuDivider(ToolbarMenuDivider):
     """Shared content duplication menu divider"""
 
 
 @viewlet_config(name='duplication.menu', context=IWfSharedContent, layer=IPyAMSLayer,
-                view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION, weight=50)
+                view=Interface, manager=IContextActions, permission=CREATE_CONTENT_PERMISSION,
+                weight=50)
 class WfSharedContentDuplicateMenu(ToolbarMenuItem):
     """Shared content duplication menu item"""
 
@@ -326,11 +353,13 @@
         state.history.clear()
         history = WorkflowHistoryItem(date=datetime.utcnow(),
                                       principal=self.request.principal.id,
-                                      comment=translate(_("Clone created from version {source} of {oid} "
-                                                          "(in « {state} » state)")).format(
+                                      comment=translate(
+                                          _("Clone created from version {source} of {oid} "
+                                            "(in « {state} » state)")).format(
                                           source=source_state.version_id,
                                           oid=ISequentialIdInfo(self.context).get_short_oid(),
-                                          state=translate(IWorkflow(self.context).get_state_label(source_state.state)))
+                                          state=translate(IWorkflow(self.context).get_state_label(
+                                              source_state.state)))
                                       )
         state.history.append(history)
         history = WorkflowHistoryItem(date=datetime.utcnow(),
@@ -371,5 +400,5 @@
                     translate = self.request.localizer.translate
                     value += '<i class="fa fa-fw fa-circle txt-color-orange hint align-middle padding-left-5" ' \
                              'title="{0}" data-ams-hint-gravity="w"></i>'.format(
-                                translate(_("Created or modified in this version")))
+                        translate(_("Created or modified in this version")))
         return value