--- a/src/pyams_content/workflow/__init__.py Mon Sep 11 14:43:43 2017 +0200
+++ b/src/pyams_content/workflow/__init__.py Mon Sep 11 14:44:49 2017 +0200
@@ -17,13 +17,13 @@
from datetime import datetime
# import interfaces
-from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, MANAGE_CONTENT_PERMISSION, PUBLISH_CONTENT_PERMISSION, \
- CREATE_CONTENT_PERMISSION
-from pyams_content.shared.common.interfaces import IWfSharedContentRoles, IManagerRestrictions, IWfSharedContent
+from pyams_content.interfaces import MANAGE_SITE_ROOT_PERMISSION, MANAGE_CONTENT_PERMISSION, \
+ PUBLISH_CONTENT_PERMISSION, CREATE_CONTENT_PERMISSION
+from pyams_content.shared.common.interfaces import IWfSharedContentRoles, IManagerRestrictions
from pyams_content.workflow.interfaces import IContentWorkflow
from pyams_security.interfaces import IRoleProtectedObject
-from pyams_workflow.interfaces import IWorkflow, AUTOMATIC, IWorkflowPublicationInfo, SYSTEM, IWorkflowVersions, \
- IWorkflowState, ObjectClonedEvent, IWorkflowInfo, IWorkflowStateLabel
+from pyams_workflow.interfaces import ObjectClonedEvent, IWorkflow, IWorkflowVersions, IWorkflowInfo, \
+ IWorkflowState, IWorkflowStateLabel, IWorkflowPublicationInfo, AUTOMATIC, SYSTEM
# import packages
from pyams_utils.adapter import adapter_config, ContextAdapter
@@ -66,20 +66,6 @@
ARCHIVED,
DELETED)
-UPDATE_STATES = (DRAFT, RETIRED)
-
-READONLY_STATES = (ARCHIVED, DELETED)
-
-PROTECTED_STATES = (PUBLISHED, RETIRING, ARCHIVING)
-
-MANAGER_STATES = (PROPOSED, )
-
-VISIBLE_STATES = PUBLISHED_STATES = (PUBLISHED, RETIRING)
-
-WAITING_STATES = (PROPOSED, RETIRING, ARCHIVING)
-
-RETIRED_STATES = (RETIRED, ARCHIVING)
-
STATES_LABELS = (_("Draft"),
_("Proposed"),
_("Canceled"),
@@ -91,6 +77,9 @@
_("Archived"),
_("Deleted"))
+STATES_VOCABULARY = SimpleVocabulary([SimpleTerm(STATES_IDS[i], title=t)
+ for i, t in enumerate(STATES_LABELS)])
+
STATES_HEADERS = {DRAFT: _("draft created"),
PROPOSED: _("publication requested"),
PUBLISHED: _("published"),
@@ -99,8 +88,24 @@
ARCHIVING: _("archiving requested"),
ARCHIVED: _("archived")}
-STATES_VOCABULARY = SimpleVocabulary([SimpleTerm(STATES_IDS[i], title=t)
- for i, t in enumerate(STATES_LABELS)])
+
+UPDATE_STATES = (DRAFT, )
+'''Default state available to contributors in update mode'''
+
+READONLY_STATES = (RETIRED, ARCHIVING, ARCHIVED, DELETED)
+'''Retired and archived contents can't be modified'''
+
+PROTECTED_STATES = (PUBLISHED, RETIRING)
+'''Protected states are available to webmasters in update mode'''
+
+MANAGER_STATES = (PROPOSED, )
+'''Only managers can update proposed contents (if their restrictions apply)'''
+
+VISIBLE_STATES = PUBLISHED_STATES = (PUBLISHED, RETIRING)
+
+WAITING_STATES = (PROPOSED, RETIRING, ARCHIVING)
+
+RETIRED_STATES = (RETIRED, ARCHIVING)
#
@@ -109,15 +114,24 @@
def can_propose_content(wf, context):
"""Check if a content can be proposed"""
+ # can't propose content if another proposed version already exists
versions = IWorkflowVersions(context)
if versions.has_version(PROPOSED):
return False
request = check_request()
+ # grant access to webmaster
if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, context):
return True
- if request.principal.id in context.owner | {context.creator} | context.contributors:
+ # grant access to owner, creator and local contributors
+ principal_id = request.principal.id
+ if principal_id in context.owner | {context.creator} | context.contributors:
return True
- return False
+ # 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)
def can_backdraft_content(wf, context):
@@ -132,6 +146,7 @@
def can_create_new_version(wf, context):
"""Check if we can create a new version"""
+ # can't create new version when previous draft already exists
versions = IWorkflowVersions(context)
if (versions.has_version(DRAFT) or
versions.has_version(PROPOSED) or
@@ -139,40 +154,73 @@
versions.has_version(REFUSED)):
return False
request = check_request()
+ # grant access to webmaster
if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, context):
return True
- if request.principal.id in context.owner | {context.creator} | context.contributors:
+ # grant access to owner, creator and local contributors
+ principal_id = request.principal.id
+ if principal_id in context.owner | {context.creator} | context.contributors:
return True
- return False
+ # 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=CREATE_CONTENT_PERMISSION, request=request)
def can_delete_version(wf, context):
"""Check if we can delete a draft version"""
request = check_request()
+ # grant access to webmaster
if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, context):
return True
- return request.principal.id in context.owner | {context.creator} | context.contributors
+ # grant access to owner, creator and local contributors
+ principal_id = request.principal.id
+ if principal_id in context.owner | {context.creator} | context.contributors:
+ 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)
def can_manage_content(wf, context):
"""Check if a manager can handle content"""
request = check_request()
+ # grant access to webmaster
if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, context):
return True
- if request.principal.id in context.managers:
+ # local content managers can manage content
+ principal_id = request.principal.id
+ if principal_id in context.managers:
return True
- restrictions = IManagerRestrictions(context).get_restrictions(request.principal.id)
+ # shared tool managers can manage content if restrictions apply
+ restrictions = IManagerRestrictions(context).get_restrictions(principal_id)
return restrictions and restrictions.check_access(context, permission=PUBLISH_CONTENT_PERMISSION, request=request)
def can_cancel_operation(wf, context):
"""Check if we can cancel a request"""
request = check_request()
+ # grant access to webmaster
if request.has_permission(MANAGE_SITE_ROOT_PERMISSION, context):
return True
- if request.principal.id in context.owner | {context.creator} | context.contributors:
+ principal_id = request.principal.id
+ # workflow actor can cancel it's own request
+ if principal_id == IWorkflowState(context).state_principal:
+ return True
+ # owner, creator and contributors can cancel workflow request
+ if principal_id in context.owner | {context.creator} | context.contributors:
return True
- return request.principal.id == IWorkflowState(context).state_principal
+ # local content managers can cancel workflow request
+ if principal_id in context.managers:
+ return True
+ # shared tool managers can cancel workflow request if restrictions apply
+ restrictions = IManagerRestrictions(context).get_restrictions(principal_id)
+ return restrictions and restrictions.check_access(context, permission=MANAGE_CONTENT_PERMISSION, request=request)
#
@@ -189,7 +237,7 @@
version_id = IWorkflowState(context).version_id
for version in IWorkflowVersions(context).get_versions((PUBLISHED, RETIRING, RETIRED, ARCHIVING)):
if version is not context:
- IWorkflowInfo(version).fire_transition_toward('archived',
+ IWorkflowInfo(version).fire_transition_toward(ARCHIVED,
comment=translate(_("Published version {0}")).format(version_id))
@@ -341,6 +389,13 @@
notify_message=_("A retire request has been submitted for content « {0} »"),
order=7)
+published_to_retired = Transition(transition_id='published_to_retired',
+ title=_("Retired content"),
+ source=PUBLISHED,
+ destination=RETIRED,
+ trigger=SYSTEM,
+ history_label=_("Content retired after passed expiration date"))
+
retiring_to_published = Transition(transition_id='retiring_to_published',
title=_("Cancel retiring request"),
source=RETIRING,
@@ -515,6 +570,7 @@
refused_to_retired,
proposed_to_published,
published_to_retiring,
+ published_to_retired,
retiring_to_published,
retiring_to_retired,
retired_to_archiving,
@@ -563,7 +619,7 @@
request = check_request()
translate = request.localizer.translate
state = IWorkflowState(content)
- if len(state.history) == 1:
+ if len(state.history) <= 2:
if state.version_id == 1:
state_label = translate(STATES_HEADERS[state.state])
else:
@@ -585,7 +641,8 @@
manager_states=MANAGER_STATES,
published_states=VISIBLE_STATES,
waiting_states=WAITING_STATES,
- retired_states=RETIRED_STATES)
+ retired_states=RETIRED_STATES,
+ auto_retired_state=RETIRED)
@utility_config(name='PyAMS default workflow', provides=IWorkflow)