Commit 24b3ec49 authored by Nicolas Delaby's avatar Nicolas Delaby

Refactor ERP5SyncML partialy

  - replace 4Suite by lxml
  - use new None type
  - store Partial Data in CDATA node instead a Comment node (avoid replacement of '--' by '@-@@-@')
  - list type are loads with marshaler
  - several optimisations, clean useless code
  - testERP5SyncML ran 33% faster than before.


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@25205 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 52b3897e
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
from Products.ERP5SyncML.XMLSyncUtils import XMLSyncUtilsMixin from Products.ERP5SyncML.XMLSyncUtils import XMLSyncUtilsMixin
from Products.ERP5SyncML.Subscription import Conflict from Products.ERP5SyncML.Subscription import Conflict
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.ERP5SyncML.XMLSyncUtils import Parse
from DateTime.DateTime import DateTime from DateTime.DateTime import DateTime
from email.MIMEBase import MIMEBase from email.MIMEBase import MIMEBase
from email import Encoders from email import Encoders
...@@ -41,19 +40,9 @@ from cStringIO import StringIO ...@@ -41,19 +40,9 @@ from cStringIO import StringIO
from xml.sax.saxutils import escape, unescape from xml.sax.saxutils import escape, unescape
import re import re
import cStringIO import cStringIO
from lxml import etree
from xml.marshal.generic import loads as unmarshaler
from zLOG import LOG, INFO, DEBUG from zLOG import LOG, INFO, DEBUG
try:
from Ft.Xml.Domlette import Print, PrettyPrint
except ImportError:
LOG('ERP5Conduit', INFO, "Can't import Print and PrettyPrint")
class Print:
def __init__(self, *args, **kw):
raise ImportError, '4Suite-XML is not installed'
class PrettyPrint:
def __init__(self, *args, **kw):
raise ImportError, '4Suite-XML is not installed'
class ERP5Conduit(XMLSyncUtilsMixin): class ERP5Conduit(XMLSyncUtilsMixin):
""" """
...@@ -133,11 +122,11 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -133,11 +122,11 @@ class ERP5Conduit(XMLSyncUtilsMixin):
conflict_list = [] conflict_list = []
xml = self.convertToXml(xml) xml = self.convertToXml(xml)
if xml is None: if xml is None:
return {'conflict_list':conflict_list, 'object':sub_object} return {'conflict_list': conflict_list, 'object': sub_object}
# In the case where this new node is a object to add # In the case where this new node is a object to add
if xml.nodeName in self.XUPDATE_INSERT_OR_ADD and \ if xml.xpath('name()') in self.XUPDATE_INSERT_OR_ADD and \
self.getSubObjectDepth(xml) == 0: self.getSubObjectDepth(xml) == 0:
if self.isHistoryAdd(xml)!=-1: # bad hack XXX to be removed if self.isHistoryAdd(xml) != -1: # bad hack XXX to be removed
for element in self.getXupdateElementList(xml): for element in self.getXupdateElementList(xml):
xml = self.getElementFromXupdate(element) xml = self.getElementFromXupdate(element)
conflict_list += self.addNode( conflict_list += self.addNode(
...@@ -147,7 +136,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -147,7 +136,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
force=force, force=force,
simulate=simulate, simulate=simulate,
**kw)['conflict_list'] **kw)['conflict_list']
elif xml.nodeName == 'object': elif xml.tag == 'object':
if object_id is None: if object_id is None:
object_id = self.getAttribute(xml, 'id') object_id = self.getAttribute(xml, 'id')
if object_id is not None: if object_id is not None:
...@@ -158,9 +147,9 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -158,9 +147,9 @@ class ERP5Conduit(XMLSyncUtilsMixin):
sub_object = None sub_object = None
if sub_object is None: # If so, it doesn't exist if sub_object is None: # If so, it doesn't exist
portal_type = '' portal_type = ''
if xml.nodeName == 'object': if xml.tag == 'object':
portal_type = self.getObjectType(xml) portal_type = self.getObjectType(xml)
elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD: # Deprecated ??? elif xml.xpath('name()') in self.XUPDATE_INSERT_OR_ADD: # Deprecated ???
portal_type = self.getXupdateObjectType(xml) # Deprecated ??? portal_type = self.getXupdateObjectType(xml) # Deprecated ???
sub_object, reset_local_roles, reset_workflow = self.constructContent( sub_object, reset_local_roles, reset_workflow = self.constructContent(
object, object,
...@@ -172,8 +161,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -172,8 +161,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
simulate=simulate, simulate=simulate,
reset_local_roles=reset_local_roles, reset_local_roles=reset_local_roles,
reset_workflow=reset_workflow) reset_workflow=reset_workflow)
elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD \ elif xml.xpath('name()') in self.XUPDATE_INSERT_OR_ADD \
and self.getSubObjectDepth(xml)>=1: and self.getSubObjectDepth(xml) >= 1:
sub_object_id = self.getSubObjectId(xml) sub_object_id = self.getSubObjectId(xml)
if previous_xml is not None and sub_object_id is not None: if previous_xml is not None and sub_object_id is not None:
# Find the previous xml corresponding to this subobject # Find the previous xml corresponding to this subobject
...@@ -195,12 +184,12 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -195,12 +184,12 @@ class ERP5Conduit(XMLSyncUtilsMixin):
conflict_list += self.addNode(xml=sub_xml,object=sub_object, conflict_list += self.addNode(xml=sub_xml,object=sub_object,
previous_xml=sub_previous_xml, force=force, previous_xml=sub_previous_xml, force=force,
simulate=simulate, **kw)['conflict_list'] simulate=simulate, **kw)['conflict_list']
elif xml.nodeName == self.history_tag or self.isHistoryAdd(xml)>0: elif xml.tag == self.history_tag or self.isHistoryAdd(xml)>0:
conflict_list += self.addWorkflowNode(object, xml, simulate) conflict_list += self.addWorkflowNode(object, xml, simulate)
#elif xml.nodeName in self.local_role_list or self.isLocalRole(xml)>0 and not simulate: #elif xml.tag in self.local_role_list or self.isLocalRole(xml)>0 and not simulate:
elif xml.nodeName in self.local_role_list: elif xml.tag in self.local_role_list:
conflict_list += self.addLocalRoleNode(object, xml) self.addLocalRoleNode(object, xml)
elif xml.nodeName in self.local_permission_list: elif xml.tag in self.local_permission_list:
conflict_list += self.addLocalPermissionNode(object, xml) conflict_list += self.addLocalPermissionNode(object, xml)
else: else:
conflict_list += self.updateNode(xml=xml,object=object, force=force, conflict_list += self.updateNode(xml=xml,object=object, force=force,
...@@ -221,7 +210,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -221,7 +210,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
xml = self.convertToXml(xml) xml = self.convertToXml(xml)
if object_id is None: if object_id is None:
#LOG('ERP5Conduit.deleteNode', DEBUG, 'deleteNode, SubObjectDepth: %i' % self.getSubObjectDepth(xml)) #LOG('ERP5Conduit.deleteNode', DEBUG, 'deleteNode, SubObjectDepth: %i' % self.getSubObjectDepth(xml))
if xml.nodeName == self.xml_object_tag: if xml.tag == self.xml_object_tag:
object_id = self.getAttribute(xml,'id') object_id = self.getAttribute(xml,'id')
elif self.getSubObjectDepth(xml) == 1: elif self.getSubObjectDepth(xml) == 1:
object_id = self.getSubObjectId(xml) object_id = self.getSubObjectId(xml)
...@@ -240,17 +229,17 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -240,17 +229,17 @@ class ERP5Conduit(XMLSyncUtilsMixin):
self.deleteObject(object, object_id) self.deleteObject(object, object_id)
# In the case where we have to delete an user role # In the case where we have to delete an user role
# If we are still there, this means the delete is for this node # If we are still there, this means the delete is for this node
elif xml.nodeName in self.XUPDATE_DEL: elif xml.xpath('name()') in self.XUPDATE_DEL:
xml = self.getElementFromXupdate(xml) xml = self.getElementFromXupdate(xml)
if xml.nodeName in self.local_role_list and not simulate: if xml.tag in self.local_role_list and not simulate:
# We want to del a local role # We want to del a local role
user = self.getAttribute(xml,'id') user = self.getAttribute(xml,'id')
#LOG('ERP5Conduit.deleteNode local_role: ', DEBUG, 'user: %s' % repr(user)) #LOG('ERP5Conduit.deleteNode local_role: ', DEBUG, 'user: %s' % repr(user))
if xml.nodeName.find(self.local_role_tag)>=0: if xml.tag.find(self.local_role_tag)>=0:
object.manage_delLocalRoles([user]) object.manage_delLocalRoles([user])
elif xml.nodeName.find(self.local_group_tag)>=0: elif xml.tag.find(self.local_group_tag)>=0:
object.manage_delLocalGroupRoles([user]) object.manage_delLocalGroupRoles([user])
if xml.nodeName in self.local_permission_list and not simulate: if xml.tag in self.local_permission_list and not simulate:
permission = self.getAttribute(xml,'id') permission = self.getAttribute(xml,'id')
object.manage_setLocalPermissions(permission) object.manage_setLocalPermissions(permission)
return conflict_list return conflict_list
...@@ -277,10 +266,10 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -277,10 +266,10 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if xml is None: if xml is None:
return {'conflict_list':conflict_list, 'object':object} return {'conflict_list':conflict_list, 'object':object}
xml = self.convertToXml(xml) xml = self.convertToXml(xml)
#LOG('ERP5Conduit.updateNode', DEBUG, 'xml.nodeName: %s' % xml.nodeName) #LOG('ERP5Conduit.updateNode', DEBUG, 'xml.tag: %s' % xml.tag)
#LOG('ERP5Conduit.updateNode, force: ', DEBUG, force) #LOG('ERP5Conduit.updateNode, force: ', DEBUG, force)
# we have an xupdate xml # we have an xupdate xml
if xml.nodeName == 'xupdate:modifications': if xml.xpath('name()') == 'xupdate:modifications':
conflict_list += self.applyXupdate(object=object, conflict_list += self.applyXupdate(object=object,
xupdate=xml, xupdate=xml,
conduit=self, conduit=self,
...@@ -290,27 +279,24 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -290,27 +279,24 @@ class ERP5Conduit(XMLSyncUtilsMixin):
# we may have only the part of an xupdate # we may have only the part of an xupdate
else: else:
args = {} args = {}
if self.isProperty(xml) and not(self.isSubObjectModification(xml)): if self.isProperty(xml):
keyword = None keyword = None
for subnode in self.getAttributeNodeList(xml): value = xml.attrib.get('select', None)
if subnode.nodeName == 'select': if value is not None:
select_list = subnode.nodeValue.split('/') # Something like: select_list = value.split('/') # Something like:
#('','object[1]','sid[1]') #('','object[1]','sid[1]')
new_select_list = () new_select_list = ()
for select_item in select_list: for select_item in select_list:
if select_item.find('[')>=0: if select_item.find('[') >= 0:
select_item = select_item[:select_item.find('[')] select_item = select_item[:select_item.find('[')]
new_select_list += (select_item,) new_select_list += (select_item,)
select_list = new_select_list # Something like : ('','object','sid') select_list = new_select_list # Something like : ('','object','sid')
keyword = select_list[len(select_list)-1] # this will be 'sid' keyword = select_list[len(select_list)-1] # this will be 'sid'
data_xml = xml
data = None data = None
if xml.nodeName not in self.XUPDATE_INSERT_OR_ADD: if xml.xpath('name()') not in self.XUPDATE_INSERT_OR_ADD:
for subnode in self.getElementNodeList(xml): for subnode in xml:
if subnode.nodeName == 'xupdate:element': if subnode.xpath('name()') in self.XUPDATE_EL:
for subnode1 in subnode.attributes: keyword = subnode.attrib.get('name', None)
if subnode1.nodeName == 'name':
keyword = subnode1.nodeValue
data_xml = subnode data_xml = subnode
else: else:
#We can call add node #We can call add node
...@@ -321,7 +307,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -321,7 +307,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
**kw) **kw)
return conflict_list return conflict_list
if xml.nodeName in self.XUPDATE_DEL: if xml.xpath('name()') in self.XUPDATE_DEL:
conflict_list += self.deleteNode(xml=xml, conflict_list += self.deleteNode(xml=xml,
object=object, object=object,
force=force, force=force,
...@@ -329,17 +315,12 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -329,17 +315,12 @@ class ERP5Conduit(XMLSyncUtilsMixin):
**kw) **kw)
return conflict_list return conflict_list
if keyword is None: # This is not a selection, directly the property if keyword is None: # This is not a selection, directly the property
keyword = xml.nodeName keyword = xml.tag
if len(self.getElementNodeList(data_xml)) == 0:
try:
data = data_xml.childNodes[0].data
except IndexError: # There is no data
data = None
if not (keyword in self.NOT_EDITABLE_PROPERTY): if not (keyword in self.NOT_EDITABLE_PROPERTY):
# We will look for the data to enter # We will look for the data to enter
data_type = object.getPropertyType(keyword) data_type = object.getPropertyType(keyword)
#LOG('ERP5Conduit.updateNode', DEBUG, 'data_type: %s for keyword: %s' % (str(data_type), keyword)) #LOG('ERP5Conduit.updateNode', DEBUG, 'data_type: %s for keyword: %s' % (str(data_type), keyword))
data = self.convertXmlValue(data, data_type=data_type) data = self.convertXmlValue(xml, data_type=data_type)
args[keyword] = data args[keyword] = data
args = self.getFormatedArgs(args=args) args = self.getFormatedArgs(args=args)
# This is the place where we should look for conflicts # This is the place where we should look for conflicts
...@@ -367,11 +348,10 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -367,11 +348,10 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if 1: if 1:
# This is a conflict # This is a conflict
isConflict = 1 isConflict = 1
string_io = StringIO() xml_string = etree.tostring(xml, encoding='utf-8')
PrettyPrint(xml, stream=string_io)
conflict = Conflict(object_path=object.getPhysicalPath(), conflict = Conflict(object_path=object.getPhysicalPath(),
keyword=keyword) keyword=keyword)
conflict.setXupdate(string_io.getvalue()) conflict.setXupdate(xml_string)
if not (data_type in self.binary_type_list): if not (data_type in self.binary_type_list):
conflict.setLocalValue(current_data) conflict.setLocalValue(current_data)
conflict.setRemoteValue(data) conflict.setRemoteValue(data)
...@@ -392,8 +372,9 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -392,8 +372,9 @@ class ERP5Conduit(XMLSyncUtilsMixin):
**kw)['conflict_list'] **kw)['conflict_list']
elif keyword == self.history_tag and not simulate: elif keyword == self.history_tag and not simulate:
# This is the case where we have to call addNode # This is the case where we have to call addNode
conflict_list += self.addNode(xml=subnode,object=object,force=force, conflict_list += self.addNode(xml=subnode, object=object,
simulate=simulate,**kw)['conflict_list'] force=force, simulate=simulate,
**kw)['conflict_list']
elif keyword in (self.local_role_tag, self.local_permission_tag) and not simulate: elif keyword in (self.local_role_tag, self.local_permission_tag) and not simulate:
# This is the case where we have to update Roles or update permission # This is the case where we have to update Roles or update permission
#LOG('ERP5Conduit.updateNode', DEBUG, 'we will add a local role') #LOG('ERP5Conduit.updateNode', DEBUG, 'we will add a local role')
...@@ -401,20 +382,21 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -401,20 +382,21 @@ class ERP5Conduit(XMLSyncUtilsMixin):
#roles = self.convertXmlValue(data,data_type='tokens') #roles = self.convertXmlValue(data,data_type='tokens')
#object.manage_setLocalRoles(user,roles) #object.manage_setLocalRoles(user,roles)
xml = self.getElementFromXupdate(xml) xml = self.getElementFromXupdate(xml)
conflict_list += self.addNode(xml=xml, object=object, force=force, conflict_list += self.addNode(xml=xml, object=object,
simulate=simulate,**kw)['conflict_list'] force=force, simulate=simulate,
**kw)['conflict_list']
elif self.isSubObjectModification(xml): elif self.isSubObjectModification(xml):
# We should find the object corresponding to # We should find the object corresponding to
# this update, so we have to look in the previous_xml # this update, so we have to look in the previous_xml
sub_object_id = self.getSubObjectId(xml) sub_object_id = self.getSubObjectId(xml)
#LOG('ERP5Conduit.updateNode', DEBUG,'isSubObjectModification sub_object_id: %s' % sub_object_id) #LOG('ERP5Conduit.updateNode', DEBUG,'isSubObjectModification sub_object_id: %s' % sub_object_id)
if previous_xml is not None and sub_object_id is not None: if previous_xml is not None and sub_object_id is not None:
sub_previous_xml = self.getSubObjectXml(sub_object_id,previous_xml) sub_previous_xml = self.getSubObjectXml(sub_object_id, previous_xml)
#LOG('ERP5Conduit.updateNode', DEBUG, 'isSubObjectModification sub_previous_xml: %s' % str(sub_previous_xml)) #LOG('ERP5Conduit.updateNode', DEBUG, 'isSubObjectModification sub_previous_xml: %s' % str(sub_previous_xml))
if sub_previous_xml is not None: if sub_previous_xml is not None:
sub_object = None sub_object = None
try: try:
sub_object = object[sub_object_id] sub_object = object._getOb(sub_object_id)
except KeyError: except KeyError:
pass pass
if sub_object is not None: if sub_object is not None:
...@@ -425,7 +407,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -425,7 +407,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
#LOG('ERP5Conduit.updateNode', DEBUG, 'sub_xml: %s' % str(sub_xml)) #LOG('ERP5Conduit.updateNode', DEBUG, 'sub_xml: %s' % str(sub_xml))
# Then do the udpate # Then do the udpate
conflict_list += self.updateNode(xml=sub_xml, object=sub_object, conflict_list += self.updateNode(xml=sub_xml, object=sub_object,
force=force, previous_xml=sub_previous_xml, force=force,
previous_xml=sub_previous_xml,
simulate=simulate, **kw) simulate=simulate, **kw)
elif previous_xml is None and xml is not None and sub_object_id is not None: elif previous_xml is None and xml is not None and sub_object_id is not None:
sub_object = None sub_object = None
...@@ -465,19 +448,17 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -465,19 +448,17 @@ class ERP5Conduit(XMLSyncUtilsMixin):
new_args = {} new_args = {}
for keyword in args.keys(): for keyword in args.keys():
data = args[keyword] data = args[keyword]
if type(keyword) is type(u"a"): if isinstance(keyword, unicode):
keyword = keyword.encode(self.getEncoding()) keyword = keyword.encode(self.getEncoding())
if type(data) is type([]) or type(data) is type(()): if isinstance(data, (tuple, list)):
new_data = [] new_data = []
for item in data: for item in data:
if type(item) is type(u"a"): if isinstance(item, unicode):
item = item.encode(self.getEncoding()) item = item.encode(self.getEncoding())
item = item.replace('@@@','\n') new_data.append(item)
new_data += [item]
data = new_data data = new_data
if type(data) is type(u"a"): if isinstance(data, unicode):
data = data.encode(self.getEncoding()) data = data.encode(self.getEncoding())
data = data.replace('@@@','\n')
if keyword == 'binary_data': if keyword == 'binary_data':
#LOG('ERP5Conduit.getFormatedArgs', DEBUG, 'binary_data keyword: %s' % str(keyword)) #LOG('ERP5Conduit.getFormatedArgs', DEBUG, 'binary_data keyword: %s' % str(keyword))
msg = MIMEBase('application','octet-stream') msg = MIMEBase('application','octet-stream')
...@@ -487,17 +468,17 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -487,17 +468,17 @@ class ERP5Conduit(XMLSyncUtilsMixin):
new_args[keyword] = data new_args[keyword] = data
return new_args return new_args
security.declareProtected(Permissions.AccessContentsInformation,'isProperty') security.declareProtected(Permissions.AccessContentsInformation, 'isProperty')
def isProperty(self, xml): def isProperty(self, xml):
""" """
Check if it is a simple property Check if it is a simple property
not an attribute @type it's a metadata
""" """
bad_list = (self.sub_object_exp,self.history_exp) bad_list = (self.sub_object_exp, self.history_exp, self.attribute_type_exp,)
for subnode in self.getAttributeNodeList(xml): value = xml.attrib.get('select', None)
if subnode.nodeName == 'select': if value is not None:
value = subnode.nodeValue
for bad_string in bad_list: for bad_string in bad_list:
if re.search(bad_string,value) is not None: if bad_string.search(value) is not None:
return 0 return 0
return 1 return 1
...@@ -508,22 +489,20 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -508,22 +489,20 @@ class ERP5Conduit(XMLSyncUtilsMixin):
This will change the xml in order to change the update This will change the xml in order to change the update
from the object to the subobject from the object to the subobject
""" """
xml_copy = xml.cloneNode(True) #make a deepcopy of the node xml from copy import deepcopy
for subnode in self.getAttributeNodeList(xml_copy): xml_copy = deepcopy(xml)
if subnode.nodeName == 'select': self.changeSubObjectSelect(xml_copy)
subnode.nodeValue = self.getSubObjectSelect(subnode.nodeValue)
return xml_copy return xml_copy
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'isHistoryAdd') 'isHistoryAdd')
def isHistoryAdd(self, xml): def isHistoryAdd(self, xml):
bad_list = (self.history_exp,) bad_list = (self.history_exp,)
for subnode in self.getAttributeNodeList(xml): value = xml.attrib.get('select')
if subnode.nodeName == 'select': if value is not None:
value = subnode.nodeValue
for bad_string in bad_list: for bad_string in bad_list:
if re.search(bad_string,value) is not None: if bad_string.search(value) is not None:
if re.search(self.bad_history_exp,value) is None: if self.bad_history_exp.search(value) is None:
return 1 return 1
else: else:
return -1 return -1
...@@ -536,11 +515,10 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -536,11 +515,10 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Check if it is a modification from an subobject Check if it is a modification from an subobject
""" """
good_list = (self.sub_object_exp,) good_list = (self.sub_object_exp,)
for subnode in self.getAttributeNodeList(xml) : value = xml.attrib.get('select', None)
if subnode.nodeName == 'select': if value is not None:
value = subnode.nodeValue
for good_string in good_list: for good_string in good_list:
if re.search(good_string,value) is not None: if good_string.search(value) is not None:
return 1 return 1
return 0 return 0
...@@ -553,45 +531,44 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -553,45 +531,44 @@ class ERP5Conduit(XMLSyncUtilsMixin):
1 means it is a subobject 1 means it is a subobject
2 means it is more depth than subobject 2 means it is more depth than subobject
""" """
#LOG('getSubObjectDepth',0,'xml.nodeName: %s' % xml.nodeName) #LOG('getSubObjectDepth',0,'xml.tag: %s' % xml.tag)
if xml.nodeName in self.XUPDATE_TAG: if xml.xpath('name()') in self.XUPDATE_TAG:
i = 0 i = 0
if xml.nodeName in self.XUPDATE_INSERT: if xml.xpath('name()') in self.XUPDATE_INSERT:
i = 1 i = 1
#LOG('getSubObjectDepth',0,'xml2.nodeName: %s' % xml.nodeName) #LOG('getSubObjectDepth',0,'xml2.tag: %s' % xml.tag)
for subnode in self.getAttributeNodeList(xml): value = xml.attrib.get('select', None)
#LOG('getSubObjectDepth',0,'subnode.nodeName: %s' % subnode.nodeName) if value is not None:
if subnode.nodeName == 'select':
value = subnode.nodeValue
#LOG('getSubObjectDepth',0,'subnode.nodeValue: %s' % subnode.nodeValue) #LOG('getSubObjectDepth',0,'subnode.nodeValue: %s' % subnode.nodeValue)
if re.search(self.sub_sub_object_exp,value) is not None: if self.sub_sub_object_exp.search(value) is not None:
return 2 # This is sure in all cases return 2 # This is sure in all cases
elif re.search(self.sub_object_exp,value) is not None: elif self.sub_object_exp.search(value) is not None:
#new_select = self.getSubObjectSelect(value) # Still needed ??? #new_select = self.getSubObjectSelect(value) # Still needed ???
#if self.getSubObjectSelect(new_select) != new_select: #if self.getSubObjectSelect(new_select) != new_select:
# return (2 - i) # return (2 - i)
#return (1 - i) #return (1 - i)
return (2 - i) return (2 - i)
elif re.search(self.object_exp,value) is not None: elif self.object_exp.search(value) is not None:
return (1 - i) return (1 - i)
return 0 return 0
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.ModifyPortalContent,
'getSubObjectSelect') 'changeSubObjectSelect')
def getSubObjectSelect(self, select): def changeSubObjectSelect(self, xml):
""" """
Return a string wich is the selection for the subobject Return a string wich is the selection for the subobject
ex: for "/object[@id='161']/object[@id='default_address']/street_address" ex: for "/object[@id='161']/object[@id='default_address']/street_address"
it returns "/object[@id='default_address']/street_address" it returns "/object[@id='default_address']/street_address"
""" """
if re.search(self.object_exp,select) is not None: select = xml.attrib.get('select')
if self.object_exp.search(select) is not None:
s = '/' s = '/'
if re.search('/.*/',select) is not None: # This means we have more than just object if re.search('/.*/', select) is not None: # This means we have more than just object
new_value = select[select.find(s,select.find(s)+1):] new_value = select[select.find(s, select.find(s)+1):]
else: else:
new_value = '/' new_value = '/'
select = new_value select = new_value
return select xml.attrib['select'] = select
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectId') 'getSubObjectId')
...@@ -600,13 +577,12 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -600,13 +577,12 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Return the id of the subobject in an xupdate modification Return the id of the subobject in an xupdate modification
""" """
object_id = None object_id = None
for subnode in self.getAttributeNodeList(xml): value = xml.attrib.get('select', None)
if subnode.nodeName == 'select': if value is not None:
value = subnode.nodeValue if self.object_exp.search(value) is not None:
if re.search(self.object_exp,value) is not None:
s = "'" s = "'"
first = value.find(s)+1 first = value.find(s) + 1
object_id = value[first:value.find(s,first)] object_id = value[first:value.find(s, first)]
return object_id return object_id
return object_id return object_id
...@@ -617,13 +593,12 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -617,13 +593,12 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Return the id of the subobject in an xupdate modification Return the id of the subobject in an xupdate modification
""" """
object_id = None object_id = None
for subnode in self.getAttributeNodeList(xml): value = xml.attrib.get('select', None)
if subnode.nodeName == 'select': if value is not None:
value = subnode.nodeValue if self.history_exp.search(value) is not None:
if re.search(self.history_exp,value) is not None:
s = self.history_tag s = self.history_tag
object_id = value[value.find(s):] object_id = value[value.find(s):]
object_id = object_id[object_id.find("'")+1:] object_id = object_id[object_id.find("'") + 1:]
object_id = object_id[:object_id.find("'")] object_id = object_id[:object_id.find("'")]
return object_id return object_id
return object_id return object_id
...@@ -635,9 +610,9 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -635,9 +610,9 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Return the xml of the subobject which as the id object_id Return the xml of the subobject which as the id object_id
""" """
xml = self.convertToXml(xml) xml = self.convertToXml(xml)
for subnode in self.getElementNodeList(xml): for subnode in xml:
if subnode.nodeName == self.xml_object_tag: if subnode.tag == self.xml_object_tag:
if object_id == self.getAttribute(subnode,'id'): if object_id == self.getAttribute(subnode, 'id'):
return subnode return subnode
return None return None
...@@ -646,11 +621,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -646,11 +621,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
Retrieve the given parameter from the xml Retrieve the given parameter from the xml
""" """
for attribute in self.getAttributeNodeList(xml): return xml.attrib.get(param, None)
if attribute.nodeName == param:
data = attribute.value
return self.convertXmlValue(data, data_type='string')
return None
security.declareProtected(Permissions.AccessContentsInformation,'getObjectProperty') security.declareProtected(Permissions.AccessContentsInformation,'getObjectProperty')
def getObjectProperty(self, property, xml, data_type=None): def getObjectProperty(self, property, xml, data_type=None):
...@@ -659,34 +630,24 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -659,34 +630,24 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
xml = self.convertToXml(xml) xml = self.convertToXml(xml)
# document, with childNodes[0] a DocumentType and childNodes[1] the Element Node # document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
for subnode in self.getElementNodeList(xml): for subnode in xml:
if subnode.nodeName == property: if subnode.tag == property:
if data_type is None: return self.convertXmlValue(subnode)
data_type = self.getPropertyType(subnode)
try:
data = subnode.childNodes[0].data
except IndexError: # There is no data
data = None
data = self.convertXmlValue(data, data_type=data_type)
return data
return None return None
security.declareProtected(Permissions.AccessContentsInformation,'convertToXml') security.declareProtected(Permissions.AccessContentsInformation,'convertToXml')
def convertToXml(self,xml): def convertToXml(self, xml):
""" """
if xml is a string, convert it to a node if xml is a string, convert it to a node
""" """
if xml is None: if xml is None: return None
return if isinstance(xml, (str, unicode)):
if type(xml) in (type('a'),type(u'a')): if isinstance(xml, unicode):
if type(xml) is type(u'a'):
xml = xml.encode('utf-8') xml = xml.encode('utf-8')
xml = Parse(xml) xml = etree.XML(xml)
#LOG('Conduit.convertToXml not failed',0,'ok')
xml = xml.childNodes[0] # Because we just created a new xml
# If we have the xml from the node erp5, we just take the subnode # If we have the xml from the node erp5, we just take the subnode
if xml.nodeName == 'erp5': if xml.tag == 'erp5':
xml = self.getElementNodeList(xml)[0] xml = xml[0]
return xml return xml
security.declareProtected(Permissions.AccessContentsInformation,'getObjectType') security.declareProtected(Permissions.AccessContentsInformation,'getObjectType')
...@@ -694,23 +655,14 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -694,23 +655,14 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
Retrieve the portal type from an xml Retrieve the portal type from an xml
""" """
portal_type = None return '%s' % xml.xpath('string(.//@portal_type)')
attr_list = xml.xpath('.//@portal_type[1]')
if attr_list:
portal_type = attr_list[0].value.encode('utf-8')
return portal_type
security.declareProtected(Permissions.AccessContentsInformation,'getPropertyType') security.declareProtected(Permissions.AccessContentsInformation,'getPropertyType')
def getPropertyType(self, xml): def getPropertyType(self, xml):
""" """
Retrieve the portal type from an xml Retrieve the portal type from an xml
""" """
p_type = None return '%s' % xml.xpath('string(.//@type)')
attr_list = xml.xpath('.//@type[1]')
if attr_list:
p_type = attr_list[0].value.encode('utf-8')
p_type = self.convertXmlValue(p_type, data_type='string')
return p_type
security.declareProtected(Permissions.AccessContentsInformation,'getXupdateObjectType') security.declareProtected(Permissions.AccessContentsInformation,'getXupdateObjectType')
def getXupdateObjectType(self, xml): def getXupdateObjectType(self, xml):
...@@ -718,22 +670,11 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -718,22 +670,11 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Retrieve the portal type from an xupdate Retrieve the portal type from an xupdate
XXXX This should not be used any more !!! XXXXXXXXXXX XXXX This should not be used any more !!! XXXXXXXXXXX
""" """
if xml.nodeName.find('xupdate')>=0: return xml.xpath('string(.//*[name() == "xupdate:attribute"][@name = "portal_type"])') or None
for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'xupdate:element':
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName == 'xupdate:attribute':
for attribute in subnode1.attributes:
if attribute.nodeName == 'name':
if attribute.nodeValue == 'portal_type':
data = subnode1.childNodes[0].data
data = self.convertXmlValue(data)
return data
return None
security.declareProtected(Permissions.ModifyPortalContent, 'newObject') security.declareProtected(Permissions.ModifyPortalContent, 'newObject')
def newObject(self, object=None, xml=None, simulate=0, reset_local_roles=1, reset_workflow=1): def newObject(self, object=None, xml=None, simulate=0, reset_local_roles=1,
reset_workflow=1):
""" """
modify the object with datas from modify the object with datas from
the xml (action section) the xml (action section)
...@@ -747,24 +688,16 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -747,24 +688,16 @@ class ERP5Conduit(XMLSyncUtilsMixin):
object.manage_delLocalRoles(user_role_list) object.manage_delLocalRoles(user_role_list)
if getattr(object, 'workflow_history', None) is not None and reset_workflow: if getattr(object, 'workflow_history', None) is not None and reset_workflow:
object.workflow_history = PersistentMapping() object.workflow_history = PersistentMapping()
if xml.nodeName.find('xupdate') >= 0: if xml.tag.find('xupdate') >= 0:
xml = self.getElementNodeList(xml)[0] xml = xml[0]
for subnode in self.getElementNodeList(xml): for subnode in xml.xpath('*'):
if subnode.nodeName not in self.NOT_EDITABLE_PROPERTY: #get only Element nodes (not Comments or Processing instructions)
if subnode.tag not in self.NOT_EDITABLE_PROPERTY:
keyword_type = self.getPropertyType(subnode) keyword_type = self.getPropertyType(subnode)
# This is the case where the property is a list # This is the case where the property is a list
keyword = str(subnode.nodeName) keyword = subnode.tag
data = None args[keyword] = self.convertXmlValue(subnode, keyword_type)
while subnode.hasChildNodes(): # We check that this tag is not empty elif subnode.tag in self.ADDABLE_PROPERTY + (self.xml_object_tag,):
subnode = subnode.firstChild
if subnode.nodeType == subnode.TEXT_NODE:
data = subnode.data
args[keyword] = data
#if args.has_key(keyword):
# LOG('newObject',0,'data: %s' % str(args[keyword]))
if args.has_key(keyword):
args[keyword] = self.convertXmlValue(args[keyword], keyword_type)
elif subnode.nodeName in self.ADDABLE_PROPERTY:
self.addNode(object=object, xml=subnode, force=1) self.addNode(object=object, xml=subnode, force=1)
# We should first edit the object # We should first edit the object
args = self.getFormatedArgs(args=args) args = self.getFormatedArgs(args=args)
...@@ -775,10 +708,10 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -775,10 +708,10 @@ class ERP5Conduit(XMLSyncUtilsMixin):
object.manage_afterEdit() object.manage_afterEdit()
self.afterNewObject(object) self.afterNewObject(object)
# Then we may create subobject ## Then we may create subobject
for subnode in self.getElementNodeList(xml): #for subnode in xml:
if subnode.nodeName in (self.xml_object_tag,): #,self.history_tag): #if subnode.tag in (self.xml_object_tag,): #,self.history_tag):
self.addNode(object=object, xml=subnode) #self.addNode(object=object, xml=subnode)
security.declareProtected(Permissions.AccessContentsInformation,'afterNewObject') security.declareProtected(Permissions.AccessContentsInformation,'afterNewObject')
def afterNewObject(self, object): def afterNewObject(self, object):
...@@ -790,8 +723,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -790,8 +723,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Return a worklow status from xml Return a worklow status from xml
""" """
status = {} status = {}
for subnode in self.getElementNodeList(xml): for subnode in xml:
keyword = self.convertXmlValue(subnode.nodeName) keyword = subnode.tag
value = self.getObjectProperty(keyword, xml) value = self.getObjectProperty(keyword, xml)
status[keyword] = value status[keyword] = value
return status return status
...@@ -801,45 +734,32 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -801,45 +734,32 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
Retrieve the list of xupdate:element subnodes Retrieve the list of xupdate:element subnodes
""" """
e_list = [] return xml.xpath('|'.join(['.//*[name() = "%s"]' % name for name in self.XUPDATE_EL]))
for subnode in self.getElementNodeList(xml):
if subnode.nodeName in self.XUPDATE_EL:
e_list += [subnode]
#LOG('getXupdateElementList, e_list:',0,e_list)
return e_list
security.declareProtected(Permissions.AccessContentsInformation,'getElementFromXupdate') security.declareProtected(Permissions.AccessContentsInformation,'getElementFromXupdate')
def getElementFromXupdate(self, xml): def getElementFromXupdate(self, xml):
""" """
from a xupdate:element returns the element as xml from a xupdate:element returns the element as xml
""" """
if xml.nodeName in self.XUPDATE_EL: if xml.xpath('name()') in self.XUPDATE_EL:
result = unicode('<', encoding='utf-8') result = '<'
result += xml.attributes.values()[0].nodeValue tag_name = xml.attrib.get('name')
for subnode in self.getElementNodeList(xml): #getElementNodeList result += tag_name
if subnode.nodeName == 'xupdate:attribute': for subnode in xml:
result += ' %s=' % subnode.attributes.values()[0].nodeValue if subnode.xpath('name()') == 'xupdate:attribute':
result += '"%s"' % subnode.childNodes[0].nodeValue result += ' %s=' % subnode.attrib.get('name')
result += '"%s"' % subnode.text
result += '>' result += '>'
# Then dumps the xml and remove what we does'nt want # Then dumps the xml and remove what we does'nt want
#xml_string = StringIO()
#PrettyPrint(xml,xml_string)
#xml_string = xml_string.getvalue()
#xml_string = unicode(xml_string,encoding='utf-8')
xml_string = self.nodeToString(xml) xml_string = self.nodeToString(xml)
xml_string = unicode(xml_string, encoding='utf-8')
#if type(xml_string) is type (u'a'):
# xml_string = xml_string.encode('utf-8')
maxi = max(xml_string.find('>')+1,\ maxi = max(xml_string.find('>')+1,\
xml_string.rfind('</xupdate:attribute>')+len('</xupdate:attribute>')) xml_string.rfind('</xupdate:attribute>')+len('</xupdate:attribute>'))
result += xml_string[maxi:xml_string.find('</xupdate:element>')] result += xml_string[maxi:xml_string.find('</xupdate:element>')]
result += '</%s>' % xml.attributes.values()[0].nodeValue result += '</%s>' % tag_name
return self.convertToXml(result.encode('utf-8')) return self.convertToXml(result)
if xml.nodeName in (self.XUPDATE_UPDATE+self.XUPDATE_DEL): if xml.xpath('name()') in (self.XUPDATE_UPDATE + self.XUPDATE_DEL):
result = u'<' result = u'<'
for subnode in self.getAttributeNodeList(xml): attribute = xml.attrib.get('select')
if subnode.nodeName == 'select':
attribute = subnode.nodeValue
s = '[@id=' s = '[@id='
s_place = attribute.find(s) s_place = attribute.find(s)
select_id = None select_id = None
...@@ -848,17 +768,14 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -848,17 +768,14 @@ class ERP5Conduit(XMLSyncUtilsMixin):
select_id = select_id[:select_id.find("'",1)+1] select_id = select_id[:select_id.find("'",1)+1]
else: else:
s_place = len(attribute) s_place = len(attribute)
property = attribute[:s_place] property = attribute[:s_place].strip('/')
if property.find('/') == 0:
property = property[1:]
result += property result += property
if select_id is not None: if select_id is not None:
result += ' id=%s' % select_id result += ' id=%s' % select_id
result += '>' result += '>'
xml_string = self.nodeToString(xml) xml_string = self.nodeToString(xml)
xml_string = unicode(xml_string,encoding='utf-8')
maxi = xml_string.find('>')+1 maxi = xml_string.find('>')+1
result += xml_string[maxi:xml_string.find('</%s>' % xml.nodeName)] result += xml_string[maxi:xml_string.find('</%s>' % xml.xpath('name()'))]
result += '</%s>' % (property) result += '</%s>' % (property)
#LOG('getElementFromXupdate, result:',0,repr(result)) #LOG('getElementFromXupdate, result:',0,repr(result))
return self.convertToXml(result) return self.convertToXml(result)
...@@ -870,49 +787,42 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -870,49 +787,42 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Return the list of workflow actions Return the list of workflow actions
""" """
action_list = [] action_list = []
if xml.nodeName in self.XUPDATE_EL: if xml.xpath('name()') in self.XUPDATE_EL:
action_list += [xml] action_list.append(xml)
return action_list return action_list
for subnode in self.getElementNodeList(xml): for subnode in xml:
if subnode.nodeName == self.action_tag: if subnode.tag == self.action_tag:
action_list += [subnode] action_list.append(subnode)
return action_list return action_list
security.declareProtected(Permissions.AccessContentsInformation,'convertXmlValue') security.declareProtected(Permissions.AccessContentsInformation,'convertXmlValue')
def convertXmlValue(self, data, data_type=None): def convertXmlValue(self, node, data_type=None):
""" """
It is possible that the xml change the value, for example It is possible that the xml change the value, for example
there is some too much '\n' and some spaces. We have to do some extra there is some too much '\n' and some spaces. We have to do some extra
things so that we convert correctly the value things so that we convert correctly the value
XXXNicolas: I'm totally disagree with, so i comment this code XXXNicolas: I'm totally disagree with, so i comment this code
""" """
if data is None: if node is None: return None
if data_type is None:
data_type = self.getPropertyType(node)
if data_type == self.none_type: return None
data = node.text
if data is not None and isinstance(data, unicode):
data = data.encode('utf-8')
elif data is None:
if data_type in self.list_type_list: if data_type in self.list_type_list:
data = () data = ()
if data_type in self.text_type_list: elif data_type in self.text_type_list:
data = '' data = ''
return data return data
#data = data.replace('\n','')
if isinstance(data, unicode):
data = data.encode(self.getEncoding())
if data == 'None':
return None
# We can now convert string in tuple, dict, binary... # We can now convert string in tuple, dict, binary...
if data_type in self.list_type_list: if data_type in self.list_type_list:
if type(data) is type('a'): data = unmarshaler(node.text)
data = tuple(data.split('@@@'))
elif data_type in self.text_type_list: 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)
data = unescape(data) data = unescape(data)
elif data_type in self.pickle_type_list: elif data_type in self.pickle_type_list:
data = data.replace('@@@','\n') msg = MIMEBase('application', 'octet-stream')
msg = MIMEBase('application','octet-stream')
Encoders.encode_base64(msg) Encoders.encode_base64(msg)
msg.set_payload(data) msg.set_payload(data)
data = msg.get_payload(decode=1) data = msg.get_payload(decode=1)
...@@ -925,7 +835,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -925,7 +835,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if data == '{}': if data == '{}':
data = {} data = {}
else: else:
dict_list = map(lambda x:x.split(':'),data[1:-1].split(',')) dict_list = map(lambda x:x.split(':'), data[1:-1].split(','))
data = map(lambda (x,y):(x.replace(' ','').replace("'",''),int(y)),dict_list) data = map(lambda (x,y):(x.replace(' ','').replace("'",''),int(y)),dict_list)
data = dict(data) data = dict(data)
return data return data
...@@ -939,15 +849,14 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -939,15 +849,14 @@ class ERP5Conduit(XMLSyncUtilsMixin):
Parse the xupdate and then it will call the conduit Parse the xupdate and then it will call the conduit
""" """
conflict_list = [] conflict_list = []
if type(xupdate) in (type('a'),type(u'a')): if isinstance(xupdate, (str, unicode)):
xupdate = Parse(xupdate) xupdate = etree.XML(xupdate)
#When xupdate mix different object, (like object and his subobject) we need to treat them separatly #When xupdate mix different object, (like object and his subobject) we need to treat them separatly
if self.isMixedXupdate(xupdate): if self.isMixedXupdate(xupdate):
#return to updateNode with only one line #return to updateNode with only one line
#del all sub_element #del all sub_element
sub_node_list = self.getElementNodeList(xupdate)
#clean the node #clean the node
for subnode in sub_node_list: for subnode in xupdate:
#Create one xupdate:modification per update node #Create one xupdate:modification per update node
conflict_list += self.updateNode(xml=subnode, conflict_list += self.updateNode(xml=subnode,
object=object, object=object,
...@@ -955,38 +864,37 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -955,38 +864,37 @@ class ERP5Conduit(XMLSyncUtilsMixin):
simulate=simulate, simulate=simulate,
**kw) **kw)
return conflict_list return conflict_list
for subnode in self.getElementNodeList(xupdate): for subnode in xupdate:
sub_xupdate = self.getSubObjectXupdate(subnode) sub_xupdate = self.getSubObjectXupdate(subnode)
selection_name = '' selection_name = ''
if subnode.nodeName in self.XUPDATE_INSERT_OR_ADD: if subnode.xpath('name()') in self.XUPDATE_INSERT_OR_ADD:
conflict_list += conduit.addNode(xml=sub_xupdate,object=object, \ conflict_list += conduit.addNode(xml=sub_xupdate,object=object,
force=force, simulate=simulate, **kw)['conflict_list'] force=force, simulate=simulate,
elif subnode.nodeName in self.XUPDATE_DEL: **kw)['conflict_list']
conflict_list += conduit.deleteNode(xml=sub_xupdate, object=object, \ elif subnode.xpath('name()') in self.XUPDATE_DEL:
conflict_list += conduit.deleteNode(xml=sub_xupdate, object=object,
force=force, simulate=simulate, **kw) force=force, simulate=simulate, **kw)
elif subnode.nodeName in self.XUPDATE_UPDATE: elif subnode.xpath('name()') in self.XUPDATE_UPDATE:
conflict_list += conduit.updateNode(xml=sub_xupdate, object=object, \ conflict_list += conduit.updateNode(xml=sub_xupdate, object=object,
force=force, simulate=simulate, **kw) force=force, simulate=simulate, **kw)
#elif subnode.nodeName in self.XUPDATE_INSERT:
# conflict_list += conduit.addNode(xml=subnode, object=object, force=force, **kw)
return conflict_list return conflict_list
def isMixedXupdate(self, xml): def isMixedXupdate(self, xml):
#If an xupdate:modifications contains modification which concerns different objects #If an xupdate:modifications contains modification which concerns different objects
subnode_list = self.getElementNodeList(xml) subnode_list = xml
nb_sub = len(subnode_list) nb_sub = len(subnode_list)
comp = 0 comp = 0
for subnode in subnode_list: for subnode in subnode_list:
value = self.getAttribute(subnode, 'select') value = self.getAttribute(subnode, 'select')
if re.search(self.object_exp, value): if self.object_exp.search(value) is not None:
comp += 1 comp += 1
if nb_sub == comp: if nb_sub == comp:
return 0 return 0
return 1 return 1
def isWorkflowActionAddable(self, object=None,status=None,wf_tool=None, def isWorkflowActionAddable(self, object=None, status=None, wf_tool=None,
wf_id=None,xml=None): wf_id=None, xml=None):
""" """
Some checking in order to check if we should add the workfow or not Some checking in order to check if we should add the workfow or not
We should not returns a conflict list as we wanted before, we should We should not returns a conflict list as we wanted before, we should
...@@ -1018,7 +926,6 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1018,7 +926,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
This is really usefull if you want to write your This is really usefull if you want to write your
own Conduit. own Conduit.
""" """
portal_types = getToolByName(object, 'portal_types')
#LOG('ERP5Conduit.addNode',0,'portal_type: |%s|' % str(portal_type)) #LOG('ERP5Conduit.addNode',0,'portal_type: |%s|' % str(portal_type))
object.newContent(portal_type=portal_type, id=object_id) object.newContent(portal_type=portal_type, id=object_id)
...@@ -1037,7 +944,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1037,7 +944,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
wf_id = self.getAttribute(xml,'id') wf_id = self.getAttribute(xml,'id')
if wf_id is None: # History added by xupdate if wf_id is None: # History added by xupdate
wf_id = self.getHistoryIdFromSelect(xml) wf_id = self.getHistoryIdFromSelect(xml)
xml = self.getElementNodeList(xml)[0] xml = xml[0]
#for action in self.getWorkflowActionFromXml(xml): #for action in self.getWorkflowActionFromXml(xml):
status = self.getStatusFromXml(xml) status = self.getStatusFromXml(xml)
#LOG('addNode, status:',0,status) #LOG('addNode, status:',0,status)
...@@ -1067,19 +974,17 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1067,19 +974,17 @@ class ERP5Conduit(XMLSyncUtilsMixin):
This allows to specify how to handle the local role informations. This allows to specify how to handle the local role informations.
This is really usefull if you want to write your own Conduit. This is really usefull if you want to write your own Conduit.
""" """
conflict_list = []
# We want to add a local role # We want to add a local role
roles = self.convertXmlValue(xml.childNodes[0].data,data_type='tokens') roles = self.convertXmlValue(xml, data_type='tokens')
user = self.getAttribute(xml,'id') user = self.getAttribute(xml, 'id')
roles = list(roles) # Needed for CPS, or we have a CPS error roles = list(roles) # Needed for CPS, or we have a CPS error
#LOG('local_role: ',0,'user: %s roles: %s' % (repr(user),repr(roles))) #LOG('local_role: ',0,'user: %s roles: %s' % (repr(user),repr(roles)))
#user = roles[0] #user = roles[0]
#roles = roles[1:] #roles = roles[1:]
if xml.nodeName.find(self.local_role_tag)>=0: if xml.tag.find(self.local_role_tag) >= 0:
object.manage_setLocalRoles(user,roles) object.manage_setLocalRoles(user, roles)
elif xml.nodeName.find(self.local_group_tag)>=0: elif xml.tag.find(self.local_group_tag) >= 0:
object.manage_setLocalGroupRoles(user,roles) object.manage_setLocalGroupRoles(user, roles)
return conflict_list
security.declareProtected(Permissions.ModifyPortalContent, 'addLocalPermissionNode') security.declareProtected(Permissions.ModifyPortalContent, 'addLocalPermissionNode')
def addLocalPermissionNode(self, object, xml): def addLocalPermissionNode(self, object, xml):
...@@ -1090,17 +995,17 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1090,17 +995,17 @@ class ERP5Conduit(XMLSyncUtilsMixin):
conflict_list = [] conflict_list = []
# We want to add a local role # We want to add a local role
#LOG('addLocalPermissionNode, xml',0,xml) #LOG('addLocalPermissionNode, xml',0,xml)
if len(xml.childNodes)>0: if len(xml.text):
roles = self.convertXmlValue(xml.childNodes[0].data,data_type='tokens') roles = self.convertXmlValue(xml, data_type='tokens')
roles = list(roles) # Needed for CPS, or we have a CPS error roles = list(roles) # Needed for CPS, or we have a CPS error
else: else:
roles = () roles = ()
permission = self.getAttribute(xml,'id') permission = self.getAttribute(xml, 'id')
#LOG('local_role: ',0,'permission: %s roles: %s' % (repr(permission),repr(roles))) #LOG('local_role: ',0,'permission: %s roles: %s' % (repr(permission),repr(roles)))
#user = roles[0] #user = roles[0]
#roles = roles[1:] #roles = roles[1:]
if xml.nodeName.find(self.local_permission_tag)>=0: if xml.tag.find(self.local_permission_tag) >= 0:
object.manage_setLocalPermissions(permission,roles) object.manage_setLocalPermissions(permission, roles)
return conflict_list return conflict_list
security.declareProtected(Permissions.ModifyPortalContent, 'editDocument') security.declareProtected(Permissions.ModifyPortalContent, 'editDocument')
...@@ -1123,11 +1028,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1123,11 +1028,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
return an xml string corresponding to the node return an xml string corresponding to the node
""" """
buf = cStringIO.StringIO() return etree.tostring(node, encoding='utf-8')
Print(node, stream=buf, encoding='utf-8')
xml_string = buf.getvalue()
buf.close()
return xml_string
def getGidFromObject(self, object): def getGidFromObject(self, object):
""" """
......
...@@ -69,8 +69,7 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -69,8 +69,7 @@ class VCardConduit(ERP5Conduit, SyncCode):
portal_type = 'Person' #the VCard can just use Person portal_type = 'Person' #the VCard can just use Person
if sub_object is None: if sub_object is None:
new_object, reset_local_roles, reset_workflow = ERP5Conduit.constructContent(self, object, object_id, new_object, reset_local_roles, reset_workflow = ERP5Conduit.constructContent(self, object, object_id, portal_type)
portal_type)
else: #if the object exist, it juste must be update else: #if the object exist, it juste must be update
new_object = sub_object new_object = sub_object
#LOG('addNode', 0, 'new_object:%s, sub_object:%s' % (new_object, sub_object)) #LOG('addNode', 0, 'new_object:%s, sub_object:%s' % (new_object, sub_object))
...@@ -80,7 +79,7 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -80,7 +79,7 @@ class VCardConduit(ERP5Conduit, SyncCode):
simulate=simulate, simulate=simulate,
**kw) **kw)
#in a first time, conflict are not used #in a first time, conflict are not used
return {'conflict_list':None, 'object': new_object} return {'conflict_list':[], 'object': new_object}
security.declareProtected(Permissions.ModifyPortalContent, 'deleteNode') security.declareProtected(Permissions.ModifyPortalContent, 'deleteNode')
def deleteNode(self, xml=None, object=None, object_id=None, force=None, def deleteNode(self, xml=None, object=None, object_id=None, force=None,
...@@ -89,12 +88,11 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -89,12 +88,11 @@ class VCardConduit(ERP5Conduit, SyncCode):
A node is deleted A node is deleted
""" """
#LOG('deleteNode :', 0, 'object:%s, object_id:%s' % (str(object), str(object_id))) #LOG('deleteNode :', 0, 'object:%s, object_id:%s' % (str(object), str(object_id)))
conflict_list = []
try: try:
object._delObject(object_id) object._delObject(object_id)
except (AttributeError, KeyError): except (AttributeError, KeyError):
LOG('VCardConduit',0,'deleteNode, Unable to delete: %s' % str(object_id)) LOG('VCardConduit',0,'deleteNode, Unable to delete: %s' % str(object_id))
return conflict_list return []
security.declareProtected(Permissions.ModifyPortalContent, 'updateNode') security.declareProtected(Permissions.ModifyPortalContent, 'updateNode')
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, def updateNode(self, xml=None, object=None, previous_xml=None, force=0,
...@@ -156,7 +154,7 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -156,7 +154,7 @@ class VCardConduit(ERP5Conduit, SyncCode):
property_value_list_well_incoded.append(property_value) property_value_list_well_incoded.append(property_value)
#elif ... put here the other encodings #elif ... put here the other encodings
else: else:
property_value_list_well_incoded=property_value_list property_value_list_well_incoded = property_value_list
return property_value_list_well_incoded return property_value_list_well_incoded
...@@ -175,7 +173,7 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -175,7 +173,7 @@ class VCardConduit(ERP5Conduit, SyncCode):
for vcard_line in vcard_list: for vcard_line in vcard_list:
if ':' in vcard_line: if ':' in vcard_line:
property, property_value = vcard_line.split(':') property, property_value = vcard_line.split(':')
property_value_list=property_value.split(';') property_value_list = property_value.split(';')
property_parameters_list = [] property_parameters_list = []
property_name = '' property_name = ''
if ';' in property: if ';' in property:
...@@ -202,21 +200,21 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -202,21 +200,21 @@ class VCardConduit(ERP5Conduit, SyncCode):
else: else:
property_name=property property_name=property
if type(property_name) is type(u'a'): if isinstance(property_name, unicode):
property_name = property_name.encode('utf-8') property_name = property_name.encode('utf-8')
tmp=[] tmp = []
for property_value in property_value_list: for property_value in property_value_list:
if type(property_value) is type(u'a'): if isinstance(property_value, unicode):
property_value = property_value.encode('utf-8') property_value = property_value.encode('utf-8')
tmp.append(property_value) tmp.append(property_value)
property_value_list=tmp property_value_list = tmp
if property_name in convert_dict.keys(): if property_name in convert_dict.keys():
if property_name == 'N' and len(property_value_list) > 1: if property_name == 'N' and len(property_value_list) > 1:
edit_dict[convert_dict['N']]=property_value_list[0] edit_dict[convert_dict['N']] = property_value_list[0]
edit_dict[convert_dict['FN']]=property_value_list[1] edit_dict[convert_dict['FN']] = property_value_list[1]
else: else:
edit_dict[convert_dict[property_name]]=property_value_list[0] edit_dict[convert_dict[property_name]] = property_value_list[0]
#LOG('edit_dict =',0,edit_dict) #LOG('edit_dict =',0,edit_dict)
return edit_dict return edit_dict
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
import smtplib # to send emails import smtplib # to send emails
from Publication import Publication,Subscriber from Publication import Publication,Subscriber
from Subscription import Signature from Subscription import Signature
from XMLSyncUtils import Parse
from XMLSyncUtils import XMLSyncUtils from XMLSyncUtils import XMLSyncUtils
from Conduit.ERP5Conduit import ERP5Conduit from Conduit.ERP5Conduit import ERP5Conduit
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
...@@ -54,9 +53,9 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -54,9 +53,9 @@ class PublicationSynchronization(XMLSyncUtils):
""" """
LOG('PubSyncInit', INFO, 'Starting... publication: %s' % (publication.getPath())) LOG('PubSyncInit', INFO, 'Starting... publication: %s' % (publication.getPath()))
#the session id is set at the same value of those of the client #the session id is set at the same value of those of the client
subscriber.setSessionId(self.getSessionId(xml_client)) subscriber.setSessionId(self.getSessionIdFromXml(xml_client))
#same for the message id #same for the message id
subscriber.setMessageId(self.getMessageId(xml_client)) subscriber.setMessageId(self.getMessageIdFromXml(xml_client))
#at the begining of the synchronization the subscriber is not authenticated #at the begining of the synchronization the subscriber is not authenticated
subscriber.setAuthenticated(False) subscriber.setAuthenticated(False)
#the last_message_id is 1 because the message that #the last_message_id is 1 because the message that
...@@ -137,7 +136,7 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -137,7 +136,7 @@ class PublicationSynchronization(XMLSyncUtils):
if authentication_type == publication.getAuthenticationType(): if authentication_type == publication.getAuthenticationType():
authentication_format = publication.getAuthenticationFormat() authentication_format = publication.getAuthenticationFormat()
decoded = subscriber.decode(authentication_format, data) decoded = subscriber.decode(authentication_format, data)
if decoded not in ('', None) and ':' in decoded: if decoded and ':' in decoded:
(login, password) = decoded.split(':') (login, password) = decoded.split(':')
uf = self.getPortalObject().acl_users uf = self.getPortalObject().acl_users
for plugin_name, plugin in uf._getOb('plugins').listPlugins( for plugin_name, plugin in uf._getOb('plugins').listPlugins(
......
...@@ -492,10 +492,6 @@ class Signature(Folder, SyncCode): ...@@ -492,10 +492,6 @@ class Signature(Folder, SyncCode):
Set the partial string we will have to Set the partial string we will have to
deliver in the future deliver in the future
""" """
if type(xml) is type(u'a'):
xml = xml.encode('utf-8')
if xml is not None:
xml = xml.replace('@-@@-@','--') # need to put back '--'
self.partial_xml = xml self.partial_xml = xml
def getPartialXML(self): def getPartialXML(self):
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
import smtplib # to send emails import smtplib # to send emails
from Subscription import Subscription,Signature from Subscription import Subscription,Signature
from XMLSyncUtils import XMLSyncUtils, Parse from XMLSyncUtils import XMLSyncUtils
import commands import commands
from Conduit.ERP5Conduit import ERP5Conduit from Conduit.ERP5Conduit import ERP5Conduit
from AccessControl import getSecurityManager from AccessControl import getSecurityManager
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
from Products.ERP5Type.Accessor.TypeDefinition import list_types from Products.ERP5Type.Accessor.TypeDefinition import list_types
from Globals import Persistent from Globals import Persistent
import re
class SyncCode(Persistent): class SyncCode(Persistent):
""" """
...@@ -87,6 +88,7 @@ class SyncCode(Persistent): ...@@ -87,6 +88,7 @@ class SyncCode(Persistent):
tuple(XUPDATE_UPDATE) + tuple(XUPDATE_DEL) tuple(XUPDATE_UPDATE) + tuple(XUPDATE_DEL)
text_type_list = ('text','string') text_type_list = ('text','string')
list_type_list = list_types list_type_list = list_types
none_type = 'None'
force_conflict_list = ('layout_and_schema','ModificationDate') force_conflict_list = ('layout_and_schema','ModificationDate')
binary_type_list = ('image','file','document','pickle') binary_type_list = ('image','file','document','pickle')
date_type_list = ('date',) date_type_list = ('date',)
...@@ -105,18 +107,12 @@ class SyncCode(Persistent): ...@@ -105,18 +107,12 @@ class SyncCode(Persistent):
ADDABLE_PROPERTY = local_role_list + (history_tag,) + local_permission_list ADDABLE_PROPERTY = local_role_list + (history_tag,) + local_permission_list
NOT_EDITABLE_PROPERTY = ('id','object','uid','xupdate:attribute') \ NOT_EDITABLE_PROPERTY = ('id','object','uid','xupdate:attribute') \
+ XUPDATE_EL + ADDABLE_PROPERTY + XUPDATE_EL + ADDABLE_PROPERTY
sub_object_exp = "/object\[@id='.*'\]/" sub_object_exp = re.compile("/object\[@id='.*'\]/")
object_exp = "/object\[@id='.*'\]" object_exp = re.compile("/object\[@id='.*'\]")
sub_sub_object_exp = "/object\[@id='.*'\]/object\[@id='.*'\]/" attribute_type_exp = re.compile("^.*attribute::type$")
history_exp = "/%s\[@id='.*'\]" % history_tag sub_sub_object_exp = re.compile("/object\[@id='.*'\]/object\[@id='.*'\]/")
local_role_exp = "/%s\[@id='.*'\]" % local_role_tag history_exp = re.compile("/%s\[@id='.*'\]" % history_tag)
local_group_exp = "/%s\[@id='.*'\]" % local_group_tag bad_history_exp = re.compile("/%s\[@id='.*'\]/" % history_tag)
bad_local_role_exp = "/%s\[@id='.*'\]/" % local_role_tag
bad_local_group_exp = "/%s\[@id='.*'\]/" % local_group_tag
bad_history_exp = "/%s\[@id='.*'\]/" % history_tag
local_role_and_group_list = (local_group_exp,local_role_exp)
bad_local_role_and_group_list = (bad_local_group_exp,bad_local_role_exp)
#media types : #media types :
......
...@@ -40,7 +40,6 @@ from Products.ERP5SyncML import Conduit ...@@ -40,7 +40,6 @@ from Products.ERP5SyncML import Conduit
from Publication import Publication, Subscriber from Publication import Publication, Subscriber
from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2 from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2
from Subscription import Subscription from Subscription import Subscription
from XMLSyncUtils import Parse
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from PublicationSynchronization import PublicationSynchronization from PublicationSynchronization import PublicationSynchronization
from SubscriptionSynchronization import SubscriptionSynchronization from SubscriptionSynchronization import SubscriptionSynchronization
...@@ -490,7 +489,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -490,7 +489,7 @@ class SynchronizationTool( SubscriptionSynchronization,
for conflict in conflict_list: for conflict in conflict_list:
if conflict.getObjectPath() == path: if conflict.getObjectPath() == path:
#LOG('getSynchronizationState', DEBUG, 'found a conflict: %s' % str(conflict)) #LOG('getSynchronizationState', DEBUG, 'found a conflict: %s' % str(conflict))
state_list += [[conflict.getSubscriber(),self.CONFLICT]] state_list.append([conflict.getSubscriber(), self.CONFLICT])
for domain in self.getSynchronizationList(): for domain in self.getSynchronizationList():
destination = domain.getDestinationPath() destination = domain.getDestinationPath()
#LOG('getSynchronizationState', TRACE, 'destination: %s' % str(destination)) #LOG('getSynchronizationState', TRACE, 'destination: %s' % str(destination))
...@@ -499,7 +498,6 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -499,7 +498,6 @@ class SynchronizationTool( SubscriptionSynchronization,
if j_path.find(destination)==0: if j_path.find(destination)==0:
o_id = j_path[len(destination)+1:].split('/')[0] o_id = j_path[len(destination)+1:].split('/')[0]
#LOG('getSynchronizationState', TRACE, 'o_id: %s' % o_id) #LOG('getSynchronizationState', TRACE, 'o_id: %s' % o_id)
subscriber_list = []
if domain.domain_type==self.PUB: if domain.domain_type==self.PUB:
subscriber_list = domain.getSubscriberList() subscriber_list = domain.getSubscriberList()
else: else:
...@@ -512,13 +510,13 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -512,13 +510,13 @@ class SynchronizationTool( SubscriptionSynchronization,
state = signature.getStatus() state = signature.getStatus()
#LOG('getSynchronizationState:', TRACE, 'sub.dest :%s, state: %s' % \ #LOG('getSynchronizationState:', TRACE, 'sub.dest :%s, state: %s' % \
#(subscriber.getSubscriptionUrl(),str(state))) #(subscriber.getSubscriptionUrl(),str(state)))
found = None found = False
# Make sure there is not already a conflict giving the state # Make sure there is not already a conflict giving the state
for state_item in state_list: for state_item in state_list:
if state_item[0]==subscriber: if state_item[0] == subscriber:
found = 1 found = True
if found is None: if not found:
state_list += [[subscriber,state]] state_list.append([subscriber, state])
return state_list return state_list
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
......
...@@ -30,27 +30,18 @@ import smtplib ...@@ -30,27 +30,18 @@ import smtplib
from Products.ERP5SyncML.SyncCode import SyncCode from Products.ERP5SyncML.SyncCode import SyncCode
from Products.ERP5SyncML.Subscription import Signature from Products.ERP5SyncML.Subscription import Signature
from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import newSecurityManager
from StringIO import StringIO
from ERP5Diff import ERP5Diff from ERP5Diff import ERP5Diff
from zLOG import LOG, INFO from zLOG import LOG, INFO
try: from lxml import etree
from Ft.Xml import Parse from lxml.etree import Element
except ImportError: from lxml.builder import E
LOG('XMLSyncUtils', INFO, "Can't import Parse") from xml.dom import minidom
class Parse:
def __init__(self, *args, **kw):
raise ImportError, '4Suite-XML is not installed'
try: try:
from base64 import b16encode, b16decode from base64 import b16encode, b16decode
except ImportError: except ImportError:
from base64 import encodestring as b16encode, decodestring as b16decode from base64 import encodestring as b16encode, decodestring as b16decode
try:
from Ft.Xml.Domlette import PrettyPrint
except ImportError:
from xml.dom.ext import PrettyPrint
from xml.dom import minidom
class XMLSyncUtilsMixin(SyncCode): class XMLSyncUtilsMixin(SyncCode):
...@@ -61,34 +52,30 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -61,34 +52,30 @@ class XMLSyncUtilsMixin(SyncCode):
Since the Header is always almost the same, this is the Since the Header is always almost the same, this is the
way to set one quickly. way to set one quickly.
""" """
xml_list = [] if source:
xml = xml_list.append if source_name:
xml(' <SyncHdr>\n') source_name = source_name.decode('utf-8')
xml(' <VerDTD>1.1</VerDTD>\n') node_to_append = E.Source(E.LocURI(source), E.LocName(source_name or ''))
xml(' <VerProto>SyncML/1.1</VerProto>\n') else:
xml(' <SessionID>%s</SessionID>\n' % session_id) if target_name:
xml(' <MsgID>%s</MsgID>\n' % msg_id) target_name = target_name.decode('utf-8')
xml(' <Target>\n') node_to_append = E.Target(E.LocURI(target), E.LocName(target_name or ''))
xml(' <LocURI>%s</LocURI>\n' % target)
if target_name not in (None, ''): xml = (E.SyncHdr(
xml(' <LocName>%s</LocName>\n' %target_name) E.VerDTD('1.1'),
xml(' </Target>\n') E.VerProto('SyncML/1.1'),
xml(' <Source>\n') E.SessionID('%s' % session_id),
xml(' <LocURI>%s</LocURI>\n' % source) E.MsgID('%s' % msg_id),
if source_name not in (None, ''): node_to_append
xml(' <LocName>%s</LocName>\n' % source_name) ))
xml(' </Source>\n') if dataCred:
if dataCred not in (None, ''): xml.append(E.Cred(
xml(' <Cred>\n') E.Meta(E.Format(authentication_format, xmlns='syncml:metinf'),
xml(' <Meta>\n') E.Type(authentication_type, xmlns='syncml:metinf'),),
xml(" <Format xmlns='syncml:metinf'>%s</Format>\n" % authentication_format) E.Data(dataCred)
xml(" <Type xmlns='syncml:metinf'>%s</Type>\n" % authentication_type) ))
xml(' </Meta>\n') return etree.tostring(xml, encoding='utf-8',
xml(' <Data>%s</Data>\n' % dataCred) xml_declaration=False, pretty_print=False)
xml(' </Cred>\n')
xml(' </SyncHdr>\n')
xml_a = ''.join(xml_list)
return xml_a
def SyncMLAlert(self, cmd_id, sync_code, target, source, last_anchor, def SyncMLAlert(self, cmd_id, sync_code, target, source, last_anchor,
next_anchor): next_anchor):
...@@ -96,28 +83,26 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -96,28 +83,26 @@ class XMLSyncUtilsMixin(SyncCode):
Since the Alert section is always almost the same, this is the Since the Alert section is always almost the same, this is the
way to set one quickly. way to set one quickly.
""" """
xml_list = [] xml = (E.Alert(
xml = xml_list.append E.CmdID('%s' % cmd_id),
xml(' <Alert>\n') E.Data('%s' % sync_code),
xml(' <CmdID>%s</CmdID>\n' % cmd_id) E.Item(
xml(' <Data>%s</Data>\n' % sync_code) E.Target(
xml(' <Item>\n') E.LocURI(target)
xml(' <Target>\n') ),
xml(' <LocURI>%s</LocURI>\n' % target) E.Source(
xml(' </Target>\n') E.LocURI(source)
xml(' <Source>\n') ),
xml(' <LocURI>%s</LocURI>\n' % source) E.Meta(
xml(' </Source>\n') E.Anchor(
xml(' <Meta>\n') E.Last(last_anchor),
xml(' <Anchor>\n') E.Next(next_anchor)
xml(' <Last>%s</Last>\n' % last_anchor) )
xml(' <Next>%s</Next>\n' % next_anchor) )
xml(' </Anchor>\n') )
xml(' </Meta>\n') ))
xml(' </Item>\n') return etree.tostring(xml, encoding='utf-8',
xml(' </Alert>\n') xml_declaration=False, pretty_print=False)
xml_a = ''.join(xml_list)
return xml_a
def SyncMLStatus(self, remote_xml, data_code, cmd_id, next_anchor, def SyncMLStatus(self, remote_xml, data_code, cmd_id, next_anchor,
subscription=None): subscription=None):
...@@ -127,56 +112,50 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -127,56 +112,50 @@ class XMLSyncUtilsMixin(SyncCode):
""" """
#list of element in the SyncBody bloc #list of element in the SyncBody bloc
syncbody_element_list = remote_xml.xpath('//SyncBody/*') sub_syncbody_element_list = remote_xml.xpath('/SyncML/SyncBody/*')
message_id = self.getMessageId(remote_xml) message_id = self.getMessageIdFromXml(remote_xml)
xml_list = [] xml_list = []
xml = xml_list.append xml = xml_list.append
if data_code != self.AUTH_REQUIRED:#because for AUTH_REQUIRED, SyncMLChal is #called if data_code != self.AUTH_REQUIRED:#because for AUTH_REQUIRED, SyncMLChal is #called
# status for SyncHdr # status for SyncHdr
message_id = self.getMessageId(remote_xml)
xml(' <Status>\n') xml(' <Status>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id) xml(' <CmdID>%s</CmdID>\n' % cmd_id)
cmd_id += 1 cmd_id += 1
xml(' <MsgRef>%s</MsgRef>\n' % self.getMessageId(remote_xml)) xml(' <MsgRef>%s</MsgRef>\n' % message_id)
xml(' <CmdRef>0</CmdRef>\n') #to make reference to the SyncHdr, it's 0 xml(' <CmdRef>0</CmdRef>\n') #to make reference to the SyncHdr, it's 0
xml(' <Cmd>SyncHdr</Cmd>\n') xml(' <Cmd>SyncHdr</Cmd>\n')
xml(' <TargetRef>%s</TargetRef>\n' \ target_uri = remote_xml.xpath('string(/SyncML/SyncHdr/Target/LocURI)')
% remote_xml.xpath('string(//SyncHdr/Target/LocURI)').encode('utf-8')) xml(' <TargetRef>%s</TargetRef>\n' % (target_uri))
xml(' <SourceRef>%s</SourceRef>\n' \ source_uri = remote_xml.xpath('string(/SyncML/SyncHdr/Source/LocURI)')
% remote_xml.xpath('string(//SyncHdr/Source/LocURI)').encode('utf-8')) xml(' <SourceRef>%s</SourceRef>\n' % (source_uri))
if isinstance(data_code, int): xml(' <Data>%s</Data>\n' % (data_code))
data_code = str(data_code)
xml(' <Data>%s</Data>\n' % data_code)
xml(' </Status>\n') xml(' </Status>\n')
#add the status bloc corresponding to the receive command #add the status bloc corresponding to the receive command
for syncbody_element in syncbody_element_list: for sub_syncbody_element in sub_syncbody_element_list:
#LOG('SyncMLStatus : ', DEBUG, "command:%s, subscription:%s" % (str(syncbody_element.nodeName), subscription)) #LOG('SyncMLStatus : ', DEBUG, "command:%s, subscription:%s" % (str(syncbody_element.tag), subscription))
if str(syncbody_element.nodeName) not in ('Status', 'Final', 'Get'): if sub_syncbody_element.tag not in ('Status', 'Final', 'Get'):
xml(' <Status>\n') xml(' <Status>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id) xml(' <CmdID>%s</CmdID>\n' % cmd_id)
cmd_id += 1 cmd_id += 1
xml(' <MsgRef>%s</MsgRef>\n' % message_id) xml(' <MsgRef>%s</MsgRef>\n' % message_id)
xml(' <CmdRef>%s</CmdRef>\n' \ xml(' <CmdRef>%s</CmdRef>\n' \
% syncbody_element.xpath('string(.//CmdID)').encode('utf-8')) % sub_syncbody_element.xpath('string(.//CmdID)'))
xml(' <Cmd>%s</Cmd>\n' % syncbody_element.nodeName.encode('utf-8')) xml(' <Cmd>%s</Cmd>\n' % sub_syncbody_element.tag)
target_ref = syncbody_element.xpath('string(.//Target/LocURI)').encode('utf-8') target_ref = sub_syncbody_element.xpath('string(.//Target/LocURI)')
if target_ref not in (None, ''): if target_ref:
xml(' <TargetRef>%s</TargetRef>\n' % target_ref ) xml(' <TargetRef>%s</TargetRef>\n' % target_ref )
source_ref = syncbody_element.xpath('string(.//Source/LocURI)').encode('utf-8') source_ref = sub_syncbody_element.xpath('string(.//Source/LocURI)')
if source_ref not in (None, ''): if source_ref:
xml(' <SourceRef>%s</SourceRef>\n' % source_ref ) xml(' <SourceRef>%s</SourceRef>\n' % source_ref )
if syncbody_element.nodeName.encode('utf-8') == 'Add': if sub_syncbody_element.tag == 'Add':
xml(' <Data>%s</Data>\n' % str(self.ITEM_ADDED)) xml(' <Data>%s</Data>\n' % self.ITEM_ADDED)
elif syncbody_element.nodeName.encode('utf-8') == 'Alert' and \ elif sub_syncbody_element.tag == 'Alert' and \
syncbody_element.xpath('string(.//Data)').encode('utf-8') == \ sub_syncbody_element.xpath('string(.//Data)') == \
str(self.SLOW_SYNC): str(self.SLOW_SYNC):
xml(' <Data>%s</Data>\n' % str(self.REFRESH_REQUIRED)) xml(' <Data>%s</Data>\n' % self.REFRESH_REQUIRED)
else: elif sub_syncbody_element.tag == 'Alert':
xml(' <Data>%s</Data>\n' % str(self.SUCCESS))
if str(syncbody_element.nodeName) == 'Alert':
xml(' <Item>\n') xml(' <Item>\n')
xml(' <Data>\n') xml(' <Data>\n')
xml(' <Anchor>\n') xml(' <Anchor>\n')
...@@ -184,16 +163,18 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -184,16 +163,18 @@ class XMLSyncUtilsMixin(SyncCode):
xml(' </Anchor>\n') xml(' </Anchor>\n')
xml(' </Data>\n') xml(' </Data>\n')
xml(' </Item>\n') xml(' </Item>\n')
else:
xml(' <Data>%s</Data>\n' % self.SUCCESS)
xml(' </Status>\n') xml(' </Status>\n')
if str(syncbody_element.nodeName) == 'Get' and subscription != None: if sub_syncbody_element.tag == 'Get' and subscription is not None:
cmd_ref = syncbody_element.xpath('string(.//CmdID)').encode('utf-8') cmd_ref = '%s' % sub_syncbody_element.xpath('string(.//CmdID)')
syncml_result = self.SyncMLPut( syncml_result = self.SyncMLPut(
cmd_id, cmd_id,
subscription, subscription,
markup='Results', markup='Results',
cmd_ref=cmd_ref, cmd_ref=cmd_ref,
message_id=self.getMessageId(remote_xml)) message_id=message_id)
xml(syncml_result) xml(syncml_result)
cmd_id += 1 cmd_id += 1
xml_a = ''.join(xml_list) xml_a = ''.join(xml_list)
...@@ -207,57 +188,51 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -207,57 +188,51 @@ class XMLSyncUtilsMixin(SyncCode):
synchronized synchronized
""" """
if remote_xml is not None: if remote_xml is not None:
msg_ref=remote_xml.xpath("string(/SyncML/SyncHdr/MsgID)").encode('utf-8') msg_ref = '%s' % remote_xml.xpath("string(/SyncML/SyncHdr/MsgID)")
cmd_ref=remote_xml.xpath("string(.//CmdID)").encode('utf-8') cmd_ref = '%s' % remote_xml.xpath("string(.//CmdID)")
target_ref=remote_xml.xpath("string(.//Target/LocURI)").encode('utf-8') target_ref = '%s' % remote_xml.xpath("string(.//Target/LocURI)")
source_ref=remote_xml.xpath("string(.//Source/LocURI)").encode('utf-8') source_ref = '%s' % remote_xml.xpath("string(.//Source/LocURI)")
xml = (E.Status())
xml_list = [] if cmd_id:
xml = xml_list.append xml.append(E.CmdID('%s' % cmd_id))
xml(' <Status>\n') if msg_ref:
#here there is a lot of test to keep compatibility with older call xml.append(E.MsgRef(msg_ref))
if cmd_id not in (None,'') : if cmd_ref:
xml(' <CmdID>%s</CmdID>\n' % cmd_id) xml.append(E.CmdRef(cmd_ref))
if msg_ref not in (None,''): if cmd:
xml(' <MsgRef>%s</MsgRef>\n' % msg_ref) xml.append(E.Cmd(cmd))
if cmd_ref not in (None,''): if target_ref:
xml(' <CmdRef>%s</CmdRef>\n' %cmd_ref) xml.append(E.TargetRef(target_ref))
if cmd not in (None,''): if source_ref:
xml(' <Cmd>%s</Cmd>\n' % cmd) xml.append(E.SourceRef(source_ref))
if target_ref not in (None,''): if sync_code:
xml(' <TargetRef>%s</TargetRef>\n' % target_ref) xml.append(E.Data('%s'% sync_code))
if source_ref not in (None,''):
xml(' <SourceRef>%s</SourceRef>\n' % source_ref) return etree.tostring(xml, encoding='utf-8',
if sync_code not in (None,''): xml_declaration=False, pretty_print=False)
xml(' <Data>%s</Data>\n' % sync_code)
xml(' </Status>\n')
xml_a = ''.join(xml_list)
return xml_a
def SyncMLChal(self, cmd_id, cmd, target_ref, source_ref, auth_format, def SyncMLChal(self, cmd_id, cmd, target_ref, source_ref, auth_format,
auth_type, data_code): auth_type, data_code):
""" """
This is used in order to ask crendentials This is used in order to ask crendentials
""" """
xml_list = [] xml = (E.Status(
xml = xml_list.append E.CmdID('%s' % cmd_id),
xml(' <Status>\n') E.MsgRef('1'),
xml(' <CmdID>%s</CmdID>\n' % cmd_id) E.CmdRef('0'),
xml(' <MsgRef>1</MsgRef>\n') E.Cmd(cmd),
xml(' <CmdRef>0</CmdRef>\n') E.TargetRef(target_ref),
xml(' <Cmd>%s</Cmd>\n' % cmd) E.SourceRef(source_ref),
xml(' <TargetRef>%s</TargetRef>\n' % target_ref) E.Chal(
xml(' <SourceRef>%s</SourceRef>\n' % source_ref) E.Meta(
xml(' <Chal>\n') E.Format(auth_format, xmlns='syncml:metinf'),
xml(' <Meta>\n') E.Type(auth_type, xmlns='syncml:metinf')
xml(" <Format xmlns='syncml:metinf'>%s</Format>\n" % auth_format) )
xml(" <Type xmlns='syncml:metinf'>%s</Type>\n" % auth_type) ),
xml(' </Meta>\n') E.Data('%s' % data_code)
xml(' </Chal>\n') ))
xml(' <Data>%s</Data>\n' % str(data_code)) return etree.tostring(xml, encoding='utf-8',
xml(' </Status>\n') xml_declaration=False, pretty_print=False)
xml_a = ''.join(xml_list)
return xml_a
def SyncMLPut(self, cmd_id, subscription, markup='Put', cmd_ref=None, def SyncMLPut(self, cmd_id, subscription, markup='Put', cmd_ref=None,
message_id=None): message_id=None):
...@@ -269,16 +244,16 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -269,16 +244,16 @@ class XMLSyncUtilsMixin(SyncCode):
conduit_name = subscription.getConduit() conduit_name = subscription.getConduit()
conduit = self.getConduitByName(conduit_name) conduit = self.getConduitByName(conduit_name)
#if the conduit support the SyncMLPut : #if the conduit support the SyncMLPut :
if hasattr(conduit, 'getCapabilitiesCTTypeList') and \ if getattr(conduit, 'getCapabilitiesCTTypeList', None) is not None and \
hasattr(conduit, 'getCapabilitiesVerCTList') and \ getattr(conduit, 'getCapabilitiesVerCTList', None) is not None and \
hasattr(conduit, 'getPreferedCapabilitieVerCT'): getattr(conduit, 'getPreferedCapabilitieVerCT', None) is not None:
xml_list = [] xml_list = []
xml = xml_list.append xml = xml_list.append
xml(' <%s>\n' % markup) xml(' <%s>\n' % markup)
xml(' <CmdID>%s</CmdID>\n' % cmd_id) xml(' <CmdID>%s</CmdID>\n' % cmd_id)
if message_id not in (None, ''): if message_id:
xml(' <MsgRef>%s</MsgRef>\n' % message_id) xml(' <MsgRef>%s</MsgRef>\n' % message_id)
if cmd_ref not in (None, '') : if cmd_ref:
xml(' <CmdRef>%s</CmdRef>\n' % cmd_ref) xml(' <CmdRef>%s</CmdRef>\n' % cmd_ref)
xml(' <Meta>\n') xml(' <Meta>\n')
xml(' <Type>application/vnd.syncml-devinf+xml</Type>\n'); xml(' <Type>application/vnd.syncml-devinf+xml</Type>\n');
...@@ -365,84 +340,80 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -365,84 +340,80 @@ class XMLSyncUtilsMixin(SyncCode):
""" """
Add an object with the SyncML protocol Add an object with the SyncML protocol
""" """
xml_list = [] data_node = Element('Data')
xml = xml_list.append if media_type == self.MEDIA_TYPE['TEXT_XML'] and isinstance(xml_string, str):
xml(' <Add>\n') data_node.append(etree.XML(xml_string))
xml(' <CmdID>%s</CmdID>\n' % cmd_id) elif media_type == self.MEDIA_TYPE['TEXT_XML'] and \
xml(' <Meta>\n') not isinstance(xml_string, str):
xml(' <Type>%s</Type>\n' % media_type) #xml_string could be Partial element if partial XML
xml(' </Meta>\n') data_node.append(xml_string)
xml(' <Item>\n')
xml(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % gid)
xml(' </Source>\n')
if media_type == self.MEDIA_TYPE['TEXT_XML']:
xml(' <Data>')
xml(xml_string)
xml('</Data>\n')
else: else:
xml(' <Data><![CDATA[') cdata = etree.CDATA(xml_string.decode('utf-8'))
xml(xml_string) data_node.text = cdata
xml('\n]]></Data>\n') xml = (E.Add(
if more_data == 1: E.CmdID('%s' % cmd_id),
xml(' <MoreData/>\n') E.Meta(
xml(' </Item>\n') E.Type(media_type)
xml(' </Add>\n') ),
xml_a = ''.join(xml_list) E.Item(
return xml_a E.Source(
E.LocURI(gid)
),
data_node
)
))
if more_data:
item_node = xml.find('Item')
item_node.append(Element('MoreData'))
return etree.tostring(xml, encoding='utf-8',
xml_declaration=False, pretty_print=False)
def deleteXMLObject(self, cmd_id=0, object_gid=None, rid=None, xml_object=''): def deleteXMLObject(self, cmd_id=0, object_gid=None, rid=None, xml_object=''):
""" """
Delete an object with the SyncML protocol Delete an object with the SyncML protocol
""" """
xml_list = [] if rid:
xml = xml_list.append elem_to_append = E.Target(E.LocURI('%s' % rid))
xml(' <Delete>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id)
xml(' <Item>\n')
if rid not in (None, ''):
xml(' <Target>\n')
xml(' <LocURI>%s</LocURI>\n' % rid)
xml(' </Target>\n')
else: else:
xml(' <Source>\n') elem_to_append = E.Source(E.LocURI('%s' % object_gid))
xml(' <LocURI>%s</LocURI>\n' % object_gid) xml = (E.Delete(
xml(' </Source>\n') E.CmdID('%s' % cmd_id),
xml(' </Item>\n') E.Item(
xml(' </Delete>\n') elem_to_append
xml_a = ''.join(xml_list) )
return xml_a ))
return etree.tostring(xml, encoding='utf-8',
xml_declaration=False, pretty_print=False)
def replaceXMLObject(self, cmd_id=0, object=None, xml_string=None, def replaceXMLObject(self, cmd_id=0, object=None, xml_string=None,
more_data=0, gid=None, rid=None, media_type=None): more_data=0, gid=None, rid=None, media_type=None):
""" """
Replace an object with the SyncML protocol Replace an object with the SyncML protocol
""" """
xml_list = [] if rid:
xml = xml_list.append elem_to_append = E.Target(E.LocURI('%s' % rid))
xml(' <Replace>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id)
xml(' <Meta>\n')
xml(' <Type>%s</Type>\n' % media_type)
xml(' </Meta>\n')
xml(' <Item>\n')
if rid is not None:
xml(' <Target>\n')
xml(' <LocURI>%s</LocURI>\n' % str(rid))
xml(' </Target>\n')
else: else:
xml(' <Source>\n') elem_to_append = E.Source(E.LocURI('%s' % gid))
xml(' <LocURI>%s</LocURI>\n' % str(gid)) data_node = Element('Data')
xml(' </Source>\n') if not isinstance(xml_string, (str, unicode)):
xml(' <Data>') data_node.append(xml_string)
xml(xml_string) else:
xml(' </Data>\n') data_node.append(etree.XML(xml_string))
if more_data == 1: xml = (E.Replace(
xml(' <MoreData/>\n') E.CmdID('%s' % cmd_id),
xml(' </Item>\n') E.Meta(
xml(' </Replace>\n') E.Type(media_type)
xml_a = ''.join(xml_list) ),
return xml_a E.Item(
elem_to_append,
data_node
)
))
if more_data:
item_node = xml.find('Item')
item_node.append(Element('MoreData'))
return etree.tostring(xml, encoding='utf-8',
xml_declaration=False, pretty_print=False)
def getXupdateObject(self, object_xml=None, old_xml=None): def getXupdateObject(self, object_xml=None, old_xml=None):
""" """
...@@ -467,93 +438,68 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -467,93 +438,68 @@ class XMLSyncUtilsMixin(SyncCode):
xupdate = xupdate[xupdate.find('<xupdate:modifications'):] xupdate = xupdate[xupdate.find('<xupdate:modifications'):]
return xupdate return xupdate
def getSessionId(self, xml): def getSessionIdFromXml(self, xml):
""" """
We will retrieve the session id of the message We will retrieve the session id of the message
""" """
session_id = 0 return int(xml.xpath('string(/SyncML/SyncHdr/SessionID)'))
session_id = xml.xpath('string(/SyncML/SyncHdr/SessionID)')
session_id = int(session_id)
return session_id
def getMessageId(self, xml): def getMessageIdFromXml(self, xml):
""" """
We will retrieve the message id of the message We will retrieve the message id of the message
""" """
message_id = 0 return int(xml.xpath('string(/SyncML/SyncHdr/MsgID)'))
message_id = xml.xpath('string(/SyncML/SyncHdr/MsgID)')
message_id = int(message_id)
return message_id
def getTarget(self, xml): def getTarget(self, xml):
""" """
return the target in the SyncHdr section return the target in the SyncHdr section
""" """
url = '' return '%s' % xml.xpath('string(/SyncML/SyncHdr/Target/LocURI)')
url = xml.xpath('string(/SyncML/SyncHdr/Target/LocURI)')
url = url.encode('utf-8')
return url
def getAlertLastAnchor(self, xml_stream): def getAlertLastAnchor(self, xml_stream):
""" """
Return the value of the last anchor, in the Return the value of the last anchor, in the
alert section of the xml_stream alert section of the xml_stream
""" """
last_anchor = xml_stream.xpath('string(.//Alert/Item/Meta/Anchor/Last)') return '%s' % xml_stream.xpath('string(.//Alert/Item/Meta/Anchor/Last)')
last_anchor = last_anchor.encode('utf-8')
return last_anchor
def getAlertNextAnchor(self, xml_stream): def getAlertNextAnchor(self, xml_stream):
""" """
Return the value of the next anchor, in the Return the value of the next anchor, in the
alert section of the xml_stream alert section of the xml_stream
""" """
next_anchor = xml_stream.xpath('string(.//Alert/Item/Meta/Anchor/Next)') return '%s' % xml_stream.xpath('string(.//Alert/Item/Meta/Anchor/Next)')
next_anchor = next_anchor.encode('utf-8')
return next_anchor
def getSourceURI(self, xml): def getSourceURI(self, xml):
""" """
return the source uri of the data base return the source uri of the data base
""" """
source_uri = xml.xpath('string(//SyncBody/Alert/Item/Source/LocURI)') return '%s' % xml.xpath('string(//SyncBody/Alert/Item/Source/LocURI)')
if isinstance(source_uri, unicode):
source_uri = source_uri.encode('utf-8')
return source_uri
def getTargetURI(self, xml): def getTargetURI(self, xml):
""" """
return the target uri of the data base return the target uri of the data base
""" """
target_uri = xml.xpath('string(//SyncBody/Alert/Item/Target/LocURI)') return '%s' % xml.xpath('string(//SyncBody/Alert/Item/Target/LocURI)')
if isinstance(target_uri, unicode):
target_uri = target_uri.encode('utf-8')
return target_uri
def getSubscriptionUrlFromXML(self, xml): def getSubscriptionUrlFromXML(self, xml):
""" """
return the source URI of the syncml header return the source URI of the syncml header
""" """
subscription_url = xml.xpath('string(//SyncHdr/Source/LocURI)') return '%s' % xml.xpath('string(//SyncHdr/Source/LocURI)')
if isinstance(subscription_url, unicode):
subscription_url = subscription_url.encode('utf-8')
return subscription_url
def getStatusTarget(self, xml): def getStatusTarget(self, xml):
""" """
Return the value of the alert code inside the xml_stream Return the value of the alert code inside the xml_stream
""" """
status = xml.xpath('string(TargetRef)') return '%s' % xml.xpath('string(TargetRef)')
if isinstance(status, unicode):
status = status.encode('utf-8')
return status
def getStatusCode(self, xml): def getStatusCode(self, xml):
""" """
Return the value of the alert code inside the xml_stream Return the value of the alert code inside the xml_stream
""" """
status_code = xml.xpath('string(Data)') status_code = '%s' % xml.xpath('string(Data)')
if status_code not in ('', None, []): if status_code:
return int(status_code) return int(status_code)
return None return None
...@@ -562,81 +508,64 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -562,81 +508,64 @@ class XMLSyncUtilsMixin(SyncCode):
Return the value of the command inside the xml_stream Return the value of the command inside the xml_stream
""" """
cmd = None cmd = None
if xml.nodeName=='Status': if xml.tag == 'Status':
cmd = xml.xpath('string(//Status/Cmd)') cmd = '%s' % xml.xpath('string(//Status/Cmd)')
if isinstance(cmd, unicode):
cmd = cmd.encode('utf-8')
return cmd return cmd
def getCred(self, xml): def getCred(self, xml):
""" """
return the credential information : type, format and data return the credential information : type, format and data
""" """
format='' format = '%s' % xml.xpath("string(/SyncML/SyncHdr/Cred/Meta/*[local-name() = 'Format'])")
type='' type = '%s' % xml.xpath("string(/SyncML/SyncHdr/Cred/Meta/*[local-name() = 'Type'])")
data='' data = '%s' % xml.xpath('string(/SyncML/SyncHdr/Cred/Data)')
first_node = xml.childNodes[0]
format = first_node.xpath("string(/SyncML/SyncHdr/Cred/Meta/*[local-name() = 'Format'])")
type = first_node.xpath("string(/SyncML/SyncHdr/Cred/Meta/*[local-name() = 'Type'])")
data = first_node.xpath('string(/SyncML/SyncHdr/Cred/Data)')
format = format.encode('utf-8')
type = type.encode('utf-8')
data = data.encode('utf-8')
return (format, type, data) return (format, type, data)
def checkCred(self, xml_stream): def checkCred(self, xml_stream):
""" """
Check if there's a Cred section in the xml_stream Check if there's a Cred section in the xml_stream
""" """
return xml_stream.xpath('string(SyncML/SyncHdr/Cred)') not in ('', None, []) return bool(xml_stream.xpath('string(/SyncML/SyncHdr/Cred)'))
def getChal(self, xml): def getChal(self, xml):
""" """
return the chalenge information : format and type return the chalenge information : format and type
""" """
format=None format = '%s' % xml.xpath("string(//*[local-name() = 'Format'])")
type=None type = '%s' % xml.xpath("string(//*[local-name() = 'Type'])")
first_node = xml.childNodes[0]
format = first_node.xpath("string(//*[local-name() = 'Format'])")
type = first_node.xpath("string(//*[local-name() = 'Type'])")
format = format.encode('utf-8')
type = type.encode('utf-8')
return (format, type) return (format, type)
def checkChal(self, xml_stream): def checkChal(self, xml_stream):
""" """
Check if there's a Chal section in the xml_stream Check if there's a Chal section in the xml_stream
""" """
return xml_stream.xpath('string(SyncML/SyncBody/Status/Chal)') not in ('', None, []) return bool(xml_stream.xpath('string(/SyncML/SyncBody/Status/Chal)'))
def checkMap(self, xml_stream): def checkMap(self, xml_stream):
""" """
Check if there's a Map section in the xml_stream Check if there's a Map section in the xml_stream
""" """
return xml_stream.xpath('string(SyncML/SyncBody/Map)') not in ('', None, []) return bool(xml_stream.xpath('string(/SyncML/SyncBody/Map)'))
def setRidWithMap(self, xml_stream, subscriber): def setRidWithMap(self, xml_stream, subscriber):
""" """
get all the local objects of the given target id and set them the rid with get all the local objects of the given target id and set them the rid with
the given source id (in the Map section) the given source id (in the Map section)
""" """
item_list = xml_stream.xpath('SyncML/SyncBody/Map/MapItem') item_list = xml_stream.xpath('/SyncML/SyncBody/Map/MapItem')
for map_item in item_list: for map_item in item_list:
gid = map_item.xpath('string(.//Target/LocURI)').encode('utf-8') gid = '%s' % map_item.xpath('string(.//Target/LocURI)')
signature = subscriber.getSignatureFromGid(gid) signature = subscriber.getSignatureFromGid(gid)
rid = map_item.xpath('string(.//Source/LocURI)').encode('utf-8') rid = '%s' % map_item.xpath('string(.//Source/LocURI)')
signature.setRid(rid) signature.setRid(rid)
def getAlertCodeFromXML(self, xml_stream): def getAlertCodeFromXML(self, xml_stream):
""" """
Return the value of the alert code inside the full syncml message Return the value of the alert code inside the full syncml message
""" """
alert_code = xml_stream.xpath('string(SyncML/SyncBody/Alert/Data)') alert_code = '%s' % xml_stream.xpath('string(/SyncML/SyncBody/Alert/Data)')
if alert_code not in (None, ''): if alert_code:
return int(alert_code) return int(alert_code)
else: else:
return None return None
...@@ -645,19 +574,19 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -645,19 +574,19 @@ class XMLSyncUtilsMixin(SyncCode):
""" """
Check if there's an Alert section in the xml_stream Check if there's an Alert section in the xml_stream
""" """
return xml_stream.xpath('string(SyncML/SyncBody/Alert)') not in ('', None, []) return bool(xml_stream.xpath('string(/SyncML/SyncBody/Alert)'))
def checkSync(self, xml_stream): def checkSync(self, xml_stream):
""" """
Check if there's an Sync section in the xml_xtream Check if there's an Sync section in the xml_xtream
""" """
return xml_stream.xpath('string(SyncML/SyncBody/Sync)') not in ('', None, []) return bool(xml_stream.xpath('string(/SyncML/SyncBody/Sync)'))
def checkStatus(self, xml_stream): def checkStatus(self, xml_stream):
""" """
Check if there's a Status section in the xml_xtream Check if there's a Status section in the xml_xtream
""" """
return xml_stream.xpath('string(SyncML/SyncBody/Status)') not in ('', None, []) return bool(xml_stream.xpath('string(/SyncML/SyncBody/Status)'))
def getSyncActionList(self, xml_stream): def getSyncActionList(self, xml_stream):
""" """
...@@ -671,13 +600,13 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -671,13 +600,13 @@ class XMLSyncUtilsMixin(SyncCode):
the data are : cmd, code and source the data are : cmd, code and source
""" """
status_list = [] status_list = []
xml = xml_stream.xpath('//Status') status_node_list = xml_stream.xpath('//Status')
for status in xml: for status in status_node_list:
tmp_dict = {} tmp_dict = {}
tmp_dict['cmd'] = status.xpath('string(./Cmd)').encode('utf-8') tmp_dict['cmd'] = '%s' % status.xpath('string(./Cmd)')
tmp_dict['code'] = status.xpath('string(./Data)').encode('utf-8') tmp_dict['code'] = '%s' % status.xpath('string(./Data)')
tmp_dict['source'] = status.xpath('string(./SourceRef)').encode('utf-8') tmp_dict['source'] = '%s' % status.xpath('string(./SourceRef)')
tmp_dict['target'] = status.xpath('string(./TargetRef)').encode('utf-8') tmp_dict['target'] = '%s' % status.xpath('string(./TargetRef)')
status_list.append(tmp_dict) status_list.append(tmp_dict)
return status_list return status_list
...@@ -685,77 +614,48 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -685,77 +614,48 @@ class XMLSyncUtilsMixin(SyncCode):
""" """
return the section data in text form, it's usefull for the VCardConduit return the section data in text form, it's usefull for the VCardConduit
""" """
data = action.xpath('string(Item/Data)') return '%s' % action.xpath('string(.//Item/Data)')
if isinstance(data, unicode):
data = data.encode('utf-8')
return data
def getDataSubNode(self, action): def getDataSubNode(self, action):
""" """
Return the node starting with <object....> of the action Return the node starting with <object....> of the action
""" """
if action.xpath('.//Item/Data') not in ([], None): object_node_list = action.xpath('.//Item/Data/*[1]')
data_node = action.xpath('.//Item/Data')[0] if object_node_list:
if data_node.hasChildNodes(): return object_node_list[0]
return data_node.childNodes[0]
return None
def getPartialData(self, action):
"""
Return the node starting with <object....> of the action
"""
comment_list = action.xpath('.//Item/Data[comment()]')
if comment_list != []:
return comment_list[0].childNodes[0].data.encode('utf-8')
return None return None
def getActionId(self, action): def getActionId(self, action):
""" """
Return the rid of the object described by the action Return the rid of the object described by the action
""" """
id = action.xpath('string(.//Item/Source/LocURI)') id = '%s' % action.xpath('string(.//Item/Source/LocURI)')
if id in (None, ''): if not id:
id = action.xpath('string(.//Item/Target/LocURI)') id = '%s' % action.xpath('string(.//Item/Target/LocURI)')
if isinstance(id, unicode):
id = id.encode('utf-8')
return id return id
def checkActionMoreData(self, action): def checkActionMoreData(self, action):
""" """
Return the rid of the object described by the action Return the rid of the object described by the action
""" """
return action.xpath('Item/MoreData') not in ([],None) return bool(action.xpath('.//Item/MoreData'))
def getActionType(self, action): def getActionType(self, action):
""" """
Return the type of the object described by the action Return the type of the object described by the action
""" """
action_type = action.xpath('string(Meta/Type)') return '%s' % action.xpath('string(.//Meta/Type)')
if isinstance(action_type, unicode):
action_type = action_type.encode('utf-8')
return action_type
def getElementNodeList(self, node):
"""
Return childNodes that are ElementNode
"""
return node.xpath('*')
def getTextNodeList(self, node):
"""
Return childNodes that are ElementNode
"""
subnode_list = []
for subnode in node.childNodes or []:
if subnode.nodeType == subnode.TEXT_NODE:
subnode_list += [subnode]
return subnode_list
def getAttributeNodeList(self, node): def cutXML(self, xml_string):
""" """
Return childNodes that are ElementNode Sliced a xml tree a return two fragment
""" """
return node.xpath('@*') line_list = xml_string.split('\n')
short_string = '\n'.join(line_list[:self.MAX_LINES])
rest_string = '\n'.join(line_list[self.MAX_LINES:])
xml_string = etree.Element('Partial')
xml_string.text = etree.CDATA(short_string.decode('utf-8'))
return xml_string, rest_string
def getSyncMLData(self, domain=None, remote_xml=None, cmd_id=0, def getSyncMLData(self, domain=None, remote_xml=None, cmd_id=0,
subscriber=None, xml_confirmation=None, conduit=None, subscriber=None, xml_confirmation=None, conduit=None,
...@@ -773,8 +673,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -773,8 +673,8 @@ class XMLSyncUtilsMixin(SyncCode):
local_gid_list = [] local_gid_list = []
syncml_data = kw.get('syncml_data','') syncml_data = kw.get('syncml_data','')
result = {'finished':1} result = {'finished':1}
if isinstance(remote_xml, str) or isinstance(remote_xml, unicode): if isinstance(remote_xml, (str, unicode)):
remote_xml = Parse(remote_xml) remote_xml = etree.XML(remote_xml)
if domain.isOneWayFromServer(): if domain.isOneWayFromServer():
#Do not set object_path_list, subscriber send nothing #Do not set object_path_list, subscriber send nothing
subscriber.setRemainingObjectPathList([]) subscriber.setRemainingObjectPathList([])
...@@ -792,8 +692,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -792,8 +692,8 @@ class XMLSyncUtilsMixin(SyncCode):
gid = b16decode(domain.getGidFromObject(object)) gid = b16decode(domain.getGidFromObject(object))
if gid in gid_not_encoded_list: if gid in gid_not_encoded_list:
number = len([item for item in gid_not_encoded_list if item.startswith(gid)]) number = len([item for item in gid_not_encoded_list if item.startswith(gid)])
if number > 0: if number:
gid = gid+'__'+str(number+1) gid = '%s__%s' % (gid, str(number+1))
gid_not_encoded_list.append(gid) gid_not_encoded_list.append(gid)
local_gid_list.append(b16encode(gid)) local_gid_list.append(b16encode(gid))
#LOG('getSyncMLData :', DEBUG,'gid_not_encoded_list:%s, local_gid_list:%s, gid:%s' % (gid_not_encoded_list, local_gid_list, gid)) #LOG('getSyncMLData :', DEBUG,'gid_not_encoded_list:%s, local_gid_list:%s, gid:%s' % (gid_not_encoded_list, local_gid_list, gid))
...@@ -834,27 +734,27 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -834,27 +734,27 @@ class XMLSyncUtilsMixin(SyncCode):
object = self.unrestrictedTraverse(object_path) object = self.unrestrictedTraverse(object_path)
status = self.SENT status = self.SENT
object_gid = domain.getGidFromObject(object) object_gid = domain.getGidFromObject(object)
if object_gid in ('', None): if not object_gid:
continue continue
local_gid_list += [object_gid] local_gid_list += [object_gid]
force = 0 force = 0
if syncml_data.count('\n') < self.MAX_LINES and not \ if syncml_data.count('\n') < self.MAX_LINES and not \
object.id.startswith('.'): object.id.startswith('.'):
# If not we have to cut # If not we have to cut
#LOG('getSyncMLData', DEBUG, 'object_path: %s' % '/'.join(object_path)) #LOG('getSyncMLData', 0, 'object_path: %s' % '/'.join(object_path))
#LOG('getSyncMLData', DEBUG, 'xml_mapping: %s' % str(domain.getXMLMapping())) #LOG('getSyncMLData', 0, 'xml_mapping: %s' % str(domain.getXMLMapping()))
#LOG('getSyncMLData', DEBUG, 'code: %s' % str(self.getAlertCodeFromXML(remote_xml))) #LOG('getSyncMLData', 0, 'code: %s' % str(self.getAlertCodeFromXML(remote_xml)))
#LOG('getSyncMLData', DEBUG, 'gid_list: %s' % str(local_gid_list)) #LOG('getSyncMLData', 0, 'gid_list: %s' % str(local_gid_list))
#LOG('getSyncMLData', DEBUG, 'subscriber.getGidList: %s' % subscriber.getGidList()) #LOG('getSyncMLData', 0, 'subscriber.getGidList: %s' % subscriber.getGidList())
#LOG('getSyncMLData', DEBUG, 'hasSignature: %s' % str(subscriber.hasSignature(object_gid))) #LOG('getSyncMLData', 0, 'hasSignature: %s' % str(subscriber.hasSignature(object_gid)))
#LOG('getSyncMLData', DEBUG, 'alert_code == slowsync: %s' % str(self.getAlertCodeFromXML(remote_xml) == self.SLOW_SYNC)) #LOG('getSyncMLData', 0, 'alert_code == slowsync: %s' % str(self.getAlertCodeFromXML(remote_xml) == self.SLOW_SYNC))
signature = subscriber.getSignatureFromGid(object_gid) signature = subscriber.getSignatureFromGid(object_gid)
## Here we first check if the object was modified or not by looking at dates ## Here we first check if the object was modified or not by looking at dates
#if signature is not None: #if signature is not None:
#LOG('getSyncMLData', DEBUG, 'signature.getStatus: %s' % signature.getStatus()) #LOG('getSyncMLData', DEBUG, 'signature.getStatus: %s' % signature.getStatus())
status = self.SENT status = self.SENT
more_data=0 more_data = 0
# For the case it was never synchronized, we have to send everything # For the case it was never synchronized, we have to send everything
if signature is not None and signature.getXMLMapping() is None: if signature is not None and signature.getXMLMapping() is None:
pass pass
...@@ -862,32 +762,18 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -862,32 +762,18 @@ class XMLSyncUtilsMixin(SyncCode):
signature.getStatus() != self.PARTIAL) or \ signature.getStatus() != self.PARTIAL) or \
self.getAlertCodeFromXML(remote_xml) == self.SLOW_SYNC: self.getAlertCodeFromXML(remote_xml) == self.SLOW_SYNC:
#LOG('getSyncMLData', DEBUG, 'Current object.getPath: %s' % object.getPath()) #LOG('getSyncMLData', DEBUG, 'Current object.getPath: %s' % object.getPath())
xml_object = domain.getXMLFromObject(object) xml_string = domain.getXMLFromObject(object)
xml_string = xml_object
if isinstance(xml_string, unicode):
xml_string = xml_object.encode('utf-8')
gid = subscriber.getGidFromObject(object) gid = subscriber.getGidFromObject(object)
signature = Signature(id=gid, object=object).__of__(subscriber) signature = Signature(id=gid, object=object).__of__(subscriber)
signature.setTempXML(xml_object) signature.setTempXML(xml_string)
if xml_string.count('\n') > self.MAX_LINES: if xml_string.count('\n') > self.MAX_LINES:
if xml_string.find('--') >= 0: # This make comment fails, so we need to replace xml_string, rest_string = self.cutXML(xml_string)
xml_string = xml_string.replace('--','@-@@-@') more_data = 1
more_data=1
i = 0
short_string = ''
rest_string = xml_string
while i < self.MAX_LINES:
short_string += rest_string[:rest_string.find('\n')+1]
rest_string = xml_string[len(short_string):]
i += 1
#LOG('getSyncMLData', DEBUG, 'setPartialXML with: %s' % str(rest_string))
signature.setPartialXML(rest_string) signature.setPartialXML(rest_string)
status = self.PARTIAL status = self.PARTIAL
signature.setAction('Add') signature.setAction('Add')
xml_string = '<!--' + short_string + '-->' #in fisrt, we try with rid if there is one
gid = signature.getRid()#in fisrt, we try with rid if there is one gid = signature.getRid() or signature.getGid()
if gid is None:
gid = signature.getGid()
syncml_data += self.addXMLObject( syncml_data += self.addXMLObject(
cmd_id=cmd_id, cmd_id=cmd_id,
object=object, object=object,
...@@ -918,26 +804,16 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -918,26 +804,16 @@ class XMLSyncUtilsMixin(SyncCode):
xml_string = self.getXupdateObject(xml_object, signature.getXML()) xml_string = self.getXupdateObject(xml_object, signature.getXML())
else: #if there is no xml, we re-send all the object else: #if there is no xml, we re-send all the object
xml_string = xml_object xml_string = xml_object
if xml_string.count('\n') > self.MAX_LINES: if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
xml_string = xml_object
elif xml_string.count('\n') > self.MAX_LINES:
# This make comment fails, so we need to replace # This make comment fails, so we need to replace
if xml_string.find('--') >= 0: xml_string, rest_string = self.cutXML(xml_string)
xml_string = xml_string.replace('--', '@-@@-@')
i = 0
more_data = 1 more_data = 1
short_string_list = []
short_string_list_ap = short_string_list.append
rest_string = xml_string
while i < self.MAX_LINES:
short_string_list_ap(rest_string[:rest_string.find('\n')+1])
rest_string = xml_string[len(''.join(short_string_list)):]
i += 1
signature.setPartialXML(rest_string) signature.setPartialXML(rest_string)
status = self.PARTIAL status = self.PARTIAL
signature.setAction('Replace') signature.setAction('Replace')
xml_string = '<!--' + ''.join(short_string_list) + '-->'
signature.setStatus(status) signature.setStatus(status)
if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
xml_string = xml_object
rid = signature.getRid()#in fisrt, we try with rid if there is one rid = signature.getRid()#in fisrt, we try with rid if there is one
gid = signature.getGid() gid = signature.getGid()
syncml_data += self.replaceXMLObject( syncml_data += self.replaceXMLObject(
...@@ -983,25 +859,16 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -983,25 +859,16 @@ class XMLSyncUtilsMixin(SyncCode):
signature.setStatus(self.SYNCHRONIZED) signature.setStatus(self.SYNCHRONIZED)
elif signature.getStatus() == self.PARTIAL: elif signature.getStatus() == self.PARTIAL:
xml_string = signature.getPartialXML() xml_string = signature.getPartialXML()
if xml_string.count('\n') > self.MAX_LINES: xml_to_send = Element('Partial')
i = 0 xml_to_send.text = etree.CDATA(xml_string.decode('utf-8'))
more_data=1 if(subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']):
short_string_list = [] xml_to_send = domain.getXMLFromObject(object)
short_string_list_ap = short_string_list.append elif xml_string.count('\n') > self.MAX_LINES:
rest_string = xml_string xml_to_send, rest_string = self.cutXML(xml_string)
while i < self.MAX_LINES: more_data = 1
short_string_list_ap(rest_string[:rest_string.find('\n')+1])
rest_string = xml_string[len(''.join(short_string_list)):]
i += 1
signature.setPartialXML(rest_string) signature.setPartialXML(rest_string)
xml_string = ''.join(short_string_list)
status = self.PARTIAL status = self.PARTIAL
if xml_string.find('--') >= 0: # This make comment fails, so we need to replace
xml_string = xml_string.replace('--','@-@@-@')
xml_string = '<!--' + xml_string + '-->'
signature.setStatus(status) signature.setStatus(status)
if(subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']):
xml_string = domain.getXMLFromObject(object)
if signature.getAction() == 'Replace': if signature.getAction() == 'Replace':
rid = signature.getRid()#in fisrt, we try with rid if there is one rid = signature.getRid()#in fisrt, we try with rid if there is one
gid = signature.getGid() gid = signature.getGid()
...@@ -1010,18 +877,17 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1010,18 +877,17 @@ class XMLSyncUtilsMixin(SyncCode):
object=object, object=object,
gid=gid, gid=gid,
rid=rid, rid=rid,
xml_string=xml_string, xml_string=xml_to_send,
more_data=more_data, more_data=more_data,
media_type=subscriber.getMediaType()) media_type=subscriber.getMediaType())
elif signature.getAction() == 'Add': elif signature.getAction() == 'Add':
gid = signature.getRid()#in fisrt, we try with rid if there is one #in fisrt, we try with rid if there is one
if gid == None: gid = signature.getRid() or signature.getGid()
gid = signature.getGid()
syncml_data += self.addXMLObject( syncml_data += self.addXMLObject(
cmd_id=cmd_id, cmd_id=cmd_id,
object=object, object=object,
gid=gid, gid=gid,
xml_string=xml_string, xml_string=xml_to_send,
more_data=more_data, more_data=more_data,
media_type=subscriber.getMediaType()) media_type=subscriber.getMediaType())
if not more_data: if not more_data:
...@@ -1048,25 +914,22 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1048,25 +914,22 @@ class XMLSyncUtilsMixin(SyncCode):
#LOG('applyActionList args', DEBUG, 'domain : %s\n subscriber : %s\n cmd_id : %s' % (domain.getPath(), subscriber.getPath(), cmd_id)) #LOG('applyActionList args', DEBUG, 'domain : %s\n subscriber : %s\n cmd_id : %s' % (domain.getPath(), subscriber.getPath(), cmd_id))
#LOG('applyActionList', DEBUG, self.getSyncActionList(remote_xml)) #LOG('applyActionList', DEBUG, self.getSyncActionList(remote_xml))
for action in self.getSyncActionList(remote_xml): for action in self.getSyncActionList(remote_xml):
if isinstance(action, unicode):
action = action.encode('utf-8')
conflict_list = [] conflict_list = []
status_code = self.SUCCESS status_code = self.SUCCESS
# Thirst we have to check the kind of action it is # Thirst we have to check the kind of action it is
partial_data = self.getPartialData(action) partial_data = '%s' % action.xpath('string(.//Item/Data/Partial)')
rid = self.getActionId(action) rid = self.getActionId(action)
if action.nodeName != 'Delete': if action.tag != 'Delete':
if hasattr(conduit, 'getGidFromXML') and \ if getattr(conduit, 'getGidFromXML', None) is not None and \
conduit.getGidFromXML(self.getDataText(action), conduit.getGidFromXML(self.getDataText(action), gid_from_xml_list):
gid_from_xml_list) not in ('', None):
gid = conduit.getGidFromXML(self.getDataText(action), gid = conduit.getGidFromXML(self.getDataText(action),
gid_from_xml_list) gid_from_xml_list)
gid_from_xml_list.append(gid) gid_from_xml_list.append(gid)
gid = b16encode(gid) gid = b16encode(gid)
else: else:
gid=rid gid = rid
else: else:
gid=rid gid = rid
object_id = domain.generateNewIdWithGenerator(object=destination, gid=gid) object_id = domain.generateNewIdWithGenerator(object=destination, gid=gid)
signature = subscriber.getSignatureFromGid(gid) signature = subscriber.getSignatureFromGid(gid)
if signature is not None and rid != gid: if signature is not None and rid != gid:
...@@ -1083,7 +946,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1083,7 +946,7 @@ class XMLSyncUtilsMixin(SyncCode):
#LOG('applyActionList, try to find an object with rid', DEBUG, '') #LOG('applyActionList, try to find an object with rid', DEBUG, '')
object = subscriber.getObjectFromRid(rid) object = subscriber.getObjectFromRid(rid)
signature = subscriber.getSignatureFromRid(rid) signature = subscriber.getSignatureFromRid(rid)
if signature not in ('', None): if signature is not None:
gid = signature.getId() gid = signature.getId()
#LOG('applyActionList subscriber.getObjectFromGid %s' % gid, DEBUG, object) #LOG('applyActionList subscriber.getObjectFromGid %s' % gid, DEBUG, object)
if signature is None: if signature is None:
...@@ -1097,33 +960,30 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1097,33 +960,30 @@ class XMLSyncUtilsMixin(SyncCode):
signature.setObjectId(object_id) signature.setObjectId(object_id)
subscriber.addSignature(signature) subscriber.addSignature(signature)
force = signature.getForce() force = signature.getForce()
if self.checkActionMoreData(action) == 0: if not self.checkActionMoreData(action):
data_subnode = None data_subnode = None
if partial_data != None: if partial_data:
signature_partial_xml = signature.getPartialXML() signature_partial_xml = signature.getPartialXML()
if signature_partial_xml is not None: if signature_partial_xml:
data_subnode = signature.getPartialXML() + partial_data data_subnode = signature_partial_xml + partial_data
else: else:
data_subnode = partial_data data_subnode = partial_data
#LOG('applyActionList', DEBUG, 'data_subnode: %s' % data_subnode) #LOG('applyActionList', DEBUG, 'data_subnode: %s' % data_subnode)
if subscriber.getMediaType() == self.MEDIA_TYPE['TEXT_XML']: if subscriber.getMediaType() == self.MEDIA_TYPE['TEXT_XML']:
data_subnode = Parse(data_subnode) data_subnode = etree.XML(data_subnode)
data_subnode = data_subnode.childNodes[0] # Because we just created a new xml
# document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
else: else:
if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']: if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
data_subnode = self.getDataText(action) data_subnode = self.getDataText(action)
else: else:
data_subnode = self.getDataSubNode(action) data_subnode = self.getDataSubNode(action)
if action.nodeName == 'Add': if action.tag == 'Add':
# Then store the xml of this new subobject # Then store the xml of this new subobject
reset = 0 reset = 0
if object is None: if object is None:
add_data = conduit.addNode(xml=data_subnode, add_data = conduit.addNode(xml=data_subnode,
object=destination, object=destination,
object_id=object_id) object_id=object_id)
if add_data['conflict_list'] not in ('', None, []): conflict_list.extend(add_data['conflict_list'])
conflict_list += add_data['conflict_list']
# Retrieve directly the object from addNode # Retrieve directly the object from addNode
object = add_data['object'] object = add_data['object']
if object is not None: if object is not None:
...@@ -1134,11 +994,9 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1134,11 +994,9 @@ class XMLSyncUtilsMixin(SyncCode):
#Object was retrieve but need to be updated without recreated #Object was retrieve but need to be updated without recreated
#usefull when an object is only deleted by workflow. #usefull when an object is only deleted by workflow.
if data_subnode is not None: if data_subnode is not None:
if type(data_subnode) != type(''): if not isinstance(data_subnode, str):
string_io = StringIO() xml_string = etree.tostring(data_subnode, encoding='utf-8')
PrettyPrint(data_subnode, stream=string_io) actual_xml = subscriber.getXMLFromObject(object=object, force=1)
xml_string = string_io.getvalue()
actual_xml = subscriber.getXMLFromObject(object = object, force=1)
data_subnode = self.getXupdateObject(xml_string, actual_xml) data_subnode = self.getXupdateObject(xml_string, actual_xml)
conflict_list += conduit.updateNode( conflict_list += conduit.updateNode(
xml=data_subnode, xml=data_subnode,
...@@ -1153,9 +1011,10 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1153,9 +1011,10 @@ class XMLSyncUtilsMixin(SyncCode):
if reset: if reset:
#After a reset we want copy the LAST XML view on Signature. #After a reset we want copy the LAST XML view on Signature.
#this implementation is not sufficient, need to be improved. #this implementation is not sufficient, need to be improved.
string_io = StringIO() if not isinstance(data_subnode, str):
PrettyPrint(data_subnode, stream=string_io) xml_object = etree.tostring(data_subnode, encoding='utf-8')
xml_object = string_io.getvalue() else:
xml_object = data_subnode
else: else:
xml_object = domain.getXMLFromObject(object) xml_object = domain.getXMLFromObject(object)
signature.setStatus(self.SYNCHRONIZED) signature.setStatus(self.SYNCHRONIZED)
...@@ -1168,7 +1027,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1168,7 +1027,7 @@ class XMLSyncUtilsMixin(SyncCode):
sync_code=self.ITEM_ADDED, sync_code=self.ITEM_ADDED,
remote_xml=action) remote_xml=action)
cmd_id +=1 cmd_id +=1
elif action.nodeName == 'Replace': elif action.tag == 'Replace':
#LOG('applyActionList', DEBUG, 'object: %s will be updated...' % str(object)) #LOG('applyActionList', DEBUG, 'object: %s will be updated...' % str(object))
if object is not None: if object is not None:
#LOG('applyActionList', DEBUG, 'object: %s will be updated...' % object.id) #LOG('applyActionList', DEBUG, 'object: %s will be updated...' % object.id)
...@@ -1185,14 +1044,11 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1185,14 +1044,11 @@ class XMLSyncUtilsMixin(SyncCode):
simulate=simulate) simulate=simulate)
xml_object = domain.getXMLFromObject(object) xml_object = domain.getXMLFromObject(object)
signature.setTempXML(xml_object) signature.setTempXML(xml_object)
if conflict_list != []: if conflict_list:
status_code = self.CONFLICT status_code = self.CONFLICT
signature.setStatus(self.CONFLICT) signature.setStatus(self.CONFLICT)
signature.setConflictList(signature.getConflictList() \ signature.setConflictList(signature.getConflictList()+conflict_list)
+ conflict_list) data_subnode_string = etree.tostring(data_subnode, encoding='utf-8')
string_io = StringIO()
PrettyPrint(data_subnode, stream=string_io)
data_subnode_string = string_io.getvalue()
signature.setPartialXML(data_subnode_string) signature.setPartialXML(data_subnode_string)
elif not simulate: elif not simulate:
signature.setStatus(self.SYNCHRONIZED) signature.setStatus(self.SYNCHRONIZED)
...@@ -1206,13 +1062,11 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1206,13 +1062,11 @@ class XMLSyncUtilsMixin(SyncCode):
# This means we are on the publisher side and we want to store # This means we are on the publisher side and we want to store
# the xupdate from the subscriber and we also want to generate # the xupdate from the subscriber and we also want to generate
# the current xupdate from the last synchronization # the current xupdate from the last synchronization
string_io = StringIO() data_subnode_string = etree.tostring(data_subnode, encoding='utf-8')
PrettyPrint(data_subnode, stream=string_io)
data_subnode_string = string_io.getvalue()
#LOG('applyActionList, subscriber_xupdate:', TRACE, data_subnode_string) #LOG('applyActionList, subscriber_xupdate:', TRACE, data_subnode_string)
signature.setSubscriberXupdate(data_subnode_string) signature.setSubscriberXupdate(data_subnode_string)
elif action.nodeName == 'Delete': elif action.tag == 'Delete':
object_id = signature.getId() object_id = signature.getId()
#LOG('applyActionList Delete on : ', DEBUG, (signature.getId(), subscriber.getObjectFromGid(object_id))) #LOG('applyActionList Delete on : ', DEBUG, (signature.getId(), subscriber.getObjectFromGid(object_id)))
if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']: if subscriber.getMediaType() != self.MEDIA_TYPE['TEXT_XML']:
...@@ -1220,7 +1074,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1220,7 +1074,7 @@ class XMLSyncUtilsMixin(SyncCode):
else: else:
data_subnode = self.getDataSubNode(action) data_subnode = self.getDataSubNode(action)
#LOG('applyActionList, object gid to delete :', 0, subscriber.getObjectFromGid(object_id)) #LOG('applyActionList, object gid to delete :', 0, subscriber.getObjectFromGid(object_id))
if subscriber.getObjectFromGid(object_id) not in (None, ''): if subscriber.getObjectFromGid(object_id) is not None:
#if the object exist: #if the object exist:
conduit.deleteNode( conduit.deleteNode(
xml=data_subnode, xml=data_subnode,
...@@ -1242,10 +1096,10 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1242,10 +1096,10 @@ class XMLSyncUtilsMixin(SyncCode):
#LOG('applyActionList', DEBUG, 'waiting more data for :%s' % signature.getId()) #LOG('applyActionList', DEBUG, 'waiting more data for :%s' % signature.getId())
xml_confirmation += self.SyncMLConfirmation( xml_confirmation += self.SyncMLConfirmation(
cmd_id=cmd_id, cmd_id=cmd_id,
cmd=action.nodeName, cmd=action.tag,
sync_code=self.WAITING_DATA, sync_code=self.WAITING_DATA,
remote_xml=action) remote_xml=action)
if conflict_list != [] and signature is not None: if conflict_list and signature is not None:
# We had a conflict # We had a conflict
signature.setStatus(self.CONFLICT) signature.setStatus(self.CONFLICT)
...@@ -1259,14 +1113,15 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1259,14 +1113,15 @@ class XMLSyncUtilsMixin(SyncCode):
status_list = self.getSyncBodyStatusList(remote_xml) status_list = self.getSyncBodyStatusList(remote_xml)
has_status_list = 0 has_status_list = 0
destination_waiting_more_data = 0 destination_waiting_more_data = 0
if status_list != []:
for status in status_list: for status in status_list:
if not status['code']:
continue
status_cmd = status['cmd'] status_cmd = status['cmd']
object_gid = status['source'] object_gid = status['source']
if object_gid in ('', None, []): if not object_gid:
object_gid = status['target'] object_gid = status['target']
status_code = int(status['code']) status_code = int(status['code'])
if status_cmd in ('Add','Replace',): if status_cmd in ('Add', 'Replace',):
has_status_list = 1 has_status_list = 1
signature = subscriber.getSignatureFromGid(object_gid) signature = subscriber.getSignatureFromGid(object_gid)
if signature is None: if signature is None:
...@@ -1342,10 +1197,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1342,10 +1197,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
has_response = 0 #check if syncmodif replies to this messages has_response = 0 #check if syncmodif replies to this messages
cmd_id = 1 # specifies a SyncML message-unique command identifier cmd_id = 1 # specifies a SyncML message-unique command identifier
#LOG('SyncModif', DEBUG, 'Starting... domain: %s' % domain.getId()) #LOG('SyncModif', DEBUG, 'Starting... domain: %s' % domain.getId())
first_node = remote_xml.childNodes[0]
# Get informations from the header # Get informations from the header
xml_header = first_node.childNodes[1] xml_header = remote_xml[0]
if xml_header.nodeName != "SyncHdr": if xml_header.tag != "SyncHdr":
LOG('SyncModif', INFO, 'This is not a SyncML Header') LOG('SyncModif', INFO, 'This is not a SyncML Header')
raise ValueError, "Sorry, This is not a SyncML Header" raise ValueError, "Sorry, This is not a SyncML Header"
...@@ -1358,24 +1212,24 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1358,24 +1212,24 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
# We have to check if this message was not already, this can be dangerous # We have to check if this message was not already, this can be dangerous
# to update two times the same object # to update two times the same object
message_id = self.getMessageId(remote_xml) message_id = self.getMessageIdFromXml(remote_xml)
correct_message = subscriber.checkCorrectRemoteMessageId(message_id) correct_message = subscriber.checkCorrectRemoteMessageId(message_id)
if not correct_message: # We need to send again the message if not correct_message: # We need to send again the message
LOG('SyncModif, no correct message:', INFO, "sending again...") LOG('SyncModif, no correct message:', INFO, "sending again...")
last_xml = subscriber.getLastSentMessage() last_xml = subscriber.getLastSentMessage()
LOG("SyncModif last_xml :", INFO, last_xml) LOG("SyncModif last_xml :", INFO, last_xml)
string_io = StringIO() remote_xml = etree.tostring(remote_xml, encoding='utf-8',
PrettyPrint(remote_xml, stream=string_io) xml_declaration=True,
remote_xml = string_io.getvalue() pretty_print=True)
LOG("SyncModif remote_xml :", INFO, remote_xml) LOG("SyncModif remote_xml :", INFO, remote_xml)
if last_xml != '': if last_xml:
has_response = 1 has_response = 1
if domain.domain_type == self.PUB: # We always reply if domain.domain_type == self.PUB: # We always reply
self.sendResponse( self.sendResponse(
from_url=domain.publication_url, from_url=domain.publication_url,
to_url=subscriber.subscription_url, to_url=subscriber.subscription_url,
sync_id=domain.getTitle(), sync_id=domain.getTitle(),
xml=last_xml,domain=domain, xml=last_xml, domain=domain,
content_type=domain.getSyncContentType()) content_type=domain.getSyncContentType())
elif domain.domain_type == self.SUB: elif domain.domain_type == self.SUB:
self.sendResponse( self.sendResponse(
...@@ -1435,7 +1289,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1435,7 +1289,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
destination_url = '' destination_url = ''
# alert message if we want more data # alert message if we want more data
if destination_waiting_more_data == 1: if destination_waiting_more_data:
xml(self.SyncMLAlert( xml(self.SyncMLAlert(
cmd_id, cmd_id,
self.WAITING_DATA, self.WAITING_DATA,
...@@ -1448,10 +1302,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1448,10 +1302,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
cmd_id = cmd_id+1 cmd_id = cmd_id+1
if domain.getActivityEnabled(): if domain.getActivityEnabled():
#use activities to get SyncML data. #use activities to get SyncML data.
if not (isinstance(remote_xml, str) or isinstance(remote_xml, unicode)): if not isinstance(remote_xml, (str, unicode)):
string_io = StringIO() remote_xml = etree.tostring(remote_xml, encoding='utf-8',
PrettyPrint(remote_xml,stream=string_io) xml_declaration=True, pretty_print=False)
remote_xml = string_io.getvalue()
domain.activate(activity='SQLQueue', domain.activate(activity='SQLQueue',
tag=domain.getId(), tag=domain.getId(),
priority=self.PRIORITY).activateSyncModif( priority=self.PRIORITY).activateSyncModif(
...@@ -1518,12 +1371,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1518,12 +1371,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
domain = self.unrestrictedTraverse(kw['domain_relative_url']) domain = self.unrestrictedTraverse(kw['domain_relative_url'])
subscriber = self.unrestrictedTraverse(kw['subscriber_relative_url']) subscriber = self.unrestrictedTraverse(kw['subscriber_relative_url'])
conduit = subscriber.getConduit() conduit = subscriber.getConduit()
result = self.getSyncMLData( result = self.getSyncMLData(domain=domain, subscriber=subscriber,
domain = domain, conduit=conduit, max=self.MAX_OBJECTS, **kw)
subscriber = subscriber,
conduit = conduit,
max = self.MAX_OBJECTS,
**kw)
syncml_data = result['syncml_data'] syncml_data = result['syncml_data']
cmd_id = result['cmd_id'] cmd_id = result['cmd_id']
kw['syncml_data'] = syncml_data kw['syncml_data'] = syncml_data
...@@ -1537,7 +1386,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1537,7 +1386,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
xml_confirmation = result['xml_confirmation'] xml_confirmation = result['xml_confirmation']
cmd_id = result['cmd_id'] cmd_id = result['cmd_id']
cmd_id_before_getsyncmldata = kw['cmd_id_before_getsyncmldata'] cmd_id_before_getsyncmldata = kw['cmd_id_before_getsyncmldata']
remote_xml = Parse(kw['remote_xml']) remote_xml = etree.XML(kw['remote_xml'])
xml_list = kw['xml_list'] xml_list = kw['xml_list']
has_status_list = kw['has_status_list'] has_status_list = kw['has_status_list']
has_response = kw['has_response'] has_response = kw['has_response']
...@@ -1555,6 +1404,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1555,6 +1404,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
def sendSyncModif(self, syncml_data, cmd_id_before_getsyncmldata, subscriber, def sendSyncModif(self, syncml_data, cmd_id_before_getsyncmldata, subscriber,
domain, xml_confirmation, remote_xml, xml_list, domain, xml_confirmation, remote_xml, xml_list,
has_status_list, has_response): has_status_list, has_response):
xml = xml_list.append xml = xml_list.append
if syncml_data != '': if syncml_data != '':
xml(' <Sync>\n') xml(' <Sync>\n')
...@@ -1584,7 +1434,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1584,7 +1434,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
xml=xml_a, xml=xml_a,
domain=domain, domain=domain,
content_type=domain.getSyncContentType()) content_type=domain.getSyncContentType())
if syncml_data == '': if not syncml_data:
LOG('this is the end of the synchronisation session !!!', INFO, domain.getId()) LOG('this is the end of the synchronisation session !!!', INFO, domain.getId())
subscriber.setAuthenticated(False) subscriber.setAuthenticated(False)
domain.setAuthenticated(False) domain.setAuthenticated(False)
...@@ -1652,17 +1502,15 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1652,17 +1502,15 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
result = None result = None
if xml_client is not None: if xml_client is not None:
if isinstance(xml_client, str) or isinstance(xml_client, unicode): if isinstance(xml_client, (str, unicode)):
xml_client = Parse(xml_client) xml_client = etree.XML(xml_client)
first_node = xml_client.childNodes[0] if xml_client.tag != "SyncML":
if first_node.nodeName != "SyncML":
LOG('PubSync', INFO, 'This is not a SyncML Message') LOG('PubSync', INFO, 'This is not a SyncML Message')
raise ValueError, "Sorry, This is not a SyncML Message" raise ValueError, "Sorry, This is not a SyncML Message"
alert_code = self.getAlertCodeFromXML(xml_client) alert_code = self.getAlertCodeFromXML(xml_client)
# Get informations from the header # Get informations from the header
client_header = first_node.childNodes[1] client_header = xml_client[0]
if client_header.nodeName != "SyncHdr": if client_header.tag != "SyncHdr":
LOG('PubSync', INFO, 'This is not a SyncML Header') LOG('PubSync', INFO, 'This is not a SyncML Header')
raise ValueError, "Sorry, This is not a SyncML Header" raise ValueError, "Sorry, This is not a SyncML Header"
subscription_url = self.getSubscriptionUrlFromXML(client_header) subscription_url = self.getSubscriptionUrlFromXML(client_header)
...@@ -1717,17 +1565,17 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1717,17 +1565,17 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
""" """
response = None #check if subsync replies to this messages response = None #check if subsync replies to this messages
subscription = self.unrestrictedTraverse(subscription_path) subscription = self.unrestrictedTraverse(subscription_path)
if msg is None and (subscription.getSubscriptionUrl()).find('file')>=0: if msg is None and (subscription.getSubscriptionUrl()).find('file') >= 0:
msg = self.readResponse(sync_id=subscription.getSubscriptionUrl(), msg = self.readResponse(sync_id=subscription.getSubscriptionUrl(),
from_url=subscription.getSubscriptionUrl()) from_url=subscription.getSubscriptionUrl())
if msg is None: if msg is None:
response = self.SubSyncInit(subscription) response = self.SubSyncInit(subscription)
else: else:
xml_client = msg xml_client = msg
if isinstance(xml_client, str) or isinstance(xml_client, unicode): if isinstance(xml_client, (str, unicode)):
xml_client = Parse(xml_client) xml_client = etree.XML(xml_client)
status_list = self.getSyncBodyStatusList(xml_client) status_list = self.getSyncBodyStatusList(xml_client)
if status_list not in (None, []): if status_list:
status_code_syncHdr = status_list[0]['code'] status_code_syncHdr = status_list[0]['code']
if status_code_syncHdr.isdigit(): if status_code_syncHdr.isdigit():
status_code_syncHdr = int(status_code_syncHdr) status_code_syncHdr = int(status_code_syncHdr)
......
# -*- coding: utf-8 -*-
############################################################################## ##############################################################################
# #
# Copyright (c) 2004 Nexedi SARL and Contributors. All Rights Reserved. # Copyright (c) 2004 Nexedi SARL and Contributors. All Rights Reserved.
...@@ -486,23 +487,23 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -486,23 +487,23 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
ZopeTestCase._print('\nTest First Synchronization ') ZopeTestCase._print('\nTest First Synchronization ')
LOG('Testing... ',0,'test_08_FirstSynchronization') LOG('Testing... ',0,'test_08_FirstSynchronization')
self.login() self.login()
self.setupPublicationAndSubscription(quiet=1,run=1) self.setupPublicationAndSubscription(quiet=1, run=1)
nb_person = self.populatePersonServer(quiet=1,run=1) nb_person = self.populatePersonServer(quiet=1, run=1)
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
for sub in portal_sync.getSubscriptionList(): for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.SLOW_SYNC) self.assertEquals(sub.getSynchronizationType(), SyncCode.SLOW_SYNC)
# Synchronize the first client # Synchronize the first client
nb_message1 = self.synchronize(self.sub_id1) nb_message1 = self.synchronize(self.sub_id1)
for sub in portal_sync.getSubscriptionList(): for sub in portal_sync.getSubscriptionList():
if sub.getTitle() == self.sub_id1: if sub.getTitle() == self.sub_id1:
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY) self.assertEquals(sub.getSynchronizationType(), SyncCode.TWO_WAY)
else: else:
self.assertEquals(sub.getSynchronizationType(),SyncCode.SLOW_SYNC) self.assertEquals(sub.getSynchronizationType(), SyncCode.SLOW_SYNC)
self.assertEqual(nb_message1, self.nb_message_first_synchronization) self.assertEqual(nb_message1, self.nb_message_first_synchronization)
# Synchronize the second client # Synchronize the second client
nb_message2 = self.synchronize(self.sub_id2) nb_message2 = self.synchronize(self.sub_id2)
for sub in portal_sync.getSubscriptionList(): for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY) self.assertEquals(sub.getSynchronizationType(), SyncCode.TWO_WAY)
self.assertEqual(nb_message2, self.nb_message_first_synchronization) self.assertEqual(nb_message2, self.nb_message_first_synchronization)
self.checkFirstSynchronization(id=self.id1, nb_person=nb_person) self.checkFirstSynchronization(id=self.id1, nb_person=nb_person)
......
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