Added contributors restrictions to allow a contributor to manage contents owned by other principals
--- a/src/pyams_content/shared/common/interfaces/__init__.py Tue Oct 01 08:31:43 2019 +0200
+++ b/src/pyams_content/shared/common/interfaces/__init__.py Tue Oct 01 12:04:20 2019 +0200
@@ -38,29 +38,33 @@
"""Shared tool roles interface"""
webmasters = PrincipalsSet(title=_("Webmasters"),
- description=_("Webmasters can handle all contents, including published ones"),
+ description=_("Webmasters can handle all contents, including "
+ "published ones"),
role_id=WEBMASTER_ROLE,
required=False)
pilots = PrincipalsSet(title=_("Pilots"),
- description=_("Pilots can handle tool configuration, manage access rules, grant users "
- "roles and manage managers restrictions"),
+ description=_("Pilots can handle tool configuration, manage access "
+ "rules, grant users roles and manage managers "
+ "restrictions"),
role_id=PILOT_ROLE,
required=False)
managers = PrincipalsSet(title=_("Managers"),
- description=_("Managers can handle main operations in tool's workflow, like publish "
- "or retire contents"),
+ description=_("Managers can handle main operations in tool's "
+ "workflow, like publish or retire contents"),
role_id=MANAGER_ROLE,
required=False)
contributors = PrincipalsSet(title=_("Contributors"),
- description=_("Contributors are users which are allowed to create new contents"),
+ description=_("Contributors are users which are allowed to "
+ "create new contents"),
role_id=CONTRIBUTOR_ROLE,
required=False)
designers = PrincipalsSet(title=_("Designers"),
- description=_("Designers are users which are allowed to manage presentation templates"),
+ description=_("Designers are users which are allowed to manage "
+ "presentation templates"),
role_id=DESIGNER_ROLE,
required=False)
@@ -83,11 +87,12 @@
containers(ISharedToolContainer)
- shared_content_menu = Attribute("Boolean flag indicating if tool is displayed into 'Shared contents' or "
- "Shared tools' menu")
+ shared_content_menu = Attribute("Boolean flag indicating if tool is displayed into 'Shared "
+ "contents' or Shared tools' menu")
shared_content_workflow = Choice(title=_("Workflow name"),
- description=_("Name of workflow utility used to manage tool contents"),
+ description=_("Name of workflow utility used to manage tool "
+ "contents"),
vocabulary="PyAMS workflows",
default="PyAMS default workflow")
@@ -119,12 +124,14 @@
content_name = Attribute("Content name")
content_url = TextLine(title=_("Content URL"),
- description=_("URL used to access this content; this is important for SEO and "
- "should include most important words describing content; spaces and "
- "underscores will be automatically replaced by hyphens"),
+ description=_("URL used to access this content; this is important for "
+ "SEO and should include most important words describing "
+ "content; spaces and underscores will be automatically "
+ "replaced by hyphens"),
required=True)
- handle_content_url = Attribute("Static boolean value to specify if content URL is supported by this content type")
+ handle_content_url = Attribute("Static boolean value to specify if content URL is supported by "
+ "this content type")
creator = Principal(title=_("Version creator"),
description=_("Name of content's version creator. "
@@ -154,15 +161,19 @@
description=_("Content's header is generally displayed in page header"),
required=False)
- handle_header = Attribute("Static boolean value to specify if header is supported by this content type")
+ handle_header = Attribute("Static boolean value to specify if header is supported by this "
+ "content type")
description = I18nTextField(title=_("Meta-description"),
- description=_("The content's description is 'hidden' into HTML's page headers; but it "
- "can be seen, for example, in some search engines results as content's "
- "description; if description is empty, content's header will be used."),
+ description=_("The content's description is 'hidden' into HTML's "
+ "page headers; but it can be seen, for example, in "
+ "some search engines results as content's "
+ "description; if description is empty, content's "
+ "header will be used."),
required=False)
- handle_description = Attribute("Static boolean value to specify if description is supported by this content type")
+ handle_description = Attribute("Static boolean value to specify if description is supported by "
+ "this content type")
keywords = TextLineListField(title=_("Keywords"),
description=_("They will be included into HTML pages metadata"),
@@ -189,37 +200,39 @@
"""Shared content roles"""
owner = PrincipalsSet(title=_("Content owner"),
- description=_("The owner is the creator of content's first version, except if it was "
- "transferred afterwards to another owner"),
+ description=_("The owner is the creator of content's first version, "
+ "except if it was transferred afterwards to another owner"),
role_id=OWNER_ROLE,
required=True,
max_length=1)
managers = PrincipalsSet(title=_("Managers"),
- description=_("Managers can handle main operations in tool's workflow, like publish "
- "or retire contents"),
+ description=_("Managers can handle main operations in tool's "
+ "workflow, like publish or retire contents"),
role_id=MANAGER_ROLE,
required=False)
contributors = PrincipalsSet(title=_("Contributors"),
- description=_("Contributors are users which are allowed to update this content in "
- "addition to it's owner"),
+ description=_("Contributors are users which are allowed to update "
+ "this content in addition to it's owner"),
role_id=CONTRIBUTOR_ROLE,
required=False)
designers = PrincipalsSet(title=_("Designers"),
- description=_("Designers are users which are allowed to manage presentation templates"),
+ description=_("Designers are users which are allowed to manage "
+ "presentation templates"),
role_id=DESIGNER_ROLE,
required=False)
readers = PrincipalsSet(title=_("Readers"),
- description=_("Readers are users which are asked to verify and comment contents before "
- "they are published"),
+ description=_("Readers are users which are asked to verify and comment "
+ "contents before they are published"),
role_id=READER_ROLE,
required=False)
guests = PrincipalsSet(title=_("Guests"),
- description=_("Guests are users which are allowed to view contents with restricted access"),
+ description=_("Guests are users which are allowed to view contents "
+ "with restricted access"),
role_id=GUEST_ROLE,
required=False)
@@ -286,11 +299,19 @@
"""Shared content contributor restrictions"""
publication_checks = Bool(title=_("Publication checks"),
- description=_("If 'yes', this contributor will have to confirm that contents have "
- "been previewed and checked before asking for publication"),
+ description=_("If 'yes', this contributor will have to confirm that "
+ "contents have been previewed and checked before "
+ "asking for publication"),
required=False,
default=True)
+ owners = PrincipalsSet(title=_("Substitute for"),
+ description=_("Contributor will have access to contents owned by these "
+ "principals"))
+
+ def check_access(self, context, permission=MANAGE_CONTENT_PERMISSION, request=None):
+ """Check if principal is granted access to given context"""
+
class IContributorRestrictions(IRestrictions):
"""Contributor restrictions interface"""
@@ -311,19 +332,21 @@
"""Shared content manager restrictions"""
publication_checks = Bool(title=_("Publication checks"),
- description=_("If 'yes', this manager will have to confirm that contents have "
- "been previewed and checked before publishing a content"),
+ description=_("If 'yes', this manager will have to confirm that "
+ "contents have been previewed and checked before "
+ "publishing a content"),
required=False,
default=True)
restricted_contents = Bool(title=_("Restricted contents"),
- description=_("If 'yes', this manager will get restricted access to manage contents "
- "based on selected settings"),
+ description=_("If 'yes', this manager will get restricted access "
+ "to manage contents based on selected settings"),
required=False,
default=True)
owners = PrincipalsSet(title=_("Selected owners"),
- description=_("Manager will have access to contents owned by these principals"),
+ description=_("Manager will have access to contents owned by these "
+ "principals"),
required=False)
def check_access(self, context, permission=MANAGE_CONTENT_PERMISSION, request=None):
--- a/src/pyams_content/shared/common/security.py Tue Oct 01 08:31:43 2019 +0200
+++ b/src/pyams_content/shared/common/security.py Tue Oct 01 12:04:20 2019 +0200
@@ -10,19 +10,12 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
-
-
-# import standard library
+from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION, MANAGER_ROLE, CONTRIBUTOR_ROLE
+from pyams_content.shared.common.interfaces import IWfSharedContent, IManagerRestrictions, \
+ MANAGER_RESTRICTIONS_KEY, IManagerRestrictionsFactory, IBaseSharedTool, IManagerRestrictionInfo, \
+ IRestrictionInfo, IContributorRestrictionInfo, IContributorRestrictions, \
+ IContributorRestrictionsFactory, CONTRIBUTOR_RESTRICTIONS_KEY, IRestrictions
-# import interfaces
-from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION, MANAGER_ROLE, CONTRIBUTOR_ROLE
-from pyams_content.shared.common.interfaces import IWfSharedContent, IManagerRestrictions, MANAGER_RESTRICTIONS_KEY, \
- IManagerRestrictionsFactory, IBaseSharedTool, IManagerRestrictionInfo, IRestrictionInfo, \
- IContributorRestrictionInfo, IContributorRestrictions, IContributorRestrictionsFactory, \
- CONTRIBUTOR_RESTRICTIONS_KEY, IRestrictions
-
-# import packages
from persistent import Persistent
from pyams_security.interfaces import IPrincipalInfo, IRevokedRoleEvent, IGrantedRoleEvent
from pyams_utils.adapter import adapter_config, ContextAdapter, get_annotation_adapter
@@ -34,6 +27,9 @@
from zope.schema.fieldproperty import FieldProperty
+__docformat__ = 'restructuredtext'
+
+
@implementer(IRestrictionInfo)
class PrincipalRestrictionInfo(Persistent):
"""Principal restriction info"""
@@ -97,6 +93,16 @@
restriction_interface = IContributorRestrictionInfo
publication_checks = FieldProperty(IContributorRestrictionInfo['publication_checks'])
+ owners = FieldProperty(IContributorRestrictionInfo['owners'])
+
+ def check_access(self, context, permission=MANAGE_CONTENT_PERMISSION, request=None):
+ if request is None:
+ request = check_request()
+ if not request.has_permission(permission, context): # check permission
+ return False
+ if context.owner & (self.owners or set()): # check if owners are matching
+ return True
+ return False
@adapter_config(context=IBaseSharedTool, provides=IContributorRestrictions)
--- 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
--- a/src/pyams_content/workflow/__init__.py Tue Oct 01 08:31:43 2019 +0200
+++ b/src/pyams_content/workflow/__init__.py Tue Oct 01 12:04:20 2019 +0200
@@ -10,8 +10,6 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
-
from datetime import datetime, timedelta
from pyramid.threadlocal import get_current_registry
@@ -21,11 +19,12 @@
from zope.location import locate
from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
-from pyams_content import _
-from pyams_content.interfaces import CREATE_VERSION_PERMISSION, MANAGE_CONTENT_PERMISSION, MANAGE_SITE_ROOT_PERMISSION, \
- PUBLISH_CONTENT_PERMISSION
-from pyams_content.interfaces import MANAGER_ROLE, OWNER_ROLE, PILOT_ROLE, READER_ROLE, WEBMASTER_ROLE
-from pyams_content.shared.common.interfaces import IManagerRestrictions, IWfSharedContentRoles
+from pyams_content.interfaces import CREATE_VERSION_PERMISSION, MANAGE_CONTENT_PERMISSION, \
+ MANAGE_SITE_ROOT_PERMISSION, PUBLISH_CONTENT_PERMISSION
+from pyams_content.interfaces import MANAGER_ROLE, OWNER_ROLE, PILOT_ROLE, READER_ROLE, \
+ WEBMASTER_ROLE
+from pyams_content.shared.common.interfaces import IContributorRestrictions, IManagerRestrictions, \
+ IWfSharedContentRoles
from pyams_content.workflow.interfaces import IContentWorkflow
from pyams_content.workflow.task import ContentArchivingTask, ContentPublishingTask
from pyams_scheduler.interfaces import IDateTaskScheduling, IScheduler
@@ -36,11 +35,17 @@
from pyams_utils.registry import get_utility, query_utility, utility_config
from pyams_utils.request import check_request
from pyams_utils.timezone import gmtime
-from pyams_workflow.interfaces import AUTOMATIC, IWorkflow, IWorkflowInfo, IWorkflowPublicationInfo, IWorkflowState, \
- IWorkflowStateLabel, IWorkflowVersions, ObjectClonedEvent, SYSTEM
+from pyams_workflow.interfaces import AUTOMATIC, IWorkflow, IWorkflowInfo, \
+ IWorkflowPublicationInfo, IWorkflowState, IWorkflowStateLabel, IWorkflowVersions, \
+ ObjectClonedEvent, SYSTEM
from pyams_workflow.workflow import Transition, Workflow
+__docformat__ = 'restructuredtext'
+
+from pyams_content import _
+
+
#
# Workflow states
#
@@ -137,12 +142,18 @@
principal_id = request.principal.id
if principal_id in context.owner | {context.creator} | context.contributors:
return True
+ # grant access to allowed contributors
+ restrictions = IContributorRestrictions(context).get_restrictions(principal_id)
+ if restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION,
+ request=request):
+ return True
# grant access to local content managers
if principal_id in context.managers:
return True
# grant access to shared tool managers if restrictions apply
restrictions = IManagerRestrictions(context).get_restrictions(principal_id)
- return restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION, request=request)
+ return restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION,
+ request=request)
def can_backdraft_content(wf, context):
@@ -173,6 +184,11 @@
principal_id = request.principal.id
if principal_id in context.owner | {context.creator} | context.contributors:
return True
+ # grant access to allowed contributors
+ restrictions = IContributorRestrictions(context).get_restrictions(principal_id)
+ if restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION,
+ request=request):
+ return True
# grant access to local content managers
if principal_id in context.managers:
return True
@@ -191,6 +207,11 @@
principal_id = request.principal.id
if principal_id in context.owner | {context.creator} | context.contributors:
return True
+ # grant access to allowed contributors
+ restrictions = IContributorRestrictions(context).get_restrictions(principal_id)
+ if restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION,
+ request=request):
+ return True
# grant access to local content managers
if principal_id in context.managers:
return True
@@ -227,6 +248,11 @@
# owner, creator and contributors can cancel workflow request
if principal_id in context.owner | {context.creator} | context.contributors:
return True
+ # grant access to allowed contributors
+ restrictions = IContributorRestrictions(context).get_restrictions(principal_id)
+ if restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION,
+ request=request):
+ return True
# local content managers can cancel workflow request
if principal_id in context.managers:
return True
--- a/src/pyams_content/workflow/basic.py Tue Oct 01 08:31:43 2019 +0200
+++ b/src/pyams_content/workflow/basic.py Tue Oct 01 12:04:20 2019 +0200
@@ -10,8 +10,6 @@
# FOR A PARTICULAR PURPOSE.
#
-__docformat__ = 'restructuredtext'
-
from datetime import datetime, timedelta
from zope.copy import copy
@@ -20,11 +18,10 @@
from zope.location import locate
from zope.schema.vocabulary import SimpleTerm, SimpleVocabulary
-from pyams_content import _
from pyams_content.interfaces import CREATE_VERSION_PERMISSION, MANAGER_ROLE, \
- MANAGE_CONTENT_PERMISSION, MANAGE_SITE_ROOT_PERMISSION, OWNER_ROLE, PILOT_ROLE, PUBLISH_CONTENT_PERMISSION, \
- READER_ROLE, WEBMASTER_ROLE
-from pyams_content.shared.common.interfaces import IManagerRestrictions
+ MANAGE_CONTENT_PERMISSION, MANAGE_SITE_ROOT_PERMISSION, OWNER_ROLE, PILOT_ROLE, \
+ PUBLISH_CONTENT_PERMISSION, READER_ROLE, WEBMASTER_ROLE
+from pyams_content.shared.common.interfaces import IContributorRestrictions, IManagerRestrictions
from pyams_content.shared.common.interfaces import IWfSharedContentRoles
from pyams_content.workflow import ContentArchivingTask, ContentPublishingTask
from pyams_content.workflow.interfaces import IBasicWorkflow
@@ -36,11 +33,16 @@
from pyams_utils.registry import get_current_registry, get_utility, query_utility, utility_config
from pyams_utils.request import check_request
from pyams_utils.timezone import gmtime
-from pyams_workflow.interfaces import IWorkflow, IWorkflowInfo, IWorkflowPublicationInfo, IWorkflowState, \
- IWorkflowStateLabel, IWorkflowVersions, ObjectClonedEvent, SYSTEM
+from pyams_workflow.interfaces import IWorkflow, IWorkflowInfo, IWorkflowPublicationInfo, \
+ IWorkflowState, IWorkflowStateLabel, IWorkflowVersions, ObjectClonedEvent, SYSTEM
from pyams_workflow.workflow import Transition, Workflow
+__docformat__ = 'restructuredtext'
+
+from pyams_content import _
+
+
DRAFT = 'draft'
PRE_PUBLISHED = 'pre-published'
PUBLISHED = 'published'
@@ -127,6 +129,11 @@
principal_id = request.principal.id
if principal_id in context.owner | {context.creator} | context.contributors:
return True
+ # grant access to allowed contributors
+ restrictions = IContributorRestrictions(context).get_restrictions(principal_id)
+ if restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION,
+ request=request):
+ return True
# grant access to local content managers
if principal_id in context.managers:
return True
@@ -145,6 +152,11 @@
principal_id = request.principal.id
if principal_id in context.owner | {context.creator} | context.contributors:
return True
+ # grant access to allowed contributors
+ restrictions = IContributorRestrictions(context).get_restrictions(principal_id)
+ if restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION,
+ request=request):
+ return True
# grant access to local content managers
if principal_id in context.managers:
return True