Assuming that you’re sure that implicit publication of links does not lead to unintended results (imagine that the editor looks like this: “I would put it in a draft state and decorate it with confidential comments, intended to be temporarily ready for publication, who the hell posted it? "), and that all content types have an assigned workflow, the code below is an implementation of the algorithm that you describe.
If you have content type elements that do not have an assigned workflow, an implicit publication will be required for the next top parent with the workflow assignment. But it also changes the inherited permissions of siblings or even cousins and aunts if the first parent also does not have an assigned workflow. However, you can do this, look for “ruthless” in the code and follow the comment instructions in this case, but assigning a workflow for all content types seems more appropriate here.
In order to draw attention to backlinks when the link item changes to a lower public state than the current state, a warning will be given to the user that he may not be available to the audience of the link item, so automatic “down-publishing” is undesirable, as Luke points out Fabbry.
The definition of which state is considered more public than another lives in PublicRank.states , you need to configure it for the state of the workflow you are using.
Ok, so this concerns two related files, first register two event handlers in your.addon/your/addon/configure.zcml :
<subscriber for="Products.CMFCore.interfaces.IContentish Products.CMFCore.interfaces.IActionSucceededEvent" handler=".subscriber.publishReferences" /> <subscriber for="Products.CMFCore.interfaces.IContentish Products.DCWorkflow.interfaces.IBeforeTransitionEvent" handler=".subscriber.warnAboutPossiblyInaccessibleBackReferences" />
Then add your.addon/your/addon/subscriber.py with the following contents:
from Products.statusmessages.interfaces import IStatusMessage from zope.globalrequest import getRequest class PublicRank: """ Define which state is to be considered more public than another, most public first. Assume for now, only Plone default workflow 'simple_publication_workflow' is used in the portal. """ states = ['published', 'pending', 'private'] def isMorePublic(state_one, state_two): """ Check if state_one has a lesser index in the rank than state_two. """ states = PublicRank.states if states.index(state_one) < states.index(state_two): return True else: return False def getState(obj): """ Return workflow-state-id or None, if no workflow is assigned. Show possible error on the console and log it. """ if hasWorkflow(obj): try: return obj.portal_workflow.getInfoFor(obj, 'review_state') except ExceptionError as err: obj.plone_log(err) else: return None def getTransitions(obj): """ Return the identifiers of the available transitions as a list. """ transitions = [] trans_dicts = obj.portal_workflow.getTransitionsFor(obj) for trans_dict in trans_dicts: transitions.append(trans_dict['id']) return transitions def hasWorkflow(obj): """ Return boolean, indicating whether obj has a workflow assigned, or not. """ return len(obj.portal_workflow.getWorkflowsFor(obj)) > 0 def hasTransition(obj, transition): if transition in getTransitions(obj): return True else: return False def isSite(obj): return len(obj.getPhysicalPath()) == 2 def publishReferences(obj, eve, RUHTLESS=False): """ If an obj gets published, publish its references, too. If an item doesn't have a workflow assigned and RUHTLESS is passed to be True, publish next upper parent with a workflow. """ states = PublicRank.states state = getState(obj) transition = eve.action if state in states: refs = obj.getRefs() for ref in refs: ref_state = getState(ref) if ref_state: if isMorePublic(state, ref_state): setState(ref, transition) else: