Commit 50418dfb 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 a46fc230
......@@ -72,7 +72,7 @@ from Products.ERP5Type.patches.ppml import importXML
customImporters={
XMLExportImport.magic: importXML,
}
from Products.ERP5Type.patches.WorkflowTool import WorkflowHistoryList
from zLOG import LOG, WARNING, INFO
from warnings import warn
from gzip import GzipFile
......@@ -537,7 +537,16 @@ class BaseTemplateItem(Implicit, Persistent):
def importFile(self, bta, **kw):
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
"""
......@@ -549,7 +558,9 @@ class BaseTemplateItem(Implicit, Persistent):
'last_id', 'uid',
'__ac_local_roles__', '__ac_local_roles_group_id_dict__'))
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')
# PythonScript covers both Zope Python scripts
# and ERP5 Python Scripts
......@@ -676,8 +687,9 @@ class ObjectTemplateItem(BaseTemplateItem):
relative_url = '/'.join([url,id])
obj = p.unrestrictedTraverse(relative_url)
obj = obj._getCopy(context)
keep_workflow_history = self.isKeepWorkflowObject(relative_url)
obj = self.removeProperties(obj, 1, keep_workflow_history)
obj = self.removeProperties(obj, 1,
self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
id_list = obj.objectIds() # FIXME duplicated variable name
if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead
# we must keep groups because they are deleted along with subobjects
......@@ -704,8 +716,9 @@ class ObjectTemplateItem(BaseTemplateItem):
except AttributeError:
raise AttributeError, "Could not find object '%s' during business template processing." % relative_url
_recursiveRemoveUid(obj)
keep_workflow_history = self.isKeepWorkflowObject(relative_url)
obj = self.removeProperties(obj, 1, keep_workflow_history)
obj = self.removeProperties(obj, 1,
self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
id_list = obj.objectIds()
if hasattr(aq_base(obj), 'groups'): # XXX should check metatype instead
# we must keep groups because they are deleted along with subobjects
......@@ -1457,8 +1470,9 @@ class PathTemplateItem(ObjectTemplateItem):
obj = obj.__of__(context)
_recursiveRemoveUid(obj)
id_list = obj.objectIds()
keep_workflow_history = self.isKeepWorkflowObject(relative_url)
obj = self.removeProperties(obj, 1, keep_workflow_history)
obj = self.removeProperties(obj, 1,
self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
if hasattr(aq_base(obj), 'groups'):
# we must keep groups because it's ereased when we delete subobjects
groups = deepcopy(obj.groups)
......@@ -1610,8 +1624,9 @@ class CategoryTemplateItem(ObjectTemplateItem):
relative_url = '/'.join([url,id])
obj = p.unrestrictedTraverse(relative_url)
obj = obj._getCopy(context)
keep_workflow_history = self.isKeepWorkflowObject(relative_url)
obj = self.removeProperties(obj, 1, keep_workflow_history)
obj = self.removeProperties(obj, 1,
self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
id_list = obj.objectIds()
if id_list:
self.build_sub_objects(context, id_list, relative_url)
......@@ -1633,8 +1648,9 @@ class CategoryTemplateItem(ObjectTemplateItem):
else:
raise ValueError, "%s not found" % relative_url
_recursiveRemoveUid(obj)
keep_workflow_history = self.isKeepWorkflowObject(relative_url)
obj = self.removeProperties(obj, 1, keep_workflow_history)
obj = self.removeProperties(obj, 1,
self.isKeepWorkflowObject(relative_url),
self.isKeepWorkflowObjectLastHistoryOnly(relative_url))
include_sub_categories = obj.__of__(context).getProperty('business_template_include_sub_categories', 0)
id_list = obj.objectIds()
if len(id_list) > 0 and include_sub_categories:
......@@ -2982,8 +2998,11 @@ class ActionTemplateItem(ObjectTemplateItem):
continue
raise NotFound('Action %r not found' % id)
key = posixpath.join(url[-2], url[-1], value)
keep_workflow_history = self.isKeepWorkflowObject(key)
self._objects[key] = self.removeProperties(action, 1, keep_workflow_history)
self._objects[key] = self.removeProperties(
action, 1,
self.isKeepWorkflowObject(key),
self.isKeepWorkflowObjectLastHistoryOnly(key))
self._objects[key].wl_clearLocks()
def install(self, context, trashbin, **kw):
......@@ -4037,6 +4056,20 @@ class DocumentTemplateItem(FilesystemToZodbTemplateItem):
"Document",
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):
"""
Upon import, only consider XML file for ZODB Components (as the Python
......@@ -5580,11 +5613,7 @@ Business Template is a set of definitions, such as skins, portal types and categ
"""
return self._getOrderedList('template_tool_id')
def isKeepObject(self, path):
"""
Return True if path is included in keep object list.
"""
keep_list = self.getTemplateKeepPathList()
def _isInKeepList(self, keep_list, path):
for keep_path in keep_list:
if keep_path.endswith('**') and path.startswith(keep_path[:-2]):
return True
......@@ -5592,17 +5621,24 @@ Business Template is a set of definitions, such as skins, portal types and categ
return True
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):
"""
Return True if path is included in keep workflow object list.
"""
keep_list = self.getTemplateKeepWorkflowPathList()
for keep_path in keep_list:
if keep_path.endswith('**') and path.startswith(keep_path[:-2]):
return True
elif path == keep_path:
return True
return False
return self._isInKeepList(self.getTemplateKeepWorkflowPathList(), path)
def isKeepWorkflowObjectLastHistoryOnly(self, path):
"""
Return True if path is included in keep workflow last state only list
"""
return self._isInKeepList(self.getTemplateKeepLastWorkflowHistoryOnlyPathList(),
path)
def getExportPath(self):
preferences = self.getPortalObject().portal_preferences
......@@ -6154,11 +6190,11 @@ Business Template is a set of definitions, such as skins, portal types and categ
if migrated_id_list:
template_id_list_method(migrated_id_list)
path_list = self.getTemplateKeepWorkflowPathList()
path_list = self.getTemplateKeepLastWorkflowHistoryOnlyPathList()
path_list.extend([ ('portal_components/' + id_)
for id_ in migrated_id_list ])
self.setTemplateKeepWorkflowPathList(path_list)
self.setTemplateKeepLastWorkflowHistoryOnlyPathList(path_list)
component_dict = component_portal_type_dict.get('Document Component')
if component_dict:
......
......@@ -78,6 +78,7 @@
<string>my_template_path_list</string>
<string>my_template_keep_path_list</string>
<string>my_template_keep_workflow_path_list</string>
<string>my_template_keep_last_workflow_history_only_path_list</string>
</list>
</value>
</item>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="LinesField" module="Products.Formulator.StandardFields"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>id</string> </key>
<value> <string>my_template_keep_last_workflow_history_only_path_list</string> </value>
</item>
<item>
<key> <string>message_values</string> </key>
<value>
<dictionary>
<item>
<key> <string>external_validator_failed</string> </key>
<value> <string>The input failed the external validator.</string> </value>
</item>
<item>
<key> <string>line_too_long</string> </key>
<value> <string>A line was too long.</string> </value>
</item>
<item>
<key> <string>required_not_found</string> </key>
<value> <string>Input is required but no input given.</string> </value>
</item>
<item>
<key> <string>too_long</string> </key>
<value> <string>You entered too many characters.</string> </value>
</item>
<item>
<key> <string>too_many_lines</string> </key>
<value> <string>You entered too many lines.</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>overrides</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>tales</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>values</string> </key>
<value>
<dictionary>
<item>
<key> <string>alternate_name</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>css_class</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>default</string> </key>
<value>
<list/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>editable</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>enabled</string> </key>
<value> <int>1</int> </value>
</item>
<item>
<key> <string>external_validator</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>extra</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>10</int> </value>
</item>
<item>
<key> <string>hidden</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>max_length</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_linelength</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>max_lines</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>required</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string>Path of Objects whose Last Workflow History only should be Exported</string> </value>
</item>
<item>
<key> <string>unicode</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>view_separator</string> </key>
<value> <string encoding="cdata"><![CDATA[
<br />
]]></string> </value>
</item>
<item>
<key> <string>whitespace_preserve</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>width</string> </key>
<value> <int>80</int> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
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
* ZODB Components: ID and Reference may be quite long so make fields wider in Component_view.
......
41109
\ No newline at end of file
41110
\ 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
* ZODB Components: Add error and warning property for Components.
......
62
\ No newline at end of file
63
\ No newline at end of file
......@@ -7410,20 +7410,38 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
sequence['current_bt'].setProperty(self.template_property,
sequence['document_id'])
sequence['current_bt'].setTemplateKeepWorkflowPathList(
sequence['current_bt'].setTemplateKeepLastWorkflowHistoryOnlyPathList(
'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):
self.getPortalObject().portal_components.deleteContent(
sequence['document_id'])
def stepCheckZodbDocumentExistsAndValidated(self, sequence=None, **kw):
self.assertHasAttribute(self.getPortalObject().portal_components,
sequence['document_id'])
component = getattr(self.getPortalObject().portal_components,
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,
sequence['document_id']).getValidationState(),
'validated')
self.assertEquals(validation_state_only_list, ['validated'])
def stepCheckZodbDocumentRemoved(self, sequence=None, **kw):
component_tool = self.getPortalObject().portal_components
......@@ -7479,6 +7497,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckForkedMigrationExport \
CheckBuiltBuildingState \
CheckNotInstalledInstallationState \
CheckZodbDocumentWorkflowHistoryUnchanged \
RemoveZodbDocument \
RemoveBusinessTemplate \
RemoveAllTrashBins \
......@@ -7544,6 +7563,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckForkedMigrationExport \
CheckBuiltBuildingState \
CheckNotInstalledInstallationState \
CheckZodbDocumentWorkflowHistoryUnchanged \
RemoveZodbDocument \
RemoveBusinessTemplate \
RemoveAllTrashBins \
......@@ -7592,7 +7612,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
component_id = '%s.erp5.%s' % (self.component_module,
sequence.get('document_title'))
self.assertEquals(bt.getTemplateKeepWorkflowPathList(),
self.assertEquals(bt.getTemplateKeepLastWorkflowHistoryOnlyPathList(),
['portal_components/' + component_id])
self.assertEquals(bt.getProperty(self.template_property),
......@@ -7657,6 +7677,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckBuiltBuildingState \
CheckNotInstalledInstallationState \
RemoveBusinessTemplate \
CheckZodbDocumentWorkflowHistoryUnchanged \
RemoveZodbDocument \
Tic \
ImportBusinessTemplate \
......@@ -7709,6 +7730,7 @@ class TestDocumentTemplateItem(BusinessTemplateMixin):
CheckNotInstalledInstallationState
SaveBusinessTemplate
RemoveBusinessTemplate
CheckZodbDocumentWorkflowHistoryUnchanged
RemoveZodbDocument
CheckDocumentExists
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