Back to index

plone3  3.1.7
remap.py
Go to the documentation of this file.
00001 import transaction
00002 
00003 SAVE_THRESHOLD = 100 # Do a savepoint every so often
00004 _marker = object()
00005 
00006 from Products.CMFCore.utils import getToolByName
00007 from Products.DCWorkflow.utils import modifyRolesForPermission
00008 from Globals import PersistentMapping
00009 from Acquisition import aq_base
00010 from DateTime import DateTime
00011 
00012 def remap_workflow(context, type_ids, chain, state_map={}):
00013     """Change the workflow for each type in type_ids to use the workflow
00014     chain given. state_map is a dictionary of old state names to
00015     new ones. States that are not found will be remapped to the default
00016     state of the new workflow.
00017     """
00018     
00019     if chain is None:
00020         chain = '(Default)'
00021 
00022     portal_workflow = getToolByName(context, 'portal_workflow')
00023     
00024     default_chain = portal_workflow.getDefaultChain()
00025     chains_by_type = dict(portal_workflow.listChainOverrides())
00026     
00027     # Build a dictionary of type id -> chain before we made changes
00028     old_chains = dict([(t, chains_by_type.get(t, default_chain)) for t in type_ids])
00029 
00030     # Work out which permissions were managed by the old chain, but not
00031     # by the new chain. This may vary by type id.
00032 
00033     # Update the workflow chain in portal_workflows.
00034      
00035     # XXX: There is no decent API for this it seems :-(
00036     if chain == '(Default)':
00037         cbt = portal_workflow._chains_by_type
00038         for type_id in type_ids:
00039             if cbt.has_key(type_id):
00040                 del cbt[type_id]
00041     else:
00042         portal_workflow.setChainForPortalTypes(type_ids, chain)
00043 
00044     # Now remap, and fix permissions
00045     
00046     # For each portal type, work out which workflows were controlling them
00047     # before, and which permissions were in that, which are not in the new
00048     # chain. These permissions need to be reset to 'Acquire'.
00049     
00050     chain_workflows = {}
00051     new_chain_permissions = set()
00052     permissions_to_reset = {}
00053 
00054     if chain == '(Default)':
00055         chain = default_chain
00056     for c in chain:
00057         if c not in chain_workflows:
00058             chain_workflows[c] = getattr(portal_workflow, c)
00059             for permission in chain_workflows[c].permissions:
00060                 new_chain_permissions.add(permission)
00061 
00062     for typeid, oc in old_chains.items():
00063         if oc == '(Default)':
00064             oc = default_chain
00065         permissions_to_reset[typeid] = set()
00066         for c in oc:
00067             if c not in chain_workflows:
00068                 chain_workflows[c] = getattr(portal_workflow, c)
00069             for permission in chain_workflows[c].permissions:
00070                 if permission not in new_chain_permissions:
00071                     permissions_to_reset[typeid].add(permission)
00072     
00073     portal_catalog = getToolByName(context, 'portal_catalog')
00074     
00075     # Then update the state of each
00076     remapped_count = 0
00077     threshold_count = 0
00078     for brain in portal_catalog(portal_type=type_ids):
00079         obj = brain.getObject()
00080         portal_type = brain.portal_type
00081         
00082         # If there are permissions to reset to acquire, do so now
00083         for permission in permissions_to_reset[brain.portal_type]:
00084             # A list makes it acquire ... if it was a tuple, it wouldn't
00085             modifyRolesForPermission(obj, permission, [])
00086         
00087         # Work out what, if any, the previous state of the object was
00088         
00089         if len(chain) > 0:
00090             old_chain = old_chains[portal_type]
00091             old_wf = None
00092             if len(old_chain) > 0:
00093                 old_wf = chain_workflows[old_chain[0]]
00094         
00095             old_state = None
00096             if old_wf is not None:
00097                 old_status = portal_workflow.getStatusOf(old_wf.getId(), obj)
00098                 if old_status is not None:
00099                     old_state = old_status.get('review_state', None)
00100             
00101             # Now add a transition
00102             for new_wf_name in chain:
00103                 new_wf = chain_workflows[new_wf_name]
00104                 new_status = { 'action'       : None,
00105                                'actor'        : None, 
00106                                'comments'     : 'State remapped from control panel',
00107                                'review_state' : state_map.get(old_state, new_wf.initial_state),
00108                                'time'         : DateTime()}
00109                 portal_workflow.setStatusOf(new_wf_name, obj, new_status)
00110             
00111                 # Trigger any automatic transitions, or else just make sure the role mappings are right
00112                 auto_transition = new_wf._findAutomaticTransition(obj, new_wf._getWorkflowStateOf(obj))
00113                 if auto_transition is not None:
00114                     new_wf._changeStateOf(obj, auto_transition)
00115                 else:
00116                     new_wf.updateRoleMappingsFor(obj)
00117 
00118         obj.reindexObject(idxs=['allowedRolesAndUsers', 'review_state'])
00119         
00120         remapped_count += 1
00121         threshold_count += 1
00122         
00123         if threshold_count > SAVE_THRESHOLD:
00124             transaction.savepoint()
00125             threshold_count = 0
00126             
00127     return remapped_count