# HG changeset patch # User Thierry Florac # Date 1569924260 -7200 # Node ID c682811fa1ea76a3e2d9bd14ce01d374ed6d1c37 # Parent 329116e5f8e3707d0880f8a5b364ed679e6e4165 Added contributors restrictions to allow a contributor to manage contents owned by other principals diff -r 329116e5f8e3 -r c682811fa1ea src/pyams_content/shared/common/interfaces/__init__.py --- 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): diff -r 329116e5f8e3 -r c682811fa1ea src/pyams_content/shared/common/security.py --- 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) diff -r 329116e5f8e3 -r c682811fa1ea src/pyams_content/shared/common/zmi/__init__.py --- 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 += ''.format( - translate(_("Created or modified in this version"))) + translate(_("Created or modified in this version"))) return value diff -r 329116e5f8e3 -r c682811fa1ea src/pyams_content/workflow/__init__.py --- 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 diff -r 329116e5f8e3 -r c682811fa1ea src/pyams_content/workflow/basic.py --- 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