Commit c8329138 authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Export only the last Workflow History.

Only the source code and the last workflow history is actually relevant, so
remove all Workflow History except the last one to minimize diffs.

This adds a property to BusinessTemplate for generic behavior, overriden for
ZODB Components to ignore all Workflows except component_validation_workflow.
parent 15483206
...@@ -73,7 +73,7 @@ from Products.ERP5Type.patches.ppml import importXML ...@@ -73,7 +73,7 @@ from Products.ERP5Type.patches.ppml import importXML
customImporters={ customImporters={
XMLExportImport.magic: importXML, XMLExportImport.magic: importXML,
} }
from Products.ERP5Type.patches.WorkflowTool import WorkflowHistoryList
from zLOG import LOG, WARNING, INFO from zLOG import LOG, WARNING, INFO
from warnings import warn from warnings import warn
from gzip import GzipFile from gzip import GzipFile
...@@ -537,7 +537,16 @@ class BaseTemplateItem(Implicit, Persistent): ...@@ -537,7 +537,16 @@ class BaseTemplateItem(Implicit, Persistent):
def importFile(self, bta, **kw): def importFile(self, bta, **kw):
bta.importFiles(item=self) bta.importFiles(item=self)
def removeProperties(self, obj, export, keep_workflow_history=False): def _removeAllButLastWorkflowHistory(self, obj):
for workflow_id in obj.workflow_history.keys():
obj.workflow_history[workflow_id] = WorkflowHistoryList(
obj.workflow_history[workflow_id][-1])
def removeProperties(self,
obj,
export,
keep_workflow_history=False,
keep_workflow_history_last_history_only=False):
""" """
Remove unneeded properties for export Remove unneeded properties for export
""" """
...@@ -549,7 +558,9 @@ class BaseTemplateItem(Implicit, Persistent): ...@@ -549,7 +558,9 @@ class BaseTemplateItem(Implicit, Persistent):
'last_id', 'uid', 'last_id', 'uid',
'__ac_local_roles__', '__ac_local_roles_group_id_dict__')) '__ac_local_roles__', '__ac_local_roles_group_id_dict__'))
if export: if export:
if not keep_workflow_history: if keep_workflow_history_last_history_only:
self._removeAllButLastWorkflowHistory(obj)
elif not keep_workflow_history:
attr_set.add('workflow_history') attr_set.add('workflow_history')
# PythonScript covers both Zope Python scripts # PythonScript covers both Zope Python scripts
# and ERP5 Python Scripts # and ERP5 Python Scripts
...@@ -676,8 +687,9 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -676,8 +687,9 @@ class ObjectTemplateItem(BaseTemplateItem):
relative_url = '/'.join([url,id]) relative_url = '/'.join([url,id])
obj = p.unrestrictedTraverse(relative_url) obj = p.unrestrictedTraverse(relative_url)
obj = obj._getCopy(context) obj = obj._getCopy(context)
keep_workflow_history = self.isKeepWorkflowObject(relative_url) obj = self.removeProperties(obj, 1,
obj = self.removeProperties(obj, 1, keep_workflow_history) self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
id_list = obj.objectIds() # FIXME duplicated variable name id_list = obj.objectIds() # FIXME duplicated variable name
if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead
# we must keep groups because they are deleted along with subobjects # we must keep groups because they are deleted along with subobjects
...@@ -704,8 +716,9 @@ class ObjectTemplateItem(BaseTemplateItem): ...@@ -704,8 +716,9 @@ class ObjectTemplateItem(BaseTemplateItem):
except AttributeError: except AttributeError:
raise AttributeError, "Could not find object '%s' during business template processing." % relative_url raise AttributeError, "Could not find object '%s' during business template processing." % relative_url
_recursiveRemoveUid(obj) _recursiveRemoveUid(obj)
keep_workflow_history = self.isKeepWorkflowObject(relative_url) obj = self.removeProperties(obj, 1,
obj = self.removeProperties(obj, 1, keep_workflow_history) self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
id_list = obj.objectIds() id_list = obj.objectIds()
if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead
# we must keep groups because they are deleted along with subobjects # we must keep groups because they are deleted along with subobjects
...@@ -1386,8 +1399,9 @@ class PathTemplateItem(ObjectTemplateItem): ...@@ -1386,8 +1399,9 @@ class PathTemplateItem(ObjectTemplateItem):
obj = obj.__of__(context) obj = obj.__of__(context)
_recursiveRemoveUid(obj) _recursiveRemoveUid(obj)
id_list = obj.objectIds() id_list = obj.objectIds()
keep_workflow_history = self.isKeepWorkflowObject(relative_url) obj = self.removeProperties(obj, 1,
obj = self.removeProperties(obj, 1, keep_workflow_history) self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
if hasattr(aq_base(obj), 'groups'): if hasattr(aq_base(obj), 'groups'):
# we must keep groups because it's ereased when we delete subobjects # we must keep groups because it's ereased when we delete subobjects
groups = deepcopy(obj.groups) groups = deepcopy(obj.groups)
...@@ -1547,8 +1561,9 @@ class CategoryTemplateItem(ObjectTemplateItem): ...@@ -1547,8 +1561,9 @@ class CategoryTemplateItem(ObjectTemplateItem):
relative_url = '/'.join([url,id]) relative_url = '/'.join([url,id])
obj = p.unrestrictedTraverse(relative_url) obj = p.unrestrictedTraverse(relative_url)
obj = obj._getCopy(context) obj = obj._getCopy(context)
keep_workflow_history = self.isKeepWorkflowObject(relative_url) obj = self.removeProperties(obj, 1,
obj = self.removeProperties(obj, 1, keep_workflow_history) self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
id_list = obj.objectIds() id_list = obj.objectIds()
if id_list: if id_list:
self.build_sub_objects(context, id_list, relative_url) self.build_sub_objects(context, id_list, relative_url)
...@@ -1570,8 +1585,9 @@ class CategoryTemplateItem(ObjectTemplateItem): ...@@ -1570,8 +1585,9 @@ class CategoryTemplateItem(ObjectTemplateItem):
else: else:
raise ValueError, "%s not found" % relative_url raise ValueError, "%s not found" % relative_url
_recursiveRemoveUid(obj) _recursiveRemoveUid(obj)
keep_workflow_history = self.isKeepWorkflowObject(relative_url) obj = self.removeProperties(obj, 1,
obj = self.removeProperties(obj, 1, keep_workflow_history) self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
include_sub_categories = obj.__of__(context).getProperty('business_template_include_sub_categories', 0) include_sub_categories = obj.__of__(context).getProperty('business_template_include_sub_categories', 0)
id_list = obj.objectIds() id_list = obj.objectIds()
if len(id_list) > 0 and include_sub_categories: if len(id_list) > 0 and include_sub_categories:
...@@ -2919,8 +2935,11 @@ class ActionTemplateItem(ObjectTemplateItem): ...@@ -2919,8 +2935,11 @@ class ActionTemplateItem(ObjectTemplateItem):
continue continue
raise NotFound('Action %r not found' % id) raise NotFound('Action %r not found' % id)
key = posixpath.join(url[-2], url[-1], value) key = posixpath.join(url[-2], url[-1], value)
keep_workflow_history = self.isKeepWorkflowObject(key) self._objects[key] = self.removeProperties(
self._objects[key] = self.removeProperties(action, 1, keep_workflow_history) action, 1,
self.isKeepWorkflowObject(key),
self.isKeepWorkflowObjectLastHistoryOnly(key))
self._objects[key].wl_clearLocks() self._objects[key].wl_clearLocks()
def install(self, context, trashbin, **kw): def install(self, context, trashbin, **kw):
...@@ -3974,6 +3993,20 @@ class DocumentTemplateItem(FilesystemToZodbTemplateItem): ...@@ -3974,6 +3993,20 @@ class DocumentTemplateItem(FilesystemToZodbTemplateItem):
"Document", "Document",
class_id + ".py") class_id + ".py")
def _removeAllButLastWorkflowHistory(self, obj):
"""
Only export the last state of component_validation_workflow, because only
the source code and its state to load it is necessary for ZODB Components
and too much history would be exported (edit_workflow)
"""
for wf_id in obj.workflow_history.keys():
if wf_id != 'component_validation_workflow':
del obj.workflow_history[wf_id]
continue
wf_history_list = obj.workflow_history[wf_id]
obj.workflow_history[wf_id] = WorkflowHistoryList([wf_history_list[-1]])
def _importFile(self, file_name, file_obj): def _importFile(self, file_name, file_obj):
""" """
Upon import, only consider XML file for ZODB Components (as the Python Upon import, only consider XML file for ZODB Components (as the Python
...@@ -5508,11 +5541,7 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5508,11 +5541,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
""" """
return self._getOrderedList('template_tool_id') return self._getOrderedList('template_tool_id')
def isKeepObject(self, path): def _isInKeepList(self, keep_list, path):
"""
Return True if path is included in keep object list.
"""
keep_list = self.getTemplateKeepPathList()
for keep_path in keep_list: for keep_path in keep_list:
if keep_path.endswith('**') and path.startswith(keep_path[:-2]): if keep_path.endswith('**') and path.startswith(keep_path[:-2]):
return True return True
...@@ -5520,17 +5549,24 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -5520,17 +5549,24 @@ Business Template is a set of definitions, such as skins, portal types and categ
return True return True
return False return False
def isKeepObject(self, path):
"""
Return True if path is included in keep object list.
"""
return self._isInKeepList(self.getTemplateKeepPathList(), path)
def isKeepWorkflowObject(self, path): def isKeepWorkflowObject(self, path):
""" """
Return True if path is included in keep workflow object list. Return True if path is included in keep workflow object list.
""" """
keep_list = self.getTemplateKeepWorkflowPathList() return self._isInKeepList(self.getTemplateKeepWorkflowPathList(), path)
for keep_path in keep_list:
if keep_path.endswith('**') and path.startswith(keep_path[:-2]): def isKeepWorkflowObjectLastHistoryOnly(self, path):
return True """
elif path == keep_path: Return True if path is included in keep workflow last state only list
return True """
return False return self._isInKeepList(self.getTemplateKeepLastWorkflowHistoryOnlyPathList(),
path)
def getExportPath(self): def getExportPath(self):
preferences = self.getPortalObject().portal_preferences preferences = self.getPortalObject().portal_preferences
...@@ -6085,11 +6121,11 @@ Business Template is a set of definitions, such as skins, portal types and categ ...@@ -6085,11 +6121,11 @@ Business Template is a set of definitions, such as skins, portal types and categ
if migrated_id_list: if migrated_id_list:
template_id_list_method(migrated_id_list) template_id_list_method(migrated_id_list)
path_list = self.getTemplateKeepWorkflowPathList() path_list = self.getTemplateKeepLastWorkflowHistoryOnlyPathList()
path_list.extend([ ('portal_components/' + id_) path_list.extend([ ('portal_components/' + id_)
for id_ in migrated_id_list ]) for id_ in migrated_id_list ])
self.setTemplateKeepWorkflowPathList(path_list) self.setTemplateKeepLastWorkflowHistoryOnlyPathList(path_list)
component_dict = component_portal_type_dict.get('Document Component') component_dict = component_portal_type_dict.get('Document Component')
if component_dict: if component_dict:
......
...@@ -78,6 +78,7 @@ ...@@ -78,6 +78,7 @@
<string>my_template_path_list</string> <string>my_template_path_list</string>
<string>my_template_keep_path_list</string> <string>my_template_keep_path_list</string>
<string>my_template_keep_workflow_path_list</string> <string>my_template_keep_workflow_path_list</string>
<string>my_template_keep_last_workflow_history_only_path_list</string>
</list> </list>
</value> </value>
</item> </item>
......
2013-08-20 arnaud.fontaine
* ZODB Components: Add field to specify the object paths whose only last workflow history must be kept.
2013-08-20 arnaud.fontaine 2013-08-20 arnaud.fontaine
* ZODB Components: ID and Reference may be quite long so make fields wider in Component_view. * ZODB Components: ID and Reference may be quite long so make fields wider in Component_view.
......
41120 41121
\ No newline at end of file \ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Standard Property" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>categories</string> </key>
<value>
<tuple>
<string>elementary_type/lines</string>
</tuple>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string>A list of object paths where only the last workflow history will be kept</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_keep_last_workflow_history_only_path_property</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Standard Property</string> </value>
</item>
<item>
<key> <string>property_default</string> </key>
<value> <string>python: ()</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
2013-08-20 arnaud.fontaine
* ZODB Components: Add BusinessTemplate property to specify the object paths whose only last workflow history must be kept on export.
2013-08-15 arnaud.fontaine 2013-08-15 arnaud.fontaine
* ZODB Components: Add error and warning property for Components. * ZODB Components: Add error and warning property for Components.
......
63 64
\ No newline at end of file \ No newline at end of file
...@@ -7225,20 +7225,38 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): ...@@ -7225,20 +7225,38 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
sequence['current_bt'].setProperty(self.template_property, sequence['current_bt'].setProperty(self.template_property,
sequence['document_id']) sequence['document_id'])
sequence['current_bt'].setTemplateKeepWorkflowPathList( sequence['current_bt'].setTemplateKeepLastWorkflowHistoryOnlyPathList(
'portal_components/' + sequence['document_id']) 'portal_components/' + sequence['document_id'])
def stepCheckZodbDocumentWorkflowHistoryUnchanged(self, sequence=None, **kw):
component = getattr(self.getPortalObject().portal_components,
sequence['document_id'], None)
self.assertNotEqual(component, None)
self.assertEquals(sorted(list(component.workflow_history)),
['component_validation_workflow', 'edit_workflow'])
self.failIf(len(component.workflow_history['component_validation_workflow']) <= 1)
def stepRemoveZodbDocument(self, sequence=None, **kw): def stepRemoveZodbDocument(self, sequence=None, **kw):
self.getPortalObject().portal_components.deleteContent( self.getPortalObject().portal_components.deleteContent(
sequence['document_id']) sequence['document_id'])
def stepCheckZodbDocumentExistsAndValidated(self, sequence=None, **kw): def stepCheckZodbDocumentExistsAndValidated(self, sequence=None, **kw):
self.assertHasAttribute(self.getPortalObject().portal_components, component = getattr(self.getPortalObject().portal_components,
sequence['document_id']) sequence['document_id'], None)
self.assertNotEqual(component, None)
self.assertEquals(component.getValidationState(), 'validated')
# Only the last Workflow History should have been exported
self.assertEquals(list(component.workflow_history),
['component_validation_workflow'])
validation_state_only_list = []
for validation_dict in list(component.workflow_history['component_validation_workflow']):
validation_state_only_list.append(validation_dict.get('validation_state'))
self.assertEquals(getattr(self.getPortalObject().portal_components, self.assertEquals(validation_state_only_list, ['validated'])
sequence['document_id']).getValidationState(),
'validated')
def stepCheckZodbDocumentRemoved(self, sequence=None, **kw): def stepCheckZodbDocumentRemoved(self, sequence=None, **kw):
component_tool = self.getPortalObject().portal_components component_tool = self.getPortalObject().portal_components
...@@ -7294,6 +7312,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): ...@@ -7294,6 +7312,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckForkedMigrationExport \ CheckForkedMigrationExport \
CheckBuiltBuildingState \ CheckBuiltBuildingState \
CheckNotInstalledInstallationState \ CheckNotInstalledInstallationState \
CheckZodbDocumentWorkflowHistoryUnchanged \
RemoveZodbDocument \ RemoveZodbDocument \
RemoveBusinessTemplate \ RemoveBusinessTemplate \
RemoveAllTrashBins \ RemoveAllTrashBins \
...@@ -7359,6 +7378,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): ...@@ -7359,6 +7378,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckForkedMigrationExport \ CheckForkedMigrationExport \
CheckBuiltBuildingState \ CheckBuiltBuildingState \
CheckNotInstalledInstallationState \ CheckNotInstalledInstallationState \
CheckZodbDocumentWorkflowHistoryUnchanged \
RemoveZodbDocument \ RemoveZodbDocument \
RemoveBusinessTemplate \ RemoveBusinessTemplate \
RemoveAllTrashBins \ RemoveAllTrashBins \
...@@ -7407,7 +7427,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): ...@@ -7407,7 +7427,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
component_id = '%s.erp5.%s' % (self.component_module, component_id = '%s.erp5.%s' % (self.component_module,
sequence.get('document_title')) sequence.get('document_title'))
self.assertEquals(bt.getTemplateKeepWorkflowPathList(), self.assertEquals(bt.getTemplateKeepLastWorkflowHistoryOnlyPathList(),
['portal_components/' + component_id]) ['portal_components/' + component_id])
self.assertEquals(bt.getProperty(self.template_property), self.assertEquals(bt.getProperty(self.template_property),
...@@ -7472,6 +7492,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): ...@@ -7472,6 +7492,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckBuiltBuildingState \ CheckBuiltBuildingState \
CheckNotInstalledInstallationState \ CheckNotInstalledInstallationState \
RemoveBusinessTemplate \ RemoveBusinessTemplate \
CheckZodbDocumentWorkflowHistoryUnchanged \
RemoveZodbDocument \ RemoveZodbDocument \
Tic \ Tic \
ImportBusinessTemplate \ ImportBusinessTemplate \
...@@ -7524,6 +7545,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin): ...@@ -7524,6 +7545,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckNotInstalledInstallationState CheckNotInstalledInstallationState
SaveBusinessTemplate SaveBusinessTemplate
RemoveBusinessTemplate RemoveBusinessTemplate
CheckZodbDocumentWorkflowHistoryUnchanged
RemoveZodbDocument RemoveZodbDocument
CheckDocumentExists CheckDocumentExists
CheckZodbDocumentRemoved CheckZodbDocumentRemoved
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment