Commit 337a2213 authored by Sebastien Robin's avatar Sebastien Robin

many updates made when the cvs was down


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@118 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent b374861f
......@@ -27,21 +27,22 @@
##############################################################################
from Products.ERP5SyncML.SyncCode import SyncCode
from Products.ERP5SyncML.XMLSyncUtils import XMLSyncUtilsMixin
from Products.ERP5SyncML.Subscription import Conflict
from Products.CMFCore.utils import getToolByName
from Products.ERP5SyncML.XupdateUtils import XupdateUtils
from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Type.Accessor.TypeDefinition import list_types
from xml.dom.ext.reader.Sax2 import FromXml
from DateTime.DateTime import DateTime
from email.MIMEBase import MIMEBase
from email import Encoders
import sre
import re, copy
from zLOG import LOG
class ERP5Conduit(SyncCode):
class ERP5Conduit(XMLSyncUtilsMixin):
"""
A conduit is a piece of code in charge of
......@@ -63,10 +64,22 @@ class ERP5Conduit(SyncCode):
a default class. This will be defined at the level of the synchronisation
tool
"""
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx
Look carefully when we are adding elements,
for example, when we do 'insert-after', with 2 xupdate:element,
so adding 2 differents objects, actually it adds only XXXX one XXX object
In this case the getSubObjectDepth(), doesn't have
too much sence
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
There is also one problem, when we synchronize a conflict, we are not waiting
the response of the client, so that we are not sure if it take into account,
we may have CONFLICT_NOT_SYNCHRONIZED AND CONFLICT_SYNCHRONIZED
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
NOT_EDITABLE_PROPERTY = ('id','object','workflow_history','security_info','uid'
'xupdate:element','xupdate:attribute')
"""
def getEncoding(self):
......@@ -75,18 +88,9 @@ class ERP5Conduit(SyncCode):
"""
return "iso-8859-1"
def __init__(self):
self.args = {}
def applyModification(object=None):
"""
This will apply all updates
"""
args = self.args
def addNode(self, xml=None, object=None, previous_xml=None, force=0, **kw):
"""
A node is added
......@@ -96,69 +100,76 @@ class ERP5Conduit(SyncCode):
[object.getPath(),keyword,local_and_actual_value,remote_value]
"""
conflict_list = []
xml = self.convertToXML(xml)
xml = self.convertToXml(xml)
LOG('addNode',0,'xml_reconstitued: %s' % str(xml))
# In the case where this new node is a object to add
LOG('addNode',0,'object.id: %s' % object.getId())
LOG('addNode',0,'xml.nodeName: %s' % xml.nodeName)
LOG('addNode',0,'isSubObjectAdd: %i' % self.getSubObjectAddDepth(xml))
LOG('addNode',0,'isSubObjectAdd: %i' % self.getSubObjectDepth(xml))
if xml.nodeName == 'object' \
or xml.nodeName == 'xupdate:insert-after' and self.getSubObjectAddDepth(xml)==1:
or xml.nodeName in self.XUPDATE_INSERT_OR_ADD and self.getSubObjectDepth(xml)==1:
object_id = self.getObjectId(xml)
docid = self.getObjectDocid(xml)
LOG('addNode',0,'object_id: %s' % object_id)
if object_id is not None:
subobject = None
try:
subobject = object[object_id]
except KeyError:
pass
subobject = object._getOb(object_id)
except (AttributeError, KeyError):
subobject = None
#subobject = None
#try:
# subobject = object[object_id]
#except KeyError:
# pass
if subobject is None: # If so it does'nt exist yes
portal_type = ''
if xml.nodeName == 'object':
portal_type = self.getObjectType(xml)
elif xml.nodeName == 'xupdate:insert-after':
elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD:
portal_type = self.getXupdateObjectType(xml)
portal_types = getToolByName(object,'portal_types')
LOG('ERP5Conduit.addNode',0,'portal_type: |%s|' % str(portal_type))
portal_types.constructContent(type_name = portal_type,
container = object,
id = object_id)
subobject = object[object_id]
if docid==None: # ERP5 content
portal_types.constructContent(type_name = portal_type,
container = object,
id = object_id)
else: # CPS content
# This is specific to CPS, we will call the proxy tool
px_tool= getToolByName(object,'portal_proxies')
proxy_type = 'document'
if portal_type == 'Workspace':
proxy_type = 'folder'
proxy = px_tool.createEmptyProxy(proxy_type,
object,portal_type,object_id,docid)
#px_tool.createRevision(proxy,px_tool.getDefaultLanguage()) # Doesn't works well
# px_tool._addProxy(proxy,None) # Doesn't works well
#object.newContent(portal_type=portal_type, id=object_id) # Doesn't works with CPS
#subobject = object[object_id] # Doesn't works with CPS
subobject = object._getOb(object_id)
# Again for CPS proxy XXX May be not needed
#if docid is not None:
# subobject.proxyChanged()
self.newObject(object=subobject,xml=xml)
elif xml.nodeName == 'xupdate:insert-after' \
and self.getSubObjectAddDepth(xml)==2:
elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD \
and self.getSubObjectDepth(xml)==2:
# We should find the object corresponding to
# this update, so we have to look in the previous_xml
object_number = self.getSubObjectIndex(xml)
LOG('addNode',0,'getSubObjectModification number: %i' % object_number)
sub_object_id = self.getSubObjectId(xml)
LOG('addNode',0,'getSubObjectModification number: %s' % sub_object_id)
#LOG('updateNode',0,'isSubObjectModification previous: %s' % str(previous_xml))
if previous_xml is not None and object_number is not None:
LOG('addNode',0,'previous xml is not none and also object_number')
if type(previous_xml) in (type('a'),type(u'a')):
previous_xml = FromXml(previous_xml)
previous_xml = previous_xml.childNodes[1] # Because we just created a new xml
# document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
if previous_xml is not None and sub_object_id is not None:
LOG('addNode',0,'previous xml is not none and also sub_object_id')
previous_xml = self.getSubObjectXml(sub_object_id,previous_xml)
# Get the id of the previous object
i = 0
sub_previous_xml = None
# Find the previous xml corresponding to this subobject
for subnode in self.getElementNodeList(previous_xml):
if subnode.nodeName=='object':
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName=='object':
i += 1
if i==object_number:
sub_previous_xml = subnode1
sub_previous_xml == self.getSubObjectXml(sub_object_id,previous_xml)
LOG('addNode',0,'isSubObjectModification sub_p_xml: %s' % str(sub_previous_xml))
if sub_previous_xml is not None:
sub_object = None
LOG('addNode',0,'getObjectId: %s' % self.getObjectId(sub_previous_xml) )
# XXXXXXXXXXXX
# The problem is actually that the sub_previous_xml doesn't correspong to the
# xml, we have the xupdate of a subobject but we have the previous_xml
# of the object
try:
sub_object = object[self.getObjectId(sub_previous_xml)]
sub_object = object[sub_object_id]
except KeyError:
pass
if sub_object is not None:
......@@ -174,20 +185,37 @@ class ERP5Conduit(SyncCode):
conflict_list += self.updateNode(xml=xml,object=object, force=force, **kw)
return conflict_list
def deleteNode(self, xml=None, object=None, **kw):
def deleteNode(self, xml=None, object=None, object_id=None, force=None, **kw):
"""
A node is deleted
"""
# In the case where this new node is a object to delete
LOG('ERP5Conduit',0,'deleteNode')
xml = self.convertToXML(xml)
if xml.nodeName == 'object':
object_id = self.getObjectId(xml)
if object_id is not None:
LOG('ERP5Conduit',0,'deleteNode, object.id: %s' % object.getId())
conflict_list = []
xml = self.convertToXml(xml)
if object_id is None:
LOG('ERP5Conduit',0,'deleteNode, SubObjectDepth: %i' % self.getSubObjectDepth(xml))
if xml.nodeName == self.xml_object_tag:
object_id = self.getObjectId(xml)
elif self.getSubObjectDepth(xml)==1:
object_id = self.getSubObjectId(xml)
elif self.getSubObjectDepth(xml)==2:
# we have to call delete node on a subsubobject
sub_object_id = self.getSubObjectId(xml)
try:
object._delObject(object_id)
sub_object = object._getOb(sub_object_id)
sub_xml = self.getSubObjectXupdate(xml)
conflict_list += self.deleteNode(xml=sub_xml,object=sub_object,
force=force)
except KeyError:
pass
else: # We do have an object_id
try:
object._delObject(object_id)
except (AttributeError, KeyError):
pass
return conflict_list
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, **kw):
"""
......@@ -198,7 +226,7 @@ class ERP5Conduit(SyncCode):
when we have sub objects
"""
conflict_list = []
xml = self.convertToXML(xml)
xml = self.convertToXml(xml)
LOG('updateNode',0,'xml.nodeName: %s' % xml.nodeName)
# we have an xupdate xml
if xml.nodeName == 'xupdate:modifications':
......@@ -208,52 +236,48 @@ class ERP5Conduit(SyncCode):
# we may have only the part of an xupdate
else:
args = {}
LOG('isSubObjectModification',0,'result: %s' % str(self.isSubObjectModification(xml)))
if self.isProperty(xml) and not(self.isSubObjectModification(xml)):
for subnode in xml.attributes:
if subnode.nodeType == subnode.ATTRIBUTE_NODE and subnode.nodeName=='select':
select_list = subnode.nodeValue.split('/') # Something like: ('','object[1]','sid[1]')
LOG('updateNode',0,'selection: %s' % str(subnode.nodeValue))
select_list = subnode.nodeValue.split('/') # Something like:
#('','object[1]','sid[1]')
new_select_list = ()
for select_item in select_list:
new_select_list += (select_item[:select_item.find('[')],)
if select_item.find('[')>=0:
select_item = select_item[:select_item.find('[')]
new_select_list += (select_item,)
select_list = new_select_list # Something like : ('','object','sid')
keyword = select_list[len(select_list)-1] # this will be 'sid'
if xml.nodeName != 'xupdate:insert-after':
LOG('updateNode',0,'keyword: %s' % str(keyword))
if not (xml.nodeName in self.XUPDATE_INSERT_OR_ADD):
for subnode in self.getElementNodeList(xml):
if subnode.nodeName=='xupdate:element':
for subnode1 in subnode.attributes:
if subnode1.nodeName=='name':
keyword = subnode1.nodeValue
i = 1
while (keyword.find('()') > 0) and (i <= len(select_list)):
keyword = select_list[len(select_list)-i] # we want description in :
# /object[1]/description[1]/text()[1]
i += 1
if not (keyword in self.NOT_EDITABLE_PROPERTY):
# We will look for the data to enter
if len(self.getElementNodeList(xml))==0:
data = xml.childNodes[0].data
data = self.convertXmlValue(data)
#data = data[data.find('\n')+1:data.rfind('\n')]
#data = data.replace('@@@','\n')
else:
data=[]
for subnode in self.getElementNodeList(xml):
element_data = subnode.childNodes[0].data
#element_data = element_data[element_data.find('\n')+1:element_data.rfind('\n')]
element_data = self.convertXmlValue(element_data)
element_data = element_data.replace('@@@','\n')
data += [element_data]
if len(data) == 1: # This is probably because this is not a list but a string XXX may be not good
data = data[0]
#LOG('updateNode',0,'data: %s' % str(data))
if keyword.find('_list') > 0:
LOG('updateNode',0,'keyword is type list')
if type(data) == type(u'a'): # Probably deprecated
data = data.split('@@@') # XXX very bad hack, must find something better
#if type(data) == type(u'a'):
# LOG('updateNode',0,'splitting it')
# data = data.split('\n')
try:
data = xml.childNodes[0].data
except IndexError: # There is no data
data = None
# XXX may be not needed any more
#else:
# data=()
# for subnode in self.getElementNodeList(xml):
# element_data = subnode.childNodes[0].data
# element_data = self.convertXmlValue(element_data)
# data += (element_data,)
# if len(data) == 1: # This is probably because this is not a list
# but a string XXX may be not good
# data = data[0]
data_type = object.getPropertyType(keyword)
LOG('updateNode',0,'data_type: %s' % str(data_type))
data = self.convertXmlValue(data,data_type=data_type)
args[keyword] = data
args = self.getFormatedArgs(args=args)
# This is the place where we should look for conflicts
......@@ -263,21 +287,26 @@ class ERP5Conduit(SyncCode):
# - current_data : the data actually on this box
isConflict = 0
if previous_xml is not None: # if no previous_xml, no conflict
old_data = self.getObjectProperty(keyword,previous_xml)
old_data = self.getObjectProperty(keyword,previous_xml,data_type=data_type)
current_data = object.getProperty(keyword)
LOG('updateNode',0,'Conflict data: %s' % str(data))
LOG('updateNode',0,'Conflict old_data: %s' % str(old_data))
LOG('updateNode',0,'Conflict current_data: %s' % str(current_data))
if (old_data != current_data) and (data != current_data):
# This is a conflict
isConflict = 1
conflict_list += [Conflict(object_path=object.getPhysicalPath(),keyword=keyword,\
local_value=current_data,remote_value=data)]
#conflict_list += [[object.getPath(),keyword,current_data,data]]
LOG('updateNode',0,'Conflict on : %s' % keyword)
# Hack in order to get the synchronization working for demo
# XXX this have to be removed after
if not (data_type in self.binary_type_list):
# This is a conflict
isConflict = 1
conflict_list += [Conflict(object_path=object.getPhysicalPath(),
keyword=keyword,
local_value=current_data,
remote_value=data)]
# We will now apply the argument with the method edit
if args != {} and (isConflict==0 or force):
LOG('updateNode',0,'object.edit, args: %s' % str(args))
object.edit(**args)
LOG('updateNode',0,'object._edit, args: %s' % str(args))
object._edit(**args)
if keyword == 'object':
# This is the case where we have to call addNode
LOG('updateNode',0,'we will add sub-object')
......@@ -285,38 +314,16 @@ class ERP5Conduit(SyncCode):
elif self.isSubObjectModification(xml):
# We should find the object corresponding to
# this update, so we have to look in the previous_xml
object_number = self.getSubObjectIndex(xml)
LOG('updateNode',0,'getSubObjectModification number: %i' % object_number)
#LOG('updateNode',0,'isSubObjectModification previous: %s' % str(previous_xml))
if previous_xml is not None and object_number is not None:
LOG('updateNode',0,'previous xml is not none and also object_number')
if type(previous_xml) in (type('a'),type(u'a')):
previous_xml = FromXml(previous_xml)
previous_xml = previous_xml.childNodes[1] # Because we just created a new xml
# document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
# Get the id of the previous object
i = 0
sub_previous_xml = None
# Find the previous xml corresponding to this subobject
for subnode in self.getElementNodeList(previous_xml):
if subnode.nodeName=='object':
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName=='object':
i += 1
if i==object_number:
sub_previous_xml = subnode1
sub_object_id = self.getSubObjectId(xml)
LOG('updateNode',0,'getSubObjectModification number: %s' % sub_object_id)
if previous_xml is not None and sub_object_id is not None:
LOG('updateNode',0,'previous xml is not none and also sub_object_id')
sub_previous_xml = self.getSubObjectXml(sub_object_id,previous_xml)
LOG('updateNode',0,'isSubObjectModification sub_p_xml: %s' % str(sub_previous_xml))
if sub_previous_xml is not None:
sub_object = None
LOG('updateNode',0,'getObjectId: %s' % self.getObjectId(sub_previous_xml) )
# XXXXXXXXXXXX
# The problem is actually that the sub_previous_xml doesn't correspong to the
# xml, we have the xupdate of a subobject but we have the previous_xml
# of the object
# I guess it was resolved with getSubObjectXupdate... so this comment may be removed XXX
try:
sub_object = object[self.getObjectId(sub_previous_xml)]
sub_object = object[sub_object_id]
except KeyError:
pass
if sub_object is not None:
......@@ -346,10 +353,12 @@ class ERP5Conduit(SyncCode):
for item in data:
if type(item) is type(u"a"):
item = item.encode(self.getEncoding())
item = item.replace('@@@','\n')
new_data += [item]
data = new_data
if type(data) is type(u"a"):
data = data.encode(self.getEncoding())
data = data.replace('@@@','\n')
if keyword == 'binary_data':
LOG('ERP5Conduit.getFormatedArgs',0,'binary_data keyword: %s' % str(keyword))
msg = MIMEBase('application','octet-stream')
......@@ -377,33 +386,19 @@ class ERP5Conduit(SyncCode):
This will change the xml in order to change the update
from the object to the subobject
"""
for subnode in xml.attributes:
if subnode.nodeType == subnode.ATTRIBUTE_NODE and subnode.nodeName=='select':
value = subnode.nodeValue
if sre.search("/object\[[0-9]*\]/object\[[0-9]*\]/.",value) is not None:
try:
new_value = ''
new_value_list = (value.split('/')[1:2] + value.split('/')[3:])
for s in new_value_list:
new_value += '/' + s
except KeyError:
pass
subnode.nodeValue = new_value
xml = copy.deepcopy(xml)
for subnode in self.getAttributeNodeList(xml):
if subnode.nodeName=='select':
subnode.nodeValue = self.getSubObjectSelect(subnode.nodeValue)
element_node_list = self.getElementNodeList(xml)
# This is when we have a sub_sub_object_add and we will want a sub_object_add
LOG('getSubObjectXupdate',0,'xml.nodeName: %s' % xml.nodeName)
#for j in range(0,len(xml.childNodes)):
# subnode = xml.childNodes[j]
for subnode in self.getElementNodeList(xml):
#if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName=='xupdate:element':
if subnode.nodeName=='xupdate:element':
LOG('getSubObjectXupdate',0,'subnode.nodeName: %s' % subnode.nodeName)
for subnode1 in self.getElementNodeList(subnode):
LOG('getSubObjectXupdate',0,'subnode1.nodeName: %s' % subnode1.nodeName)
if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode1.nodeName=='object':
#LOG('getSubObjectXupdate',0,'xml.childNodes[j].nodeName: %s' % xml.childNodes[j].nodeName)
#xml.childNodes[j] = subnode1
if subnode1.nodeName=='object':
return subnode1
return xml
......@@ -411,60 +406,105 @@ class ERP5Conduit(SyncCode):
"""
Check if it is a modification from an subobject
"""
good_list = ('/object[1]/object',)
good_list = (self.sub_object_exp,)
for subnode in xml.attributes:
if subnode.nodeType == subnode.ATTRIBUTE_NODE and subnode.nodeName=='select':
value = subnode.nodeValue
LOG('isSubObjectModification',0,'value: %s' % value)
for good_string in good_list:
if value.find(good_string)==0:
if re.search(good_string,value) is not None:
return 1
return 0
def getSubObjectAddDepth(self, xml):
"""
Check if this modification is in reality a new subobject to add
"""
if xml.nodeName == 'xupdate:insert-after':
def getSubObjectDepth(self, xml):
"""
Give the Depth of a subobject modification
0 means, no depth
1 means it is a subobject
2 means it is more depth than subobject
"""
LOG('getSubObjectDepth',0,'xml.nodeName: %s' % xml.nodeName)
if xml.nodeName in self.XUPDATE_TAG:
LOG('getSubObjectDepth',0,'xml2.nodeName: %s' % xml.nodeName)
if xml.nodeName == self.xml_object_tag:
return 1
for subnode in self.getAttributeNodeList(xml):
LOG('getSubObjectDepth',0,'subnode.nodeName: %s' % subnode.nodeName)
if subnode.nodeName == 'select':
value = subnode.nodeValue
LOG('getSubObjectDepth',0,'subnode.nodeValue: %s' % subnode.nodeValue)
if re.search(self.sub_object_exp,value) is not None:
new_select = self.getSubObjectSelect(value)
if self.getSubObjectSelect(new_select) != new_select:
return 2
return 1
for subnode in self.getElementNodeList(xml):
# One part of this is specific to xmldiff, may be need to rewrite
if subnode.nodeName == 'xupdate:element':
for attribute in subnode.attributes:
if attribute.nodeName == 'name':
is_sub_add = 0
if attribute.nodeValue == 'object':
if attribute.nodeValue == self.xml_object_tag:
is_sub_add = 1
if not is_sub_add:
return 0
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName == 'object': # In this particular case, this is sub_sub_add
if subnode1.nodeName == self.xml_object_tag: # In this particular case, this is sub_sub_add
return 2
return 1
if subnode.nodeName == 'object':
return 1
return 0
def getSubObjectIndex(self, xml):
def getSubObjectSelect(self, select):
"""
Return the number of the subobject in an xupdate modification
Return a string wich is the selection for the subobject
ex: for "/object[@id='161']/object[@id='default_address']/street_address"
if returns "/object[@id='default_address']/street_address"
"""
selection = None
good_string = '/object[1]/object['
for subnode in xml.attributes:
if subnode.nodeType == subnode.ATTRIBUTE_NODE and subnode.nodeName=='select':
if re.search(self.sub_object_exp,select) is not None:
s = self.xml_object_tag
new_value = '/' + select[select.find(s,select.find(s)+1):]
select = new_value
return select
def getSubObjectId(self, xml):
"""
Return the id of the subobject in an xupdate modification
"""
object_id = None
for subnode in self.getAttributeNodeList(xml):
if subnode.nodeName=='select':
value = subnode.nodeValue
if value.find(good_string)==0:
string_number = value[len(good_string):]
string_number = string_number.split(']')[0]
selection = int(string_number)
return selection
if re.search(self.sub_object_exp,value) is not None:
s = self.xml_object_tag
object_id = value[value.find(s,value.find(s)+1):]
object_id = object_id[object_id.find("'")+1:]
object_id = object_id[:object_id.find("'")]
return object_id
return object_id
def getSubObjectXml(self, object_id, xml):
"""
Return the xml of the subobject which as the id object_id
"""
xml = self.convertToXml(xml)
for subnode in self.getElementNodeList(xml):
if subnode.nodeName==self.xml_object_tag:
LOG('getSub0bjectXml: object_id:',0,object_id)
if object_id == self.getObjectId(subnode):
return subnode
return None
def getObjectId(self, xml):
"""
Retrieve the id
"""
for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'id':
data = subnode.childNodes[0].data
#for subnode in self.getElementNodeList(xml):
# if subnode.nodeName == 'id':
# data = subnode.childNodes[0].data
# return self.convertXmlValue(data)
for attribute in self.getAttributeNodeList(xml):
if attribute.nodeName == 'id':
data = attribute.childNodes[0].data
return self.convertXmlValue(data)
# In the case where the new object is inside an xupdate
if xml.nodeName.find('xupdate')>=0:
......@@ -476,32 +516,42 @@ class ERP5Conduit(SyncCode):
return self.convertXmlValue(data)
return None
def getObjectDocid(self, xml):
"""
Retrieve the docid
"""
for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'docid':
data = subnode.childNodes[0].data
return self.convertXmlValue(data)
return None
def getObjectProperty(self, property, xml):
def getObjectProperty(self, property, xml, data_type=None):
"""
Retrieve the given property
"""
if type(xml) in (type('a'),type(u'a')):
xml = FromXml(xml)
xml = xml.childNodes[1] # Because we just created a new xml
xml = self.convertToXml(xml)
# document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
for subnode in self.getElementNodeList(xml):
LOG('getObjectProperty',0,'subnode.nodeName: %s' % subnode.nodeName)
if subnode.nodeName == property:
data = subnode.childNodes[0].data
data = self.convertXmlValue(data)
if property[-5:]=='_list':
data = data.split('@@@')
try:
data = subnode.childNodes[0].data
data = self.convertXmlValue(data, data_type=data_type)
except IndexError: # There is no data
data = None
return data
return None
def convertToXML(self,xml):
def convertToXml(self,xml):
"""
if xml is a string, convert it to a node
"""
if type(xml) in (type('a'),type(u'a')):
xml = FromXml(xml)
xml = xml.childNodes[1] # Because we just created a new xml
# If we have the xml from the node erp5, we just take the subnode
if xml.nodeName=='erp5':
xml = self.getElementNodeList(xml)[0]
return xml
def getObjectType(self, xml):
......@@ -556,27 +606,20 @@ class ERP5Conduit(SyncCode):
keyword=str(subnode.nodeName)
if len(subnode.childNodes) > 0: # We check that this tag is not empty
data = subnode.childNodes[0].data
data = self.convertXmlValue(data)
args[keyword]=data
LOG('newObject',0,'keyword: %s' % str(keyword))
LOG('newObject',0,'keywordtype: %s' % str(keyword_type))
#if args.has_key(keyword):
# LOG('newObject',0,'data: %s' % str(args[keyword]))
if args.has_key(keyword):
LOG('newObject',0,'data: %s' % str(args[keyword]))
if keyword_type in list_types:
if args.has_key(keyword):
if type(args[keyword]) in [type(u'a'),type('a')]:
args[keyword] = args[keyword].split('@@@')
elif keyword_type in ('text',):
if args.has_key(keyword):
args[keyword] = args[keyword].replace('@@@','\n')
args[keyword] = self.convertXmlValue(args[keyword],keyword_type)
# We should first edit the object
args = self.getFormatedArgs(args=args)
LOG('newObject',0,"object.getpath: %s" % str(object.getPath()))
LOG('newObject',0,"args: %s" % str(args))
# edit the object with a dictionnary of arguments,
# like {"telephone_number":"02-5648"}
object.edit(**args)
object._edit(**args)
# Then we may create subobject
for subnode in xml.childNodes:
......@@ -584,37 +627,37 @@ class ERP5Conduit(SyncCode):
subnode.nodeName=='object':
self.addNode(object=object,xml=subnode)
def convertXmlValue(self, data):
def convertXmlValue(self, data, data_type=None):
"""
It is possible that the xml change the value, for example
there is some too much '\n' and some spaces. We should correct it
"""
# Theses two lines are not needed any more
#if data.find('\n')>=0 and data[0]==' ': # We may suppose there is two '\n' in this case
# data = data[data.find('\n')+1:data.rfind('\n')]
# Then we should remove every other \n
# we doesn't want any of them on our synchronization, they have
# to be all replaced by '@@@', this is really usefull in order to split
# very long data
there is some too much '\n' and some spaces. We have to do some extra
things so that we convert correctly the vlalue
"""
if data is None:
if data_type in self.list_type_list:
data = ()
return data
data = data.replace('\n','')
# Remove spaces at the beginning
while data.find(' ')==0:
data = data[1:]
# Remove spaces at the end
while data.rfind(' ')==(len(data)-1):
data = data[:-1]
if type(data) is type(u"a"):
data = data.encode(self.getEncoding())
# We can now convert string in tuple, dict, binary...
if data_type in self.list_type_list:
if type(data) is type('a'):
data = tuple(data.split('@@@'))
elif data_type in self.text_type_list:
data = data.replace('@@@','\n')
elif data_type in self.binary_type_list:
data = data.replace('@@@','\n')
msg = MIMEBase('application','octet-stream')
Encoders.encode_base64(msg)
msg.set_payload(data)
data = msg.get_payload(decode=1)
elif data_type in self.date_type_list:
data = DateTime(data)
elif data_type in self.dict_type_list:
dict_list = map(lambda x:x.split(':'),data[1:-1].split(','))
data = map(lambda (x,y):(x.replace(' ','').replace("'",''),int(y)),dict_list)
data = dict(data)
LOG('convertXmlValue',0,'data: %s' % str(data))
return data
def getElementNodeList(self, node):
"""
Return childNodes that are ElementNode
"""
subnode_list = []
for subnode in node.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE:
subnode_list += [subnode]
LOG('getElementNodeList',0,'end...')
return subnode_list
......@@ -160,7 +160,7 @@ class PublicationSynchronization(XMLSyncUtils):
# FIXME: Why can't we use the method addSubscriber ??
self.list_publications[id].addSubscriber(subscriber)
# first synchronization
self.PubSyncInit(self.list_publications[id],xml_client)
self.PubSyncInit(self.list_publications[id],xml_client,subscriber=subscriber)
elif self.checkAlert(xml_client) and self.getAlertCode(xml_client) in (self.TWO_WAY,self.SLOW_SYNC):
self.PubSyncInit(publication=self.list_publications[id],
......
......@@ -45,8 +45,8 @@ class Conflict(SyncCode):
remote_value=None, domain=None, domain_id=None):
self.object_path=object_path
self.keyword = keyword
self.local_value=local_value
self.remote_value=remote_value
self.setLocalValue(local_value)
self.setRemoteValue(remote_value)
self.domain = domain
self.domain_id = domain_id
......@@ -56,6 +56,36 @@ class Conflict(SyncCode):
"""
return self.object_path
def getLocalValue(self):
"""
get the domain
"""
return self.local_value
def setLocalValue(self, value):
"""
get the domain
"""
try:
self.local_value = value
except TypeError: # It happens when we try to store StringIO
self.local_value = None
def getRemoteValue(self):
"""
get the domain
"""
return self.remote_value
def setRemoteValue(self, value):
"""
get the domain
"""
try:
self.remote_value = value
except TypeError: # It happens when we try to store StringIO
self.remote_value = None
def setDomain(self, domain):
"""
set the domain
......@@ -68,6 +98,12 @@ class Conflict(SyncCode):
"""
return self.domain
def getKeyword(self):
"""
get the domain
"""
return self.keyword
def getDomainId(self):
"""
get the domain id
......@@ -80,6 +116,17 @@ class Conflict(SyncCode):
"""
self.domain_id = domain_id
def applyRemoteValue():
"""
We will take the remote value for this conflict
"""
pass
def applyLocalValue():
"""
We will take the local value for this conflict
"""
pass
class Signature(SyncCode):
"""
......@@ -102,6 +149,7 @@ class Signature(SyncCode):
self.setTempXML(None)
self.setTempXML(None)
self.resetConflictList()
self.md5_string = None
self.force = 0
#def __init__(self,object=None, status=None, xml_string=None):
......@@ -125,6 +173,9 @@ class Signature(SyncCode):
self.setTempXML(None)
if len(self.getConflictList())>0:
self.resetConflictList()
elif status in (self.PUB_CONFLICT_MERGE,self.SENT):
# We have a solution for the conflict, don't need to keep the list
self.resetConflictList()
def getStatus(self):
"""
......@@ -151,7 +202,7 @@ class Signature(SyncCode):
self.xml = xml
if self.xml != None:
self.setTempXML(None) # We make sure that the xml will not be erased
self.md5_string = md5.new(xml).digest()
self.setMD5(xml)
def getXML(self):
"""
......@@ -183,7 +234,7 @@ class Signature(SyncCode):
"""
get the MD5 object of this signature
"""
return self.md5_object
return self.md5_string
def checkMD5(self, xml_string):
"""
......@@ -192,7 +243,7 @@ class Signature(SyncCode):
if we want to know if an objects has changed or not
Returns 1 if MD5 are equals, else it returns 0
"""
return md5.new(xml_string).digest() == self.md5_string
return ((md5.new(xml_string).digest()) == self.getMD5())
def setRid(self, rid):
"""
......@@ -223,14 +274,16 @@ class Signature(SyncCode):
Set the partial string we will have to
deliver in the future
"""
#LOG('Subscriber.setPartialXML before',0,'partial_xml: %s' % str(self.partial_xml))
self.partial_xml = xml
#LOG('Subscriber.setPartialXML after',0,'partial_xml: %s' % str(self.partial_xml))
def getPartialXML(self):
"""
Set the partial string we will have to
deliver in the future
"""
LOG('Subscriber.getPartialXML',0,'partial_xml: %s' % str(self.partial_xml))
#LOG('Subscriber.getPartialXML',0,'partial_xml: %s' % str(self.partial_xml))
return self.partial_xml
def getAction(self):
......@@ -339,6 +392,13 @@ class Subscription(SyncCode):
def getSynchronizationType(self, default=None):
"""
"""
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXX for debugging only, to be removed
dict_sign = {}
for object_id in self.signatures.keys():
dict_sign[object_id] = self.signatures[object_id].getStatus()
LOG('getSignature',0,'signatures_status: %s' % str(dict_sign))
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
code = self.SLOW_SYNC
if len(self.signatures.keys()) > 0:
code = self.TWO_WAY
......@@ -562,7 +622,7 @@ class Subscription(SyncCode):
for object_id in self.signatures.keys():
# Change the status only if we are not in a conflict mode
if not(self.signatures[object_id].getStatus() in (self.CONFLICT,self.PUB_CONFLICT_MERGE,
self.SUB_CONFLICT_MERGE)):
self.PUB_CONFLICT_CLIENT_WIN)):
self.signatures[object_id].setStatus(self.NOT_SYNCHRONIZED)
self.signatures[object_id].setPartialXML(None)
self.signatures[object_id].setTempXML(None)
......@@ -26,6 +26,7 @@
#
##############################################################################
from Products.ERP5Type.Accessor.TypeDefinition import list_types
from Globals import Persistent
class SyncCode(Persistent):
......@@ -60,10 +61,28 @@ class SyncCode(Persistent):
PARTIAL = 4
NOT_SYNCHRONIZED = 5
PUB_CONFLICT_MERGE = 6
SUB_CONFLICT_MERGE = 7
#SUB_CONFLICT_MERGE = 7
PUB_CONFLICT_CLIENT_WIN = 8
SUB_CONFLICT_CLIENT_WIN = 9
#SUB_CONFLICT_CLIENT_WIN = 9
MAX_LINES = 1000
#ENCODING='iso-8859-1'
NOT_EDITABLE_PROPERTY = ('id','object','workflow_history','security_info','uid'
'xupdate:element','xupdate:attribute')
XUPDATE_INSERT = ('xupdate:insert-after','xupdate:insert-before')
XUPDATE_ADD = ('xupdate:append',)
XUPDATE_DEL = ('xupdate:remove',)
XUPDATE_UPDATE = ('xupdate:update',)
XUPDATE_INSERT_OR_ADD = tuple(XUPDATE_INSERT) + tuple(XUPDATE_ADD)
XUPDATE_TAG = tuple(XUPDATE_INSERT) + tuple(XUPDATE_ADD) + \
tuple(XUPDATE_UPDATE) + tuple(XUPDATE_DEL)
text_type_list = ('text','string')
list_type_list = list_types
binary_type_list = ('image','file','document')
date_type_list = ('date',)
dict_type_list = ('dict',)
xml_object_tag = 'object'
sub_object_exp = "/object\[@id='.*'\]/object\[@id='.*'\]"
......@@ -28,7 +28,6 @@
import smtplib
from Products.ERP5SyncML.SyncCode import SyncCode
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
from Products.ERP5SyncML.Subscription import Signature
from xml.dom.ext.reader.Sax2 import FromXml
from cStringIO import StringIO
......@@ -36,7 +35,7 @@ from xml.dom.ext import PrettyPrint
import commands
from zLOG import LOG
class XMLSyncUtils(SyncCode):
class XMLSyncUtilsMixin(SyncCode):
def SyncMLHeader(self, session_id, msg_id, target, source):
"""
......@@ -158,7 +157,7 @@ class XMLSyncUtils(SyncCode):
xml += ' <Item>\n'
xml += ' <Source><LocURI>%s</LocURI></Source>\n' % object_id
xml += ' <Data>\n'
xml += xml_object # We have to send the data, because it allows to
#xml += xml_object # We have to send the data, because it allows to
# wich object to delete (it could be clever things
xml += ' </Data>\n'
xml += ' </Item>\n'
......@@ -197,12 +196,14 @@ class XMLSyncUtils(SyncCode):
file2 = open('/tmp/sync_old_object','w')
file2.write(old_xml)
file2.close()
xupdate = commands.getoutput('xmldiff -xg /tmp/sync_old_object /tmp/sync_new_object')
#xupdate = commands.getoutput('xmldiff -xg /tmp/sync_old_object /tmp/sync_new_object')
xupdate = commands.getoutput('erp5diff /tmp/sync_old_object /tmp/sync_new_object')
xupdate = xupdate[xupdate.find('<xupdate:modifications'):]
while xupdate.find('xupdate:move')>0:
LOG('getXupdateObject',0,'Removing the move section')
xupdate = xupdate[:xupdate.find('<xupdate:move')] + \
xupdate[xupdate.find('</xupdate:move>\n')+16:]
# XXX To be removed, this is only needed for xmldiff with does bad things
#while xupdate.find('xupdate:move')>0:
# LOG('getXupdateObject',0,'Removing the move section')
# xupdate = xupdate[:xupdate.find('<xupdate:move')] + \
# xupdate[xupdate.find('</xupdate:move>\n')+16:]
return xupdate
def getXMLObject(self, object=None, xml_mapping=None):
......@@ -517,6 +518,30 @@ class XMLSyncUtils(SyncCode):
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'Type':
return str(subnode2.childNodes[0].data)
def getElementNodeList(self, node):
"""
Return childNodes that are ElementNode
"""
subnode_list = []
for subnode in node.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE:
subnode_list += [subnode]
return subnode_list
def getAttributeNodeList(self, node):
"""
Return childNodes that are ElementNode
"""
attribute_list = []
for subnode in node.attributes:
if subnode.nodeType == subnode.ATTRIBUTE_NODE:
attribute_list += [subnode]
return attribute_list
class XMLSyncUtils(XMLSyncUtilsMixin):
def Sync(self, id, msg=None, RESPONSE=None):
"""
This is the main method for synchronization
......@@ -539,6 +564,7 @@ class XMLSyncUtils(SyncCode):
Send the server modification, this happens after the Synchronization
initialization
"""
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
cmd_id = 1 # specifies a SyncML message-unique command identifier
LOG('SyncModif',0,'Starting... domain: %s' % str(domain))
# Get the destination folder
......@@ -564,8 +590,9 @@ class XMLSyncUtils(SyncCode):
destination_waiting_more_data = 0
while next_status != None:
object_id = self.getStatusTarget(next_status)
status_code = self.SUCCESS
status_code = self.getStatusCode(next_status)
signature = subscriber.getSignature(object_id)
LOG('SyncModif',0,'next_status: %s' % str(status_code))
if status_code == self.CHUNK_OK:
destination_waiting_more_data = 1
signature.setStatus(self.PARTIAL)
......@@ -579,7 +606,7 @@ class XMLSyncUtils(SyncCode):
elif status_code == self.CONFLICT_CLIENT_WIN:
# The server was agree to apply our updates, nothing to do
signature.setStatus(self.SYNCHRONIZED)
else:
elif status_code == self.SUCCESS:
signature.setStatus(self.SYNCHRONIZED)
next_status = self.getNextSyncBodyStatus(remote_xml, next_status)
......@@ -607,6 +634,7 @@ class XMLSyncUtils(SyncCode):
data_subnode = None
if partial_data != None:
data_subnode = signature.getPartialXML() + partial_data
LOG('SyncModif',0,'data_subnode: %s' % data_subnode)
data_subnode = FromXml(data_subnode)
data_subnode = data_subnode.childNodes[1] # Because we just created a new xml
# document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
......@@ -618,8 +646,8 @@ class XMLSyncUtils(SyncCode):
object =None
LOG('SyncModif',0,'addNode, getActionId: %s' % self.getActionId(next_action))
try:
object = destination_path[self.getActionId(next_action)]
except KeyError:
object = destination_path._getOb(self.getActionId(next_action))
except (AttributeError, KeyError):
pass
if object is not None:
LOG('SyncModif',0,'addNode, found the object')
......@@ -633,8 +661,8 @@ class XMLSyncUtils(SyncCode):
elif next_action.nodeName == 'Replace':
object =None
try:
object = destination_path[self.getActionId(next_action)]
except KeyError:
object = destination_path._getOb(self.getActionId(next_action))
except (AttributeError, KeyError):
pass
LOG('SyncModif',0,'object: %s will be updated...' % str(object))
if object is not None:
......@@ -661,7 +689,8 @@ class XMLSyncUtils(SyncCode):
object.id,status_code,'Replace')
cmd_id +=1
elif next_action.nodeName == 'Delete':
conduit.deleteNode(xml=self.getDataSubNode(next_action), object=destination_path)
conduit.deleteNode(xml=self.getDataSubNode(next_action), object=destination_path,
object_id=self.getActionId(next_action))
subscriber.delSignature(self.getActionId(next_action))
else: # We want to retrieve more data
signature.setStatus(self.PARTIAL)
......@@ -669,7 +698,8 @@ class XMLSyncUtils(SyncCode):
previous_partial = signature.getPartialXML() or ''
previous_partial += partial_data
signature.setPartialXML(previous_partial)
LOG('SyncModif',0,'previous_partial: %s' % str(previous_partial))
#LOG('SyncModif',0,'previous_partial: %s' % str(previous_partial))
LOG('SyncModif',0,'waiting more data for :%s' % signature.getId())
xml_confirmation += self.SyncMLConfirmation(cmd_id,object_id,
self.WAITING_DATA,next_action.nodeName)
if conflict_list != [] and signature is not None:
......@@ -696,9 +726,10 @@ class XMLSyncUtils(SyncCode):
syncml_data = ''
if has_next_action == 0:
for object in destination_path.objectValues():
status = self.SENT
local_id_list += [object.id]
force = 0
if syncml_data.count('\n') < self.MAX_LINES: # If not we have to cut
if syncml_data.count('\n') < self.MAX_LINES and (object.id.find('.')!=0): # If not we have to cut
xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping)
LOG('SyncModif',0,'code: %s' % str(self.getAlertCode(remote_xml)))
LOG('XMLSyncModif',0,'id_list: %s' % str(local_id_list))
......@@ -707,11 +738,12 @@ class XMLSyncUtils(SyncCode):
signature = subscriber.getSignature(object.id)
status = self.SENT
more_data=0
if signature==None or signature.getXML()==None or \
# For the case it was never synchronized, we have to send everything
if signature==None or (signature.getXML()==None and signature.getStatus()!=self.PARTIAL) or \
self.getAlertCode(remote_xml)==self.SLOW_SYNC:
LOG('PubSyncModif',0,'Current object.getPath: %s' % object.getPath())
#LOG('PubSyncModif',0,'Current object.getPath: %s' % object.getPath())
xml_string = xml_object
signature = Signature(id=object.id, status=status)
signature = Signature(id=object.id)
signature.setTempXML(xml_object)
if xml_string.count('\n') > self.MAX_LINES:
more_data=1
......@@ -721,18 +753,22 @@ class XMLSyncUtils(SyncCode):
while i < self.MAX_LINES:
short_string += rest_string[:rest_string.find('\n')+1]
rest_string = xml_string[len(short_string):]
LOG('XMLSyncUtils',0,'rest_string: %s' % str(rest_string))
#LOG('XMLSyncUtils',0,'rest_string: %s' % str(rest_string))
i += 1
LOG('SyncModif',0,'setPartialXML with: %s' % str(rest_string))
signature.setPartialXML(rest_string)
signature.setStatus(self.PARTIAL)
status =self.PARTIAL
signature.setAction('Add')
xml_string = '<!--' + short_string + '-->'
syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,
xml_string=xml_string, more_data=more_data)
cmd_id += 1
signature.setStatus(status)
subscriber.addSignature(signature)
elif signature.getStatus()==self.NOT_SYNCHRONIZED \
or signature.getStatus()==self.PUB_CONFLICT_MERGE: # We don't have synchronized this object yet
LOG('SyncModif',0,'checkMD5: %s' % str(signature.checkMD5(xml_object)))
LOG('SyncModif',0,'getStatus: %s' % str(signature.getStatus()))
if signature.getStatus()==self.PUB_CONFLICT_MERGE:
xml_confirmation += self.SyncMLConfirmation(cmd_id,object.id,
self.CONFLICT_MERGE,'Replace')
......@@ -752,7 +788,6 @@ class XMLSyncUtils(SyncCode):
signature.setPartialXML(rest_string)
status = self.PARTIAL
signature.setAction('Replace')
signature.setStatus(status)
xml_string = '<!--' + short_string + '-->'
signature.setStatus(status)
syncml_data += self.replaceXMLObject(cmd_id=cmd_id,object=object,
......@@ -772,7 +807,7 @@ class XMLSyncUtils(SyncCode):
self.CONFLICT_CLIENT_WIN,'Replace')
signature.setStatus(self.SYNCHRONIZED)
elif signature.getStatus()==self.PARTIAL:
xml_string = signature.getPartialXML() or ''
xml_string = signature.getPartialXML()
if xml_string.count('\n') > self.MAX_LINES:
i = 0
more_data=1
......@@ -801,8 +836,11 @@ class XMLSyncUtils(SyncCode):
signature = subscriber.getSignature(object_id)
if signature.getStatus()!=self.PARTIAL: # If partial, then we have a signature
# but no local object
syncml_data += self.deleteXMLObject(xml_object=signature.getXML(),
object_id=object_id,cmd_id=cmd_id)
xml_object = signature.getXML()
if xml_object is not None: # This prevent to delete an object that we
# were not able to create
syncml_data += self.deleteXMLObject(xml_object=signature.getXML() or '',
object_id=object_id,cmd_id=cmd_id)
subscriber.delSignature(object_id)
......
......@@ -26,11 +26,12 @@
#
##############################################################################
from Products.ERP5SyncML.XMLSyncUtils import *
from Products.ERP5SyncML.XMLSyncUtils import XMLSyncUtilsMixin
from xml.dom.ext.reader.Sax2 import FromXml
from Products.ERP5SyncML.SyncCode import SyncCode
from zLOG import LOG
class XupdateUtils:
class XupdateUtils(XMLSyncUtilsMixin):
"""
This class contains method specific to xupdate xml,
this is the place where we should parse xupdate data.
......@@ -41,155 +42,25 @@ class XupdateUtils:
Parse the xupdate and then it will call the conduit
"""
conflict_list = []
if type(xupdate) is type('a'):
if type(xupdate) in (type('a'),type(u'a')):
xupdate = FromXml(xupdate)
# This is a list of selection with a fake tag
fake_tag_list = ()
for subnode in xupdate.childNodes:
to_continue = 0
for subnode in self.getElementNodeList(xupdate):
selection_name = ''
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'xupdate:append':
if subnode.nodeName in self.XUPDATE_ADD:
# Check if we do not have a fake tag somewhere
for subnode1 in subnode.attributes:
if subnode1.nodeType == subnode1.ATTRIBUTE_NODE and subnode1.nodeName=='select':
selection_name = subnode1.nodeValue
LOG('applyXupdate',0,'selection_name: %s' % str(selection_name))
for subnode1 in subnode.childNodes:
if subnode1.nodeType == subnode1.ELEMENT_NODE and subnode1.nodeName == 'xupdate:element':
for subnode2 in subnode1.attributes:
if subnode2.nodeName=='name' and subnode2.nodeValue == 'LogilabXMLDIFFFAKETag':
fake_tag_list += (selection_name,)
to_continue = 1
if not to_continue:
conduit.addNode(xml=subnode, object=object, force=force, **kw)
if subnode1.nodeType == subnode.ELEMENT_NODE and subnode1.nodeName == 'xupdate:text':
if selection_name in fake_tag_list: # This is the case where xmldiff do the crazy thing :
# Adding a fake tag, modify and delete,
# so we should only update.
conflict_list += conduit.updateNode(xml=subnode, object=object, force=force, **kw)
else:
conflict_list += conduit.addNode(xml=subnode,object=object, force=force, **kw)
#if to_continue:
# continue
elif subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'xupdate:remove':
for subnode1 in subnode.attributes:
if subnode1.nodeType == subnode1.ATTRIBUTE_NODE and subnode1.nodeName=='select':
selection_name = subnode1.nodeValue
LOG('applyXupdate',0,'fake_tag_list: %s' % str(fake_tag_list))
for fake_tag in fake_tag_list:
if selection_name.find(fake_tag) == 0:
LOG('applyXupdate',0,'selection ignored for delete: %s' % str(selection_name))
to_continue = 1
if not to_continue:
conduit.deleteNode(xml=subnode, object=object)
elif subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'xupdate:update':
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName == 'xupdate:element':
conflict_list += conduit.addNode(xml=subnode, object=object, force=force, **kw)
elif subnode1.nodeName == 'xupdate:text':
conflict_list += conduit.addNode(xml=subnode,object=object, force=force, **kw)
elif subnode.nodeName in self.XUPDATE_DEL:
conflict_list += conduit.deleteNode(xml=subnode, object=object, force=force, **kw)
elif subnode.nodeName in self.XUPDATE_UPDATE:
conflict_list += conduit.updateNode(xml=subnode, object=object, force=force, **kw)
elif subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'xupdate:insert-after':
elif subnode.nodeName in self.XUPDATE_INSERT:
conflict_list += conduit.addNode(xml=subnode, object=object, force=force, **kw)
return conflict_list
def old_applyXupdate(self, object=None, xupdate=None, conduit=None):
"""
deprecated and should not be used
"""
for subnode in xupdate.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'xupdate:modifications':
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE:
to_continue = 0
select_list = ()
# First check if we are not a sub-object
for subnode3 in subnode2.attributes:
if subnode3.nodeType == subnode3.ATTRIBUTE_NODE and subnode3.nodeName=='select':
nodeValue = subnode3.nodeValue
if nodeValue.find('/object[1]/object')==0:
to_continue = 1
elif nodeValue.find('/object[1]/workflow_history')==0:
to_continue = 1
elif nodeValue.find('/object[1]/security_info')==0:
to_continue = 1
else:
select_list = subnode3.nodeValue.split('/') # Something like: ('','object[1]','sid[1]')
new_select_list = ()
for select_item in select_list:
new_select_list += (select_item[:select_item.find('[')],)
select_list = new_select_list # Something like : ('','object','sid')
if to_continue:
continue
# Then we have to find the keyword, differents ways are needed
# depending if we are inserting, updating, removing...
keyword = None
data = None
if subnode2.nodeName == 'xupdate:insert-after': # We suppose the tag was empty before
# XXX this supposition could be WRONG
for subnode3 in getElementNodeList(subnode2):
if subnode3.nodeName=='xupdate:element':
for subnode4 in subnode3.attributes:
if subnode4.nodeName=='name':
keyword = subnode4.nodeValue
LOG('ApplyUpdate',0,'i-a, keyword: %s' % keyword)
if keyword=='object': # This is a subobject, we have to stop right now
to_continue = 1
elif keyword.find('element_')==0: # We are on a part of a list
keyword = select_list[len(select_list)-2]
if to_continue:
continue
if len(getElementNodeList(subnode3))==0:
data = str(subnode3.childNodes[0].data) # We assume the child is a text node
else: # We have many elements
data = []
for subnode4 in getElementNodeList(subnode3):
# In this case we should only have one childnode
LOG('ApplyUpdate',0,'subnode4: %s' % str(subnode4))
element_data = subnode4.childNodes[0].data
element_data = element_data[element_data.find('\n')+1:element_data.rfind('\n')]
data += [element_data]
elif subnode2.nodeName == 'xupdate:append':
keyword = select_list[len(select_list)-1]
if len(getElementNodeList(subnode2))==0:
data = subnode2.childNodes[0].data
data = data[data.find('\n')+1:data.rfind('\n')]
else:
data=[]
for subnode3 in getElementNodeList(subnode2):
element_data = subnode3.childNodes[0].data
element_data = element_data[element_data.find('\n')+1:element_data.rfind('\n')]
data += [element_data]
if len(data) == 1: # This is probably because this is not a list but a string XXX may be not good
data = data[0]
LOG('ERP5Conduit.ApplyUpdate',0,'args: %s' % str(args))
if keyword is not None:
if type(keyword) is type(u"a"):
LOG('ERP5Conduit.ApplyUpdate',0,'keyword before encoding: %s' % str(type(keyword)))
keyword = keyword.encode(self.getEncoding())
LOG('ERP5Conduit.ApplyUpdate',0,'keyword after encoding: %s' % str(type(keyword)))
if not(keyword in self.NOT_EDITABLE_PROPERTY):
if type(data) is type([]) or type(data) is type(()):
new_data = []
for item in data:
if type(item) is type(u"a"):
item = item.encode(self.getEncoding())
new_data += [item]
data = new_data
if type(data) is type(u"a"):
data = data.encode(self.getEncoding())
# if we have already this keyword, then we may append to a list
if args.has_key(keyword):
arg_type = type(args[keyword])
if arg_type is type(()) or arg_type is type([]):
if type(data) is not type(()) or type(data) is not type([]):
data = [data]
data = args[keyword] + data
args[keyword] = data
if len(args) > 0:
object.edit(**args)
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