Commit 46698e31 authored by Sebastien Robin's avatar Sebastien Robin

put back the use of 4Suite, more use of xpath, add flow type in order to allow...

put back the use of 4Suite, more use of xpath, add flow type in order to allow to synchronise with simple text

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@14655 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 64a2b761
...@@ -33,8 +33,7 @@ from Products.CMFCore.utils import getToolByName ...@@ -33,8 +33,7 @@ from Products.CMFCore.utils import getToolByName
from Products.ERP5SyncML.XupdateUtils import XupdateUtils from Products.ERP5SyncML.XupdateUtils import XupdateUtils
from Products.ERP5Type.Utils import convertToUpperCase from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Type.Accessor.TypeDefinition import list_types from Products.ERP5Type.Accessor.TypeDefinition import list_types
from xml.dom.ext.reader.Sax2 import FromXml from Ft.Xml import Parse
from xml.dom.minidom import parse, parseString
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
...@@ -44,10 +43,12 @@ from Products.ERP5Type import Permissions ...@@ -44,10 +43,12 @@ from Products.ERP5Type import Permissions
from Globals import PersistentMapping from Globals import PersistentMapping
import pickle import pickle
import string import string
from xml.dom.ext import PrettyPrint
from cStringIO import StringIO from cStringIO import StringIO
from xml.sax.saxutils import escape, unescape from xml.sax.saxutils import escape, unescape
import re, copy import re, copy
import cStringIO
from Ft.Xml.Domlette import Print, PrettyPrint
from zLOG import LOG from zLOG import LOG
...@@ -132,7 +133,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -132,7 +133,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return {'conflict_list':conflict_list, 'object':sub_object} return {'conflict_list':conflict_list, 'object':sub_object}
LOG('addNode',0,'xml_reconstitued: %s' % str(xml)) LOG('addNode',0,'xml_reconstitued: %s' % str(xml))
# 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 self.getSubObjectDepth(xml)==0: if xml.nodeName in self.XUPDATE_INSERT_OR_ADD and \
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)
...@@ -160,7 +162,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -160,7 +162,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
portal_type = self.getObjectType(xml) portal_type = self.getObjectType(xml)
elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD: # Deprecated ??? elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD: # Deprecated ???
portal_type = self.getXupdateObjectType(xml) # Deprecated ??? portal_type = self.getXupdateObjectType(xml) # Deprecated ???
sub_object = self.constructContent(object, object_id, docid, portal_type) sub_object = self.constructContent(object, object_id, docid,
portal_type)
self.newObject( self.newObject(
object=sub_object, object=sub_object,
xml=xml, xml=xml,
...@@ -274,9 +277,9 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -274,9 +277,9 @@ class ERP5Conduit(XMLSyncUtilsMixin):
LOG('updateNode, force: ',0,force) LOG('updateNode, force: ',0,force)
# we have an xupdate xml # we have an xupdate xml
if xml.nodeName == 'xupdate:modifications': if xml.nodeName == 'xupdate:modifications':
conflict_list += self.applyXupdate(object=object,xupdate=xml,conduit=self, conflict_list += self.applyXupdate(object=object, xupdate=xml,
previous_xml=previous_xml, force=force, simulate=simulate, conduit=self,previous_xml=previous_xml, force=force,
**kw) simulate=simulate, **kw)
# we may have only the part of an xupdate # we may have only the part of an xupdate
else: else:
args = {} args = {}
...@@ -342,7 +345,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -342,7 +345,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
# - current_data : the data actually on this box # - current_data : the data actually on this box
isConflict = 0 isConflict = 0
if (previous_xml is not None) and (not force): # if no previous_xml, no conflict if (previous_xml is not None) and (not force): # if no previous_xml, no conflict
old_data = self.getObjectProperty(keyword,previous_xml,data_type=data_type) old_data = self.getObjectProperty(keyword, previous_xml,
data_type=data_type)
#current_data = object.getProperty(keyword) #current_data = object.getProperty(keyword)
current_data = self.getProperty(object, keyword) current_data = self.getProperty(object, keyword)
LOG('updateNode',0,'Conflict data: %s' % str(data)) LOG('updateNode',0,'Conflict data: %s' % str(data))
...@@ -383,7 +387,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -383,7 +387,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if keyword == 'object': if keyword == 'object':
# This is the case where we have to call addNode # This is the case where we have to call addNode
LOG('updateNode',0,'we will add sub-object') LOG('updateNode',0,'we will add sub-object')
conflict_list += self.addNode(xml=xml,object=object,force=force, conflict_list += self.addNode(xml=xml, object=object, force=force,
simulate=simulate, **kw)['conflict_list'] simulate=simulate, **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
...@@ -397,7 +401,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -397,7 +401,7 @@ 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, force=force,
simulate=simulate,**kw)['conflict_list'] 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
...@@ -421,8 +425,21 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -421,8 +425,21 @@ class ERP5Conduit(XMLSyncUtilsMixin):
sub_xml = self.getSubObjectXupdate(xml) sub_xml = self.getSubObjectXupdate(xml)
LOG('updateNode',0,'sub_xml: %s' % str(sub_xml)) LOG('updateNode',0,'sub_xml: %s' % str(sub_xml))
# Then do the udpate # Then do the udpate
conflict_list += self.updateNode(xml=sub_xml,object=sub_object, force=force, conflict_list += self.updateNode(xml=sub_xml, object=sub_object, force=force,
previous_xml=sub_previous_xml,simulate=simulate, **kw) previous_xml=sub_previous_xml, simulate=simulate, **kw)
elif previous_xml is None and xml is not None and sub_object_id is not None:
sub_object = None
try:
sub_object = object[sub_object_id]
except KeyError:
pass
if sub_object is not None:
sub_xml = self.getSubObjectXupdate(xml)
conflict_list += self.updateNode(xml=sub_xml,
object=sub_object,
force=force,
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
try: try:
...@@ -438,7 +455,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -438,7 +455,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
**kw) **kw)
return conflict_list return conflict_list
security.declareProtected(Permissions.AccessContentsInformation,'getFormatedArgs') security.declareProtected(Permissions.AccessContentsInformation,
'getFormatedArgs')
def getFormatedArgs(self, args=None): def getFormatedArgs(self, args=None):
""" """
This lookd inside the args dictionnary and then This lookd inside the args dictionnary and then
...@@ -484,19 +502,21 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -484,19 +502,21 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return 0 return 0
return 1 return 1
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectXupdate') security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectXupdate')
def getSubObjectXupdate(self, xml): def getSubObjectXupdate(self, xml):
""" """
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.deepcopy(xml) xml_copy = xml.cloneNode(True) #make a deepcopy of the node xml
for subnode in self.getAttributeNodeList(xml): for subnode in self.getAttributeNodeList(xml_copy):
if subnode.nodeName=='select': if subnode.nodeName=='select':
subnode.nodeValue = self.getSubObjectSelect(subnode.nodeValue) subnode.nodeValue = self.getSubObjectSelect(subnode.nodeValue)
return xml return xml_copy
security.declareProtected(Permissions.AccessContentsInformation,'isHistoryAdd') security.declareProtected(Permissions.AccessContentsInformation,
'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): for subnode in self.getAttributeNodeList(xml):
...@@ -510,7 +530,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -510,7 +530,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return -1 return -1
return 0 return 0
security.declareProtected(Permissions.AccessContentsInformation,'isSubObjectModification') security.declareProtected(Permissions.AccessContentsInformation,
'isSubObjectModification')
def isSubObjectModification(self, xml): def isSubObjectModification(self, xml):
""" """
Check if it is a modification from an subobject Check if it is a modification from an subobject
...@@ -524,7 +545,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -524,7 +545,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return 1 return 1
return 0 return 0
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectDepth') security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectDepth')
def getSubObjectDepth(self, xml): def getSubObjectDepth(self, xml):
""" """
Give the Depth of a subobject modification Give the Depth of a subobject modification
...@@ -555,7 +577,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -555,7 +577,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return (1 - i) return (1 - i)
return 0 return 0
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectSelect') security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectSelect')
def getSubObjectSelect(self, select): def getSubObjectSelect(self, select):
""" """
Return a string wich is the selection for the subobject Return a string wich is the selection for the subobject
...@@ -571,7 +594,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -571,7 +594,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
select = new_value select = new_value
return select return select
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectId') security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectId')
def getSubObjectId(self, xml): def getSubObjectId(self, xml):
""" """
Return the id of the subobject in an xupdate modification Return the id of the subobject in an xupdate modification
...@@ -587,7 +611,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -587,7 +611,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return object_id return object_id
return object_id return object_id
security.declareProtected(Permissions.AccessContentsInformation,'getHistoryIdFromSelect') security.declareProtected(Permissions.AccessContentsInformation,
'getHistoryIdFromSelect')
def getHistoryIdFromSelect(self, xml): def getHistoryIdFromSelect(self, xml):
""" """
Return the id of the subobject in an xupdate modification Return the id of the subobject in an xupdate modification
...@@ -604,7 +629,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -604,7 +629,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return object_id return object_id
return object_id return object_id
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectXml') security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectXml')
def getSubObjectXml(self, object_id, xml): def getSubObjectXml(self, object_id, xml):
""" """
Return the xml of the subobject which as the id object_id Return the xml of the subobject which as the id object_id
...@@ -624,7 +650,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -624,7 +650,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
for attribute in self.getAttributeNodeList(xml): for attribute in self.getAttributeNodeList(xml):
if attribute.nodeName == param: if attribute.nodeName == param:
data = attribute.childNodes[0].data data = attribute.value
return self.convertXmlValue(data,data_type='string') return self.convertXmlValue(data,data_type='string')
return None return None
...@@ -635,7 +661,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -635,7 +661,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
for subnode in self.getElementNodeList(xml): for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'docid': if subnode.nodeName == 'docid':
data = subnode.childNodes[0].data data = subnode.childNodes[0].value
return self.convertXmlValue(data) return self.convertXmlValue(data)
return None return None
...@@ -669,7 +695,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -669,7 +695,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
LOG('Conduit.convertToXml xml',0,repr(xml)) LOG('Conduit.convertToXml xml',0,repr(xml))
if type(xml) is type(u'a'): if type(xml) is type(u'a'):
xml = xml.encode('utf-8') xml = xml.encode('utf-8')
xml = parseString(xml) xml = Parse(xml)
LOG('Conduit.convertToXml not failed',0,'ok') LOG('Conduit.convertToXml not failed',0,'ok')
xml = xml.childNodes[0] # Because we just created a new xml 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
...@@ -811,7 +837,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -811,7 +837,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
#PrettyPrint(xml,xml_string) #PrettyPrint(xml,xml_string)
#xml_string = xml_string.getvalue() #xml_string = xml_string.getvalue()
#xml_string = unicode(xml_string,encoding='utf-8') #xml_string = unicode(xml_string,encoding='utf-8')
xml_string = xml.toxml(encoding='utf-8') xml_string = self.nodeToString(xml)
xml_string = unicode(xml_string,encoding='utf-8') xml_string = unicode(xml_string,encoding='utf-8')
#if type(xml_string) is type (u'a'): #if type(xml_string) is type (u'a'):
# xml_string = xml_string.encode('utf-8') # xml_string = xml_string.encode('utf-8')
...@@ -840,12 +866,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -840,12 +866,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if select_id is not None: if select_id is not None:
result += ' id=%s' % select_id result += ' id=%s' % select_id
result += '>' result += '>'
# Then dumps the xml and remove what we does'nt want xml_string = self.nodeToString(xml)
#xml_string = StringIO()
#PrettyPrint(xml,xml_string)
#xml_string = xml_string.getvalue()
#xml_string = unicode(xml_string,encoding='utf-8')
xml_string = xml.toxml(encoding='utf-8')
xml_string = unicode(xml_string,encoding='utf-8') 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.nodeName)]
...@@ -929,7 +950,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -929,7 +950,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
conflict_list = [] conflict_list = []
if type(xupdate) in (type('a'),type(u'a')): if type(xupdate) in (type('a'),type(u'a')):
xupdate = parseString(xupdate) xupdate = Parse(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
...@@ -967,7 +988,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -967,7 +988,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
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 = subnode.getAttribute('select') value = self.getAttribute(subnode, 'select')
if re.search(self.object_exp, value): if re.search(self.object_exp, value):
comp += 1 comp += 1
if nb_sub == comp: if nb_sub == comp:
...@@ -1043,7 +1064,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1043,7 +1064,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
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)
LOG('addNode, workflow_history id:',0,wf_id) LOG('addNode, workflow_history id:',0,wf_id)
LOG('addNode, workflow_history xml:',0,xml.toxml()) #LOG('addNode, workflow_history xml:',0,xml.toxml())#toxml isn't in 4Suite
LOG('addNode, workflow_history xml.getElmentNodeList:',0,self.getElementNodeList(xml)) LOG('addNode, workflow_history xml.getElmentNodeList:',0,self.getElementNodeList(xml))
xml = self.getElementNodeList(xml)[0] xml = self.getElementNodeList(xml)[0]
LOG('addNode, workflow_history id:',0,wf_id) LOG('addNode, workflow_history id:',0,wf_id)
...@@ -1152,3 +1173,14 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1152,3 +1173,14 @@ class ERP5Conduit(XMLSyncUtilsMixin):
# conflict.setRemoteValue(status) # conflict.setRemoteValue(status)
# conflict_list += [conflict] # conflict_list += [conflict]
# return conflict_list # return conflict_list
def nodeToString(self, node):
"""
return an xml string corresponding to the node
"""
buf = cStringIO.StringIO()
Print(node, stream=buf, encoding='utf-8')
xml_string = buf.getvalue()
buf.close()
return xml_string
...@@ -153,8 +153,9 @@ class Publication(Subscription): ...@@ -153,8 +153,9 @@ class Publication(Subscription):
# Constructor # Constructor
def __init__(self, id, title, publication_url, destination_path, def __init__(self, id, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, auth_required=False, query, xml_mapping, conduit, gpg_key, id_generator, gid_generator,
authentication_format='', authentication_type=''): flow_type, auth_required=False, authentication_format='',
authentication_type=''):
""" """
constructor constructor
""" """
...@@ -166,8 +167,9 @@ class Publication(Subscription): ...@@ -166,8 +167,9 @@ class Publication(Subscription):
#self.list_subscribers = PersistentMapping() #self.list_subscribers = PersistentMapping()
self.domain_type = self.PUB self.domain_type = self.PUB
self.gpg_key = gpg_key self.gpg_key = gpg_key
self.setGidGenerator(None) self.setGidGenerator(gid_generator)
self.setIdGenerator(None) self.setFlowType(flow_type)
self.setSynchronizationIdGenerator(id_generator)
self.setConduit(conduit) self.setConduit(conduit)
Folder.__init__(self, id) Folder.__init__(self, id)
self.title = title self.title = title
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
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 xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml from Ft.Xml import Parse
from xml.dom.minidom import parse, parseString
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
...@@ -142,6 +141,13 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -142,6 +141,13 @@ class PublicationSynchronization(XMLSyncUtils):
xml(' <SyncBody>\n') xml(' <SyncBody>\n')
xml(self.SyncMLStatus(cmd_id, subscriber.getSubscriptionUrl(), xml(self.SyncMLStatus(cmd_id, subscriber.getSubscriptionUrl(),
publication.getPublicationUrl(), auth_code)) publication.getPublicationUrl(), auth_code))
cmd_id += 1
if auth_code == self.AUTH_ACCEPTED:
# alert message
xml(self.SyncMLAlert(cmd_id, sync_type,
subscriber.getSubscriptionUrl(), publication.getPublicationUrl(),
subscriber.getLastAnchor(), subscriber.getNextAnchor()))
cmd_id += 1
xml(' </SyncBody>\n') xml(' </SyncBody>\n')
xml('</SyncML>\n') xml('</SyncML>\n')
xml_a = ''.join(xml_list) xml_a = ''.join(xml_list)
...@@ -221,7 +227,7 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -221,7 +227,7 @@ class PublicationSynchronization(XMLSyncUtils):
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) or isinstance(xml_client, unicode):
xml_client = parseString(xml_client) xml_client = Parse(xml_client)
first_node = xml_client.childNodes[0] first_node = xml_client.childNodes[0]
if first_node.nodeName != "SyncML": if first_node.nodeName != "SyncML":
......
...@@ -642,8 +642,9 @@ class Subscription(Folder, SyncCode): ...@@ -642,8 +642,9 @@ class Subscription(Folder, SyncCode):
) )
# Constructor # Constructor
def __init__(self, id, title, publication_url, subscription_url, destination_path, query, xml_mapping, conduit, gpg_key, login, password, def __init__(self, id, title, publication_url, subscription_url,
authentication_format='', authentication_type=''): destination_path, query, xml_mapping, conduit, gpg_key, id_generator,
gid_generator, flow_type, login, password):
""" """
We need to create a dictionnary of We need to create a dictionnary of
signatures of documents which belong to the synchronisation signatures of documents which belong to the synchronisation
...@@ -660,14 +661,13 @@ class Subscription(Folder, SyncCode): ...@@ -660,14 +661,13 @@ class Subscription(Folder, SyncCode):
#self.signatures = PersistentMapping() #self.signatures = PersistentMapping()
self.last_anchor = '00000000T000000Z' self.last_anchor = '00000000T000000Z'
self.next_anchor = '00000000T000000Z' self.next_anchor = '00000000T000000Z'
self.login=login self.flow_type = flow_type
self.login = login
self.password=password self.password=password
self.authentication_format=authentication_format
self.authentication_type=authentication_type
self.domain_type = self.SUB self.domain_type = self.SUB
self.gpg_key = gpg_key self.gpg_key = gpg_key
self.setGidGenerator(None) self.setGidGenerator(gid_generator)
self.setIdGenerator(None) self.setSynchronizationIdGenerator(id_generator)
self.setConduit(conduit) self.setConduit(conduit)
Folder.__init__(self, id) Folder.__init__(self, id)
self.title = title self.title = title
...@@ -715,7 +715,7 @@ class Subscription(Folder, SyncCode): ...@@ -715,7 +715,7 @@ class Subscription(Folder, SyncCode):
def setXMLMapping(self, value): def setXMLMapping(self, value):
""" """
this the name of the method used in order to get the xml this the name of the method used in order to set the xml
""" """
if value == '': if value == '':
value = None value = None
...@@ -884,6 +884,20 @@ class Subscription(Folder, SyncCode): ...@@ -884,6 +884,20 @@ class Subscription(Folder, SyncCode):
""" """
return self.gid_generator return self.gid_generator
def getFlowType(self):
"""
This method return the type of the data within the xml message :
- text for VCard's
- xml for others
"""
return getattr(self, 'flow_type', 'xml')
def setFlowType(self, flow_type):
"""
set the flow type (xml or text)
"""
self.flow_type=flow_type
def getLogin(self): def getLogin(self):
""" """
This method return the login of this subscription This method return the login of this subscription
...@@ -954,7 +968,7 @@ class Subscription(Folder, SyncCode): ...@@ -954,7 +968,7 @@ class Subscription(Folder, SyncCode):
# It might be a script python # It might be a script python
generator = getattr(object,gid_gen) generator = getattr(object,gid_gen)
o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant
# LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid)) LOG('getGidFromObject',0,'o_gid: %s' % repr(o_gid))
return o_gid return o_gid
def getObjectFromGid(self, gid): def getObjectFromGid(self, gid):
...@@ -1018,10 +1032,7 @@ class Subscription(Folder, SyncCode): ...@@ -1018,10 +1032,7 @@ class Subscription(Folder, SyncCode):
""" """
This tries to generate a new Id This tries to generate a new Id
""" """
# LOG('generateNewId, object: ',0,object.getPhysicalPath()) id_generator = self.getSynchronizationIdGenerator()
id_generator = self.getIdGenerator()
# LOG('generateNewId, id_generator: ',0,id_generator)
# LOG('generateNewId, portal_object: ',0,object.getPortalObject())
if id_generator is not None: if id_generator is not None:
o_base = aq_base(object) o_base = aq_base(object)
new_id = None new_id = None
...@@ -1038,20 +1049,20 @@ class Subscription(Folder, SyncCode): ...@@ -1038,20 +1049,20 @@ class Subscription(Folder, SyncCode):
return new_id return new_id
return None return None
def setIdGenerator(self, method): def setSynchronizationIdGenerator(self, method):
""" """
This set the method name wich allows to generate This set the method name wich allows to generate
a new id a new id
""" """
if method in ('','None'): if method in ('','None'):
method = None method = None
self.id_generator = method self.synchronization_id_generator = method
def getIdGenerator(self): def getSynchronizationIdGenerator(self):
""" """
This get the method name wich allows to generate a new id This get the method name wich allows to generate a new id
""" """
return self.id_generator return getattr(self, 'synchronization_id_generator', None)
def getSubscriptionUrl(self): def getSubscriptionUrl(self):
""" """
...@@ -1185,7 +1196,7 @@ class Subscription(Folder, SyncCode): ...@@ -1185,7 +1196,7 @@ class Subscription(Folder, SyncCode):
""" """
if signature.getGid() in self.objectIds(): if signature.getGid() in self.objectIds():
self._delObject(signature.getGid()) self._delObject(signature.getGid())
self._setObject( signature.getGid(), aq_base(signature) ) self._setObject(signature.getGid(), aq_base(signature) )
def delSignature(self, gid): def delSignature(self, gid):
""" """
...@@ -1321,7 +1332,7 @@ class Subscription(Folder, SyncCode): ...@@ -1321,7 +1332,7 @@ class Subscription(Folder, SyncCode):
#elif format is .... put here the other formats #elif format is .... put here the other formats
else:#if there is no format corresponding with format, raise an error else:#if there is no format corresponding with format, raise an error
LOG('encode : unknown or not implemented format :', 0, format) LOG('encode : unknown or not implemented format :', 0, format)
raise ValueError, "Sorry, the format %s is unknow or not implemented" % format raise ValueError, "Sorry, the server ask for the format %s but it's unknow or not implemented" % format
def decode(self, format, string_to_decode): def decode(self, format, string_to_decode):
""" """
......
...@@ -28,9 +28,7 @@ ...@@ -28,9 +28,7 @@
import smtplib # to send emails import smtplib # to send emails
from Subscription import Subscription,Signature from Subscription import Subscription,Signature
from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml from Ft.Xml import Parse
from xml.dom.minidom import parse, parseString
from xml.dom.ext import PrettyPrint
from XMLSyncUtils import XMLSyncUtils from XMLSyncUtils import XMLSyncUtils
import commands import commands
from Conduit.ERP5Conduit import ERP5Conduit from Conduit.ERP5Conduit import ERP5Conduit
...@@ -99,13 +97,21 @@ class SubscriptionSynchronization(XMLSyncUtils): ...@@ -99,13 +97,21 @@ class SubscriptionSynchronization(XMLSyncUtils):
else: else:
xml_client = msg xml_client = msg
if isinstance(xml_client, str) or isinstance(xml_client, unicode): if isinstance(xml_client, str) or isinstance(xml_client, unicode):
xml_client = parseString(xml_client) xml_client = Parse(xml_client)
next_status = self.getNextSyncBodyStatus(xml_client, None) next_status = self.getNextSyncBodyStatus(xml_client, None)
#LOG('readResponse, next status :',0,next_status) #LOG('readResponse, next status :',0,next_status)
if next_status is not None: if next_status is not None:
status_code = self.getStatusCode(next_status) status_code = self.getStatusCode(next_status)
#LOG('readResponse status code :',0,status_code) #LOG('readResponse status code :',0,status_code)
if status_code == self.AUTH_REQUIRED: if status_code == self.AUTH_REQUIRED:
if self.checkChal(xml_client):
authentication_format, authentication_type = self.getChal(xml_client)
subscription.setAuthenticationFormat(authentication_format)
subscription.setAuthenticationType(authentication_type)
else:
raise ValueError, "Sorry, the server chalenge for an \
authentication, but the authentication format is not find"
#LOG('readResponse', 0, 'Authentication required') #LOG('readResponse', 0, 'Authentication required')
response = self.SubSyncCred(id, xml_client) response = self.SubSyncCred(id, xml_client)
elif status_code == self.UNAUTHORIZED: elif status_code == self.UNAUTHORIZED:
......
...@@ -40,8 +40,7 @@ from Products.ERP5SyncML import Conduit ...@@ -40,8 +40,7 @@ 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,Signature from Subscription import Subscription,Signature
from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml from Ft.Xml import Parse
from xml.dom.minidom import parse, parseString
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
...@@ -50,7 +49,6 @@ from AccessControl.SecurityManagement import newSecurityManager ...@@ -50,7 +49,6 @@ from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import noSecurityManager from AccessControl.SecurityManagement import noSecurityManager
from AccessControl.User import UnrestrictedUser from AccessControl.User import UnrestrictedUser
from Acquisition import aq_base from Acquisition import aq_base
from xml.parsers.expat import ExpatError # parseString error
import urllib import urllib
import urllib2 import urllib2
import socket import socket
...@@ -162,8 +160,10 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -162,8 +160,10 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'manage_addPublication') 'manage_addPublication')
def manage_addPublication(self, title, publication_url, destination_path, def manage_addPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, auth_required=0, query, xml_mapping, conduit, gpg_key,
authentication_format='', authentication_type='', RESPONSE=None): synchronization_id_generator=None, gid_generator=None,
flow_type='xml', auth_required=0, authentication_format='',
authentication_type='', RESPONSE=None):
""" """
create a new publication create a new publication
""" """
...@@ -173,8 +173,9 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -173,8 +173,9 @@ class SynchronizationTool( SubscriptionSynchronization,
folder = self.getObjectContainer() folder = self.getObjectContainer()
new_id = self.getPublicationIdFromTitle(title) new_id = self.getPublicationIdFromTitle(title)
pub = Publication(new_id, title, publication_url, destination_path, pub = Publication(new_id, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, auth_required, query, xml_mapping, conduit, gpg_key,
authentication_format, authentication_type) synchronization_id_generator, gid_generator, flow_type,
auth_required, authentication_format, authentication_type)
folder._setObject( new_id, pub ) folder._setObject( new_id, pub )
#if len(self.list_publications) == 0: #if len(self.list_publications) == 0:
# self.list_publications = PersistentMapping() # self.list_publications = PersistentMapping()
...@@ -186,8 +187,9 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -186,8 +187,9 @@ class SynchronizationTool( SubscriptionSynchronization,
'manage_addSubscription') 'manage_addSubscription')
def manage_addSubscription(self, title, publication_url, subscription_url, def manage_addSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key, destination_path, query, xml_mapping, conduit, gpg_key,
login=None, password=None, authentication_format='', synchronization_id_generator=None, gid_generator=None,
authentication_type='',RESPONSE=None): flow_type='xml', login=None, password=None,
RESPONSE=None):
""" """
XXX should be renamed as addSubscription XXX should be renamed as addSubscription
create a new subscription create a new subscription
...@@ -199,8 +201,8 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -199,8 +201,8 @@ class SynchronizationTool( SubscriptionSynchronization,
new_id = self.getSubscriptionIdFromTitle(title) new_id = self.getSubscriptionIdFromTitle(title)
sub = Subscription(new_id, title, publication_url, subscription_url, sub = Subscription(new_id, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key, destination_path, query, xml_mapping, conduit, gpg_key,
login, password, authentication_format, synchronization_id_generator, gid_generator, flow_type,
authentication_type) login, password)
folder._setObject( new_id, sub ) folder._setObject( new_id, sub )
#if len(self.list_subscriptions) == 0: #if len(self.list_subscriptions) == 0:
# self.list_subscriptions = PersistentMapping() # self.list_subscriptions = PersistentMapping()
...@@ -211,9 +213,11 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -211,9 +213,11 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'manage_editPublication') 'manage_editPublication')
def manage_editPublication(self, title, publication_url, destination_path, def manage_editPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, id_generator, query, xml_mapping, conduit, gpg_key,
gid_generator, auth_required=0, authentication_format='', synchronization_id_generator, gid_generator,
authentication_type='', RESPONSE=None): flow_type='xml', auth_required=0,
authentication_format='', authentication_type='',
RESPONSE=None):
""" """
modify a publication modify a publication
""" """
...@@ -225,8 +229,9 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -225,8 +229,9 @@ class SynchronizationTool( SubscriptionSynchronization,
pub.setConduit(conduit) pub.setConduit(conduit)
pub.setXMLMapping(xml_mapping) pub.setXMLMapping(xml_mapping)
pub.setGPGKey(gpg_key) pub.setGPGKey(gpg_key)
pub.setIdGenerator(id_generator) pub.setSynchronizationIdGenerator(synchronization_id_generator)
pub.setGidGenerator(gid_generator) pub.setGidGenerator(gid_generator)
pub.setFlowType(flow_type)
pub.setAuthentication(auth_required) pub.setAuthentication(auth_required)
pub.setAuthenticationFormat(authentication_format) pub.setAuthenticationFormat(authentication_format)
pub.setAuthenticationType(authentication_type) pub.setAuthenticationType(authentication_type)
...@@ -237,9 +242,9 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -237,9 +242,9 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent, security.declareProtected(Permissions.ModifyPortalContent,
'manage_editSubscription') 'manage_editSubscription')
def manage_editSubscription(self, title, publication_url, subscription_url, def manage_editSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key, id_generator, destination_path, query, xml_mapping, conduit, gpg_key,
gid_generator,login='', password='', authentication_format='', synchronization_id_generator, gid_generator, flow_type='xml', login='',
authentication_type='', RESPONSE=None): password='', RESPONSE=None):
""" """
modify a subscription modify a subscription
""" """
...@@ -252,12 +257,11 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -252,12 +257,11 @@ class SynchronizationTool( SubscriptionSynchronization,
sub.setXMLMapping(xml_mapping) sub.setXMLMapping(xml_mapping)
sub.setGPGKey(gpg_key) sub.setGPGKey(gpg_key)
sub.setSubscriptionUrl(subscription_url) sub.setSubscriptionUrl(subscription_url)
sub.setIdGenerator(id_generator) sub.setSynchronizationIdGenerator(synchronization_id_generator)
sub.setGidGenerator(gid_generator) sub.setGidGenerator(gid_generator)
sub.setFlowType(flow_type)
sub.setLogin(login) sub.setLogin(login)
sub.setPassword(password) sub.setPassword(password)
sub.setAuthenticationFormat(authentication_format)
sub.setAuthenticationType(authentication_type)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
...@@ -613,6 +617,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -613,6 +617,7 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getSubscriberDocumentPath') 'getSubscriberDocumentPath')
def getSubscriberDocumentPath(self, conflict): def getSubscriberDocumentPath(self, conflict):
""" """
apply the publisher value for all conflict of the given document apply the publisher value for all conflict of the given document
...@@ -974,7 +979,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -974,7 +979,7 @@ class SynchronizationTool( SubscriptionSynchronization,
commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename) commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename)
# Get the target and then find the corresponding publication or # Get the target and then find the corresponding publication or
# Subscription # Subscription
xml = parseString(text) xml = Parse(text)
#XXX this function is not very optimized and should be improved #XXX this function is not very optimized and should be improved
url = self.getTarget(xml) url = self.getTarget(xml)
for publication in self.getPublicationList(): for publication in self.getPublicationList():
......
...@@ -29,8 +29,7 @@ ...@@ -29,8 +29,7 @@
import smtplib 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 xml.dom.ext.reader.Sax2 import FromXml from Ft.Xml import Parse
from xml.dom.minidom import parse, parseString
from DateTime import DateTime from DateTime import DateTime
from cStringIO import StringIO from cStringIO import StringIO
from xml.dom.ext import PrettyPrint from xml.dom.ext import PrettyPrint
...@@ -200,7 +199,9 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -200,7 +199,9 @@ class XMLSyncUtilsMixin(SyncCode):
xml = xml_list.append xml = xml_list.append
xml(' <Add>\n') xml(' <Add>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id) xml(' <CmdID>%s</CmdID>\n' % cmd_id)
xml(' <Meta><Type>%s</Type></Meta>\n' % object.portal_type) xml(' <Meta>\n')
xml(' <Type>%s</Type>\n' % object.portal_type)
xml(' </Meta>\n')
xml(' <Item>\n') xml(' <Item>\n')
xml(' <Source>\n') xml(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % gid) xml(' <LocURI>%s</LocURI>\n' % gid)
...@@ -227,8 +228,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -227,8 +228,8 @@ class XMLSyncUtilsMixin(SyncCode):
xml(' <Source>\n') xml(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % object_gid) xml(' <LocURI>%s</LocURI>\n' % object_gid)
xml(' </Source>\n') xml(' </Source>\n')
xml(' <Data>\n') #xml(' <Data>\n') #this 2 lines seems to be useless
xml(' </Data>\n') #xml(' </Data>\n')
xml(' </Item>\n') xml(' </Item>\n')
xml(' </Delete>\n') xml(' </Delete>\n')
xml_a = ''.join(xml_list) xml_a = ''.join(xml_list)
...@@ -243,7 +244,9 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -243,7 +244,9 @@ class XMLSyncUtilsMixin(SyncCode):
xml = xml_list.append xml = xml_list.append
xml(' <Replace>\n') xml(' <Replace>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id) xml(' <CmdID>%s</CmdID>\n' % cmd_id)
xml(' <Meta><Type>%s</Type></Meta>\n' % object.portal_type) xml(' <Meta>\n')
xml(' <Type>%s</Type>\n' % object.portal_type)
xml(' </Meta>\n')
xml(' <Item>\n') xml(' <Item>\n')
xml(' <Source>\n') xml(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % str(gid)) xml(' <LocURI>%s</LocURI>\n' % str(gid))
...@@ -290,10 +293,13 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -290,10 +293,13 @@ class XMLSyncUtilsMixin(SyncCode):
if xml_mapping is not None: if xml_mapping is not None:
if hasattr(object,xml_mapping): if hasattr(object,xml_mapping):
xml_method = getattr(object,xml_mapping) xml_method = getattr(object,xml_mapping)
elif hasattr(object,'manage_FTPget'): #elif hasattr(object,'manage_FTPget'):
xml_method = getattr(object,'manage_FTPget') # xml_method = getattr(object,'manage_FTPget')
if xml_method is not None: if xml_method is not None:
xml = xml_method() xml = xml_method()
else:
raise ValueError, "Sorry the script or method was not found"
LOG('getXMLObject', 0, 'xml_mapping:%s, xml:%s, object:%s xml_method:%s' % (xml_mapping, xml, object, xml_method))
return xml return xml
def getSessionId(self, xml): def getSessionId(self, xml):
...@@ -301,28 +307,17 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -301,28 +307,17 @@ class XMLSyncUtilsMixin(SyncCode):
We will retrieve the session id of the message We will retrieve the session id of the message
""" """
session_id = 0 session_id = 0
for subnode in self.getElementNodeList(xml): session_id = xml.xpath('string(/SyncML/SyncHdr/SessionID)')
if subnode.nodeName == 'SyncML': session_id = int(session_id)
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName == 'SyncHdr':
for subnode2 in self.getElementNodeList(subnode1):
if subnode2.nodeName == 'SessionID':
session_id = int(subnode2.childNodes[0].data)
return session_id return session_id
def getMessageId(self, xml): def getMessageId(self, xml):
""" """
We will retrieve the message id of the message We will retrieve the message id of the message
""" """
message_id = 0 message_id = 0
for subnode in self.getElementNodeList(xml): message_id = xml.xpath('string(/SyncML/SyncHdr/MsgID)')
if subnode.nodeName == 'SyncML': message_id = int(message_id)
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName == 'SyncHdr':
for subnode2 in self.getElementNodeList(subnode1):
if subnode2.nodeName == 'MsgID':
message_id = int(subnode2.childNodes[0].data)
return message_id return message_id
def getTarget(self, xml): def getTarget(self, xml):
...@@ -330,18 +325,10 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -330,18 +325,10 @@ class XMLSyncUtilsMixin(SyncCode):
return the target in the SyncHdr section return the target in the SyncHdr section
""" """
url = '' url = ''
for subnode in self.getElementNodeList(xml): url = xml.xpath('string(/SyncML/SyncHdr/Target/LocURI)')
if subnode.nodeName == 'SyncML': url = url.encode('utf-8')
for subnode1 in self.getElementNodeList(subnode):
if subnode1.nodeName == 'SyncHdr':
for subnode2 in self.getElementNodeList(subnode1):
if subnode2.nodeName == 'Target':
for subnode3 in self.getElementNodeList(subnode2):
if subnode3.nodeName == 'LocURI':
url = subnode3.childNodes[0].data
return url 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
...@@ -351,23 +338,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -351,23 +338,8 @@ class XMLSyncUtilsMixin(SyncCode):
# Get informations from the body # Get informations from the body
client_body = first_node.childNodes[3] client_body = first_node.childNodes[3]
for subnode in client_body.childNodes: last_anchor = client_body.xpath('string(/Alert/Item/Meta/Anchor/Last)')
if subnode.nodeType == subnode.ELEMENT_NODE and \ last_anchor = last_anchor.encode('utf-8')
subnode.nodeName == "Alert":
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == "Item":
for subnode3 in subnode2.childNodes:
if subnode3.nodeType == subnode3.ELEMENT_NODE and \
subnode3.nodeName == "Meta":
for subnode4 in subnode3.childNodes:
if subnode4.nodeType == subnode4.ELEMENT_NODE and \
subnode4.nodeName == "Anchor":
for subnode5 in subnode4.childNodes:
# Get the last time we had a synchronization
if subnode5.nodeType == subnode5.ELEMENT_NODE and \
subnode5.nodeName == "Last":
last_anchor = subnode5.childNodes[0].data
return last_anchor return last_anchor
def getAlertNextAnchor(self, xml_stream): def getAlertNextAnchor(self, xml_stream):
...@@ -381,60 +353,32 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -381,60 +353,32 @@ class XMLSyncUtilsMixin(SyncCode):
# Get informations from the body # Get informations from the body
client_body = first_node.childNodes[3] client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody": next_anchor = client_body.xpath('string(/Alert/Item/Meta/Anchor/Next)')
print "This is not a SyncML Body" next_anchor = next_anchor.encode('utf-8')
for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == "Alert":
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == "Item":
for subnode3 in subnode2.childNodes:
if subnode3.nodeType == subnode3.ELEMENT_NODE and \
subnode3.nodeName == "Meta":
for subnode4 in subnode3.childNodes:
if subnode4.nodeType == subnode4.ELEMENT_NODE and \
subnode4.nodeName == "Anchor":
for subnode5 in subnode4.childNodes:
# Get the last time we had a synchronization
if subnode5.nodeType == subnode5.ELEMENT_NODE and \
subnode5.nodeName == "Next":
next_anchor = subnode5.childNodes[0].data
return next_anchor return next_anchor
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
""" """
# Get informations from the body return xml.xpath('string(TargetRef)')
if xml.nodeName=='Status':
for subnode in xml.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == 'TargetRef':
return subnode.childNodes[0].data
return None
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
""" """
# Get informations from the body status_code = xml.xpath('string(Data)')
if xml.nodeName=='Status': if status_code not in ('', None, []):
for subnode in xml.childNodes: return int(status_code)
if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == 'Data':
return int(subnode.childNodes[0].data)
return None return None
def getStatusCommand(self, xml): def getStatusCommand(self, xml):
""" """
Return the value of the command inside the xml_stream Return the value of the command inside the xml_stream
""" """
# Get informations from the body
if xml.nodeName=='Status': if xml.nodeName=='Status':
for subnode in xml.childNodes: return xml.xpath('string(//Status/Cmd)')
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Cmd': else:
return subnode.childNodes[0].data
return None return None
def getCred(self, xml): def getCred(self, xml):
...@@ -445,110 +389,83 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -445,110 +389,83 @@ class XMLSyncUtilsMixin(SyncCode):
type='' type=''
data='' data=''
first_node = xml.childNodes[0] first_node = xml.childNodes[0]
if first_node.nodeName != "SyncML": format = first_node.xpath('string(/SyncML/SyncHdr/Cred/Meta/Format)')
print "This is not a SyncML message" type = first_node.xpath('string(/SyncML/SyncHdr/Cred/Meta/Type)')
# Get informations from the header data = first_node.xpath('string(/SyncML/SyncHdr/Cred/Data)')
xml_header = first_node.childNodes[1]
if xml_header.nodeName != "SyncHdr":
LOG('PubSyncModif',0,'This is not a SyncML Header')
raise ValueError, "Sorry, This is not a SyncML Header"
for subnode in xml_header.childNodes: format = format.encode('utf-8')
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName=='Cred': type = type.encode('utf-8')
for subnode2 in subnode.childNodes: data = data.encode('utf-8')
if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == 'Meta':
for subnode3 in subnode2.childNodes:
if subnode3.nodeType == subnode3.ELEMENT_NODE and \
subnode3.nodeName == 'Format':
if len(subnode3.childNodes) > 0:
format=subnode3.childNodes[0].data
if subnode3.nodeType == subnode3.ELEMENT_NODE and \
subnode3.nodeName == 'Type':
if len(subnode3.childNodes) > 0:
type=subnode3.childNodes[0].data
if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == 'Data':
if len(subnode2.childNodes) > 0:
data=subnode2.childNodes[0].data
return (format, type, data) return (format, type, data)
def getAlertCode(self, xml_stream): def checkCred(self, xml_stream):
""" """
Return the value of the alert code inside the full syncml message Check if there's a Cred section in the xml_stream
""" """
# Get informations from the body if xml_stream.xpath('string(SyncML/SyncHdr/Cred)') not in ('', None, []):
first_node = xml_stream.childNodes[0] return True
client_body = first_node.childNodes[3] return False
if client_body.nodeName != "SyncBody":
LOG('XMLSyncUtils.getAlertCode',0,"This is not a SyncML Body")
raise ValueError, "Sorry, This is not a SyncML Body"
alert = 0
for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName=='Alert':
for subnode1 in subnode.childNodes:
if subnode1.nodeType == subnode1.ELEMENT_NODE and subnode1.nodeName == 'Data':
return int(subnode1.childNodes[0].data)
return None
def checkCred(self, xml_stream): def getChal(self, xml):
""" """
Check if there's a Cred section in the xml_stream return the chalenge information : format and type
""" """
first_node = xml_stream.childNodes[0] format=''
# Get informations from the header type=''
xml_header = first_node.childNodes[1]
if xml_header.nodeName != "SyncHdr": first_node = xml.childNodes[0]
LOG('PubSyncModif',0,'This is not a SyncML Header') format = first_node.xpath('string(/SyncML/SyncBody/Status/Chal/Meta/Format)')
raise ValueError, "Sorry, This is not a SyncML Header" type = first_node.xpath('string(/SyncML/SyncBody/Status/Chal/Meta/Type)')
cred = 0
for subnode in xml_header.childNodes: format = format.encode('utf-8')
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Cred": type = type.encode('utf-8')
cred=1 return (format, type)
return cred
def checkChal(self, xml_stream):
"""
Check if there's a Chal section in the xml_stream
"""
if xml_stream.xpath('string(SyncML/SyncBody/Status/Chal)') \
not in ('', None, []):
return True
return False
def getAlertCode(self, xml_stream):
"""
Return the value of the alert code inside the full syncml message
"""
alert_code = xml_stream.xpath('string(SyncML/SyncBody/Alert/Data)')
if alert_code not in (None, ''):
return int(alert_code)
else:
return None
def checkAlert(self, xml_stream): def checkAlert(self, xml_stream):
""" """
Check if there's an Alert section in the xml_stream Check if there's an Alert section in the xml_stream
""" """
first_node = xml_stream.childNodes[0] alert = False
client_body = first_node.childNodes[3] if xml_stream.xpath('string(SyncML/SyncBody/Alert)') not in ('', None, []):
if client_body.nodeName != "SyncBody": alert = True
print "This is not a SyncML Body"
alert = 0
for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Alert":
alert = 1
return alert return 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
""" """
first_node = xml_stream.childNodes[0] sync = False
client_body = first_node.childNodes[3] if xml_stream.xpath('string(SyncML/SyncBody/Sync)') not in ('', None, []):
if client_body.nodeName != "SyncBody": sync = True
LOG('checkSync',0,"This is not a SyncML Body") return sync
raise ValueError, "Sorry, This is not a SyncML Body"
for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Sync":
return 1
return 0
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
""" """
first_node = xml_stream.childNodes[0] status = False
client_body = first_node.childNodes[3] if xml_stream.xpath('string(SyncML/SyncBody/Status)') not in ('', None, []):
if client_body.nodeName != "SyncBody": status = True
print "This is not a SyncML Body"
status = None
for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Status":
status = "1"
return status return status
def getNextSyncAction(self, xml_stream, last_action): def getNextSyncAction(self, xml_stream, last_action):
...@@ -563,18 +480,22 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -563,18 +480,22 @@ class XMLSyncUtilsMixin(SyncCode):
print "This is not a SyncML Body" print "This is not a SyncML Body"
next_action = None next_action = None
for subnode in client_body.childNodes: for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Sync": if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == "Sync":
# if we didn't use this method before # if we didn't use this method before
if last_action == None and len(subnode.childNodes) > 1: if last_action == None and len(subnode.childNodes) > 1:
next_action = subnode.childNodes[1] next_action = subnode.childNodes[1]
else: else:
found = None found = None
for subnode2 in subnode.childNodes: for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode.ELEMENT_NODE and subnode2 != last_action and found is None: if subnode2.nodeType == subnode.ELEMENT_NODE and \
subnode2 != last_action and found is None:
pass pass
elif subnode2.nodeType == subnode.ELEMENT_NODE and subnode2 == last_action and found is None: elif subnode2.nodeType == subnode.ELEMENT_NODE and \
subnode2 == last_action and found is None:
found = 1 found = 1
elif subnode2.nodeType == subnode.ELEMENT_NODE and found is not None: elif subnode2.nodeType == subnode.ELEMENT_NODE and \
found is not None:
next_action = subnode2 next_action = subnode2
break break
return next_action return next_action
...@@ -593,7 +514,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -593,7 +514,8 @@ class XMLSyncUtilsMixin(SyncCode):
next_status = None next_status = None
found = None found = None
for subnode in client_body.childNodes: for subnode in client_body.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Status": if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == "Status":
# if we didn't use this method before # if we didn't use this method before
if last_status == None: if last_status == None:
next_status = subnode next_status = subnode
...@@ -604,27 +526,32 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -604,27 +526,32 @@ class XMLSyncUtilsMixin(SyncCode):
return subnode return subnode
return next_status return next_status
def getDataText(self, action):
"""
return the section data in text form, it's usefull for the VCardConduit
"""
return action.xpath('string(Item/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
""" """
for subnode in action.childNodes: if action.xpath('Item/Data') not in ([], None):
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Item': data_node = action.xpath('Item/Data')[0]
for subnode2 in subnode.childNodes: if data_node.hasChildNodes() and data_node.childNodes.__len__()>1:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'Data': return data_node.childNodes[1]
for subnode3 in subnode2.childNodes: return None
#if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == 'object':
if subnode3.nodeType == subnode3.ELEMENT_NODE:
return subnode3
def getPartialData(self, action): def getPartialData(self, action):
""" """
Return the node starting with <object....> of the action Return the node starting with <object....> of the action
""" """
for subnode in action.childNodes: for subnode in action.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Item': if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == 'Item':
for subnode2 in subnode.childNodes: for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'Data': if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == 'Data':
for subnode3 in subnode2.childNodes: for subnode3 in subnode2.childNodes:
#if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == 'object': #if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == 'object':
if subnode3.nodeType == subnode3.COMMENT_NODE: if subnode3.nodeType == subnode3.COMMENT_NODE:
...@@ -639,60 +566,40 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -639,60 +566,40 @@ class XMLSyncUtilsMixin(SyncCode):
return None return None
def getAttributeNodeList(self, node):
"""
Return attributesNodes that are ElementNode XXX may be not needed at all
"""
subnode_list = []
for subnode in node.attributes:
if subnode.nodeType == subnode.ATTRIBUTE_NODE:
subnode_list += [subnode]
return subnode_list
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
""" """
for subnode in action.childNodes: for subnode in action.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Item': if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == 'Item':
for subnode2 in subnode.childNodes: for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'Source': if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == 'Source':
for subnode3 in subnode2.childNodes: for subnode3 in subnode2.childNodes:
if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == 'LocURI': if subnode3.nodeType == subnode3.ELEMENT_NODE and \
subnode3.nodeName == 'LocURI':
return str(subnode3.childNodes[0].data) return str(subnode3.childNodes[0].data)
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
""" """
for subnode in action.childNodes: if action.xpath('Item/MoreData') not in ([],None) :
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Item': return True
for subnode2 in subnode.childNodes: return False
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'MoreData':
return 1
return 0
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
""" """
for subnode in action.childNodes: return action.xpath('string(Meta/Type)')
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Meta':
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'Type':
return str(subnode2.childNodes[0].data)
def getElementNodeList(self, node): def getElementNodeList(self, node):
""" """
Return childNodes that are ElementNode Return childNodes that are ElementNode
""" """
#return node.getElementsByTagName('*') return node.xpath('*')
subnode_list = []
for subnode in node.childNodes or []:
if subnode.nodeType == subnode.ELEMENT_NODE:
subnode_list += [subnode]
return subnode_list
def getTextNodeList(self, node): def getTextNodeList(self, node):
""" """
...@@ -708,11 +615,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -708,11 +615,7 @@ class XMLSyncUtilsMixin(SyncCode):
""" """
Return childNodes that are ElementNode Return childNodes that are ElementNode
""" """
attribute_list = [] return node.xpath('@*')
for subnode in node.attributes.values() or []:
if subnode.nodeType == subnode.ATTRIBUTE_NODE:
attribute_list += [subnode]
return attribute_list
def getSyncMLData(self, domain=None,remote_xml=None,cmd_id=0, def getSyncMLData(self, domain=None,remote_xml=None,cmd_id=0,
subscriber=None,destination_path=None, subscriber=None,destination_path=None,
...@@ -730,7 +633,6 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -730,7 +633,6 @@ class XMLSyncUtilsMixin(SyncCode):
if subscriber.getRemainingObjectPathList() is None: if subscriber.getRemainingObjectPathList() is None:
object_list = domain.getObjectList() object_list = domain.getObjectList()
object_path_list = map(lambda x: x.getPhysicalPath(),object_list) object_path_list = map(lambda x: x.getPhysicalPath(),object_list)
LOG('getSyncMLData, object_path_list',0,object_path_list)
subscriber.setRemainingObjectPathList(object_path_list) subscriber.setRemainingObjectPathList(object_path_list)
#object_gid = domain.getGidFromObject(object) #object_gid = domain.getGidFromObject(object)
...@@ -744,10 +646,10 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -744,10 +646,10 @@ class XMLSyncUtilsMixin(SyncCode):
if signature.getStatus()!=self.PARTIAL: # If partial, then we have a signature if signature.getStatus()!=self.PARTIAL: # If partial, then we have a signature
# but no local object # but no local object
xml_object = signature.getXML() xml_object = signature.getXML()
if xml_object is not None: # This prevent to delete an object that we if xml_object is not None: # This prevent to delete an object that
# were not able to create # we were not able to create
syncml_data += self.deleteXMLObject(xml_object=signature.getXML() or '', syncml_data += self.deleteXMLObject(xml_object=signature.getXML()\
object_gid=object_gid,cmd_id=cmd_id) or '', object_gid=object_gid,cmd_id=cmd_id)
local_gid_list = [] local_gid_list = []
#for object in domain.getObjectList(): #for object in domain.getObjectList():
...@@ -765,14 +667,16 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -765,14 +667,16 @@ class XMLSyncUtilsMixin(SyncCode):
#if gid_generator is not None: #if gid_generator is not None:
# object_gid = gid_generator() # object_gid = gid_generator()
force = 0 force = 0
if syncml_data.count('\n') < self.MAX_LINES and not object.id.startswith('.'): # If not we have to cut if syncml_data.count('\n') < self.MAX_LINES and not \
object.id.startswith('.'): # If not we have to cut
#LOG('getSyncMLData',0,'xml_mapping: %s' % str(domain.xml_mapping)) #LOG('getSyncMLData',0,'xml_mapping: %s' % str(domain.xml_mapping))
#LOG('getSyncMLData', 0, 'FlowType: %s' % str(subscriber.getFlowType()))
#LOG('getSyncMLData',0,'code: %s' % str(self.getAlertCode(remote_xml))) #LOG('getSyncMLData',0,'code: %s' % str(self.getAlertCode(remote_xml)))
#LOG('getSyncMLData',0,'gid_list: %s' % str(local_gid_list)) #LOG('getSyncMLData',0,'gid_list: %s' % str(local_gid_list))
#LOG('getSyncMLData',0,'hasSignature: %s' % str(subscriber.hasSignature(object_gid))) #LOG('getSyncMLData',0,'hasSignature: %s' % str(subscriber.hasSignature(object_gid)))
#LOG('getSyncMLData',0,'alert_code == slowsync: %s' % str(self.getAlertCode(remote_xml)==self.SLOW_SYNC)) #LOG('getSyncMLData',0,'alert_code == slowsync: %s' % str(self.getAlertCode(remote_xml)==self.SLOW_SYNC))
signature = subscriber.getSignature(object_gid) signature = subscriber.getSignature(object_gid)
#LOG('getSyncMLData',0,'current object: %s' % str(object.getId()))
# 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:
signature.checkSynchronizationNeeded(object) signature.checkSynchronizationNeeded(object)
...@@ -781,11 +685,12 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -781,11 +685,12 @@ class XMLSyncUtilsMixin(SyncCode):
# 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()==None: if signature is not None and signature.getXMLMapping()==None:
pass pass
elif signature==None or (signature.getXML()==None and signature.getStatus()!=self.PARTIAL) or \ elif signature == None or (signature.getXML() == None and \
self.getAlertCode(remote_xml)==self.SLOW_SYNC: signature.getStatus() != self.PARTIAL) or \
self.getAlertCode(remote_xml) == self.SLOW_SYNC:
#LOG('PubSyncModif',0,'Current object.getPath: %s' % object.getPath()) #LOG('PubSyncModif',0,'Current object.getPath: %s' % object.getPath())
LOG('getSyncMLData',0,'no signature for gid: %s' % object_gid) xml_object = self.getXMLObject(object=object,
xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping) xml_mapping=domain.xml_mapping)
xml_string = xml_object xml_string = xml_object
signature = Signature(gid=object_gid,id=object.getId(),object=object) signature = Signature(gid=object_gid,id=object.getId(),object=object)
signature.setTempXML(xml_object) signature.setTempXML(xml_object)
...@@ -806,14 +711,15 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -806,14 +711,15 @@ class XMLSyncUtilsMixin(SyncCode):
status =self.PARTIAL status =self.PARTIAL
signature.setAction('Add') signature.setAction('Add')
xml_string = '<!--' + short_string + '-->' xml_string = '<!--' + short_string + '-->'
syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,gid=object_gid, syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,
xml_string=xml_string, more_data=more_data) gid=object_gid, xml_string=xml_string, more_data=more_data)
cmd_id += 1 cmd_id += 1
signature.setStatus(status) signature.setStatus(status)
subscriber.addSignature(signature) subscriber.addSignature(signature)
elif signature.getStatus()==self.NOT_SYNCHRONIZED \ elif signature.getStatus()==self.NOT_SYNCHRONIZED \
or signature.getStatus()==self.PUB_CONFLICT_MERGE: # We don't have synchronized this object yet or signature.getStatus()==self.PUB_CONFLICT_MERGE: # We don't have synchronized this object yet
xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping) xml_object = self.getXMLObject(object=object,
xml_mapping=domain.xml_mapping)
#LOG('getSyncMLData',0,'checkMD5: %s' % str(signature.checkMD5(xml_object))) #LOG('getSyncMLData',0,'checkMD5: %s' % str(signature.checkMD5(xml_object)))
#LOG('getSyncMLData',0,'getStatus: %s' % str(signature.getStatus())) #LOG('getSyncMLData',0,'getStatus: %s' % str(signature.getStatus()))
if signature.getStatus()==self.PUB_CONFLICT_MERGE: if signature.getStatus()==self.PUB_CONFLICT_MERGE:
...@@ -842,8 +748,11 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -842,8 +748,11 @@ class XMLSyncUtilsMixin(SyncCode):
signature.setAction('Replace') signature.setAction('Replace')
xml_string = '<!--' + short_string + '-->' xml_string = '<!--' + short_string + '-->'
signature.setStatus(status) signature.setStatus(status)
syncml_data += self.replaceXMLObject(cmd_id=cmd_id,object=object,gid=object_gid, if(subscriber.getFlowType() == 'text'):
xml_string=xml_string, more_data=more_data) xml_string = self.getXMLObject(object=object,
xml_mapping=domain.xml_mapping)
syncml_data += self.replaceXMLObject(cmd_id=cmd_id, object=object,
gid=object_gid, xml_string=xml_string, more_data=more_data)
cmd_id += 1 cmd_id += 1
signature.setTempXML(xml_object) signature.setTempXML(xml_object)
# Now we can apply the xupdate from the subscriber # Now we can apply the xupdate from the subscriber
...@@ -852,16 +761,16 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -852,16 +761,16 @@ class XMLSyncUtilsMixin(SyncCode):
if subscriber_xupdate is not None: if subscriber_xupdate is not None:
old_xml = signature.getXML() old_xml = signature.getXML()
conduit.updateNode(xml=subscriber_xupdate, object=object, conduit.updateNode(xml=subscriber_xupdate, object=object,
previous_xml=old_xml,force=(domain.getDomainType==self.SUB), previous_xml=old_xml, force=(domain.getDomainType==self.SUB),
simulate=0) simulate=0)
xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping) xml_object = self.getXMLObject(object=object,
xml_mapping=domain.xml_mapping)
signature.setTempXML(xml_object) signature.setTempXML(xml_object)
if set_synchronized: # We have to do that after this previous update if set_synchronized: # We have to do that after this previous update
# We should not have this case when we are in CONFLICT_MERGE # We should not have this case when we are in CONFLICT_MERGE
signature.setStatus(self.SYNCHRONIZED) signature.setStatus(self.SYNCHRONIZED)
elif signature.getStatus()==self.PUB_CONFLICT_CLIENT_WIN: elif signature.getStatus()==self.PUB_CONFLICT_CLIENT_WIN:
# We have decided to apply the update # We have decided to apply the update
LOG('getSyncMLData',0,'signature.getTempXML(): %s' % str(signature.getTempXML()))
# XXX previous_xml will be getXML instead of getTempXML because # XXX previous_xml will be getXML instead of getTempXML because
# some modification was already made and the update # some modification was already made and the update
# may not apply correctly # may not apply correctly
...@@ -889,12 +798,16 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -889,12 +798,16 @@ class XMLSyncUtilsMixin(SyncCode):
xml_string = xml_string.replace('--','@-@@-@') xml_string = xml_string.replace('--','@-@@-@')
xml_string = '<!--' + xml_string + '-->' xml_string = '<!--' + xml_string + '-->'
signature.setStatus(status) signature.setStatus(status)
if(subscriber.getFlowType() == 'text'):
xml_string = self.getXMLObject(object=object,
xml_mapping=domain.xml_mapping)
LOG('xml_string =', 0, xml_string)
if signature.getAction()=='Replace': if signature.getAction()=='Replace':
syncml_data += self.replaceXMLObject(cmd_id=cmd_id,object=object,gid=object_gid, syncml_data += self.replaceXMLObject(cmd_id=cmd_id, object=object,
xml_string=xml_string, more_data=more_data) gid=object_gid, xml_string=xml_string, more_data=more_data)
elif signature.getAction()=='Add': elif signature.getAction()=='Add':
syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,gid=object_gid, syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,
xml_string=xml_string, more_data=more_data) gid=object_gid, xml_string=xml_string, more_data=more_data)
return (syncml_data,xml_confirmation,cmd_id) return (syncml_data,xml_confirmation,cmd_id)
def applyActionList(self, domain=None, subscriber=None,destination_path=None, def applyActionList(self, domain=None, subscriber=None,destination_path=None,
...@@ -918,7 +831,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -918,7 +831,8 @@ class XMLSyncUtilsMixin(SyncCode):
object = domain.getObjectFromGid(object_gid) object = domain.getObjectFromGid(object_gid)
if signature == None: if signature == None:
LOG('applyActionList, signature is None',0,signature) LOG('applyActionList, signature is None',0,signature)
signature = Signature(gid=object_gid,status=self.NOT_SYNCHRONIZED,object=object).__of__(subscriber) signature = Signature(gid=object_gid, status=self.NOT_SYNCHRONIZED,
object=object).__of__(subscriber)
subscriber.addSignature(signature) subscriber.addSignature(signature)
force = signature.getForce() force = signature.getForce()
LOG('applyActionList',0,'object: %s' % repr(object)) LOG('applyActionList',0,'object: %s' % repr(object))
...@@ -932,9 +846,13 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -932,9 +846,13 @@ class XMLSyncUtilsMixin(SyncCode):
data_subnode = partial_data data_subnode = partial_data
LOG('SyncModif',0,'data_subnode: %s' % data_subnode) LOG('SyncModif',0,'data_subnode: %s' % data_subnode)
#data_subnode = FromXml(data_subnode) #data_subnode = FromXml(data_subnode)
data_subnode = parseString(data_subnode) if subscriber.getFlowType() == 'xml':
data_subnode = Parse(data_subnode)
data_subnode = data_subnode.childNodes[0] # Because we just created a new xml 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 # document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
else:
if subscriber.getFlowType() == 'text':
data_subnode = self.getDataText(next_action)
else: else:
data_subnode = self.getDataSubNode(next_action) data_subnode = self.getDataSubNode(next_action)
if next_action.nodeName == 'Add': if next_action.nodeName == 'Add':
...@@ -942,12 +860,14 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -942,12 +860,14 @@ class XMLSyncUtilsMixin(SyncCode):
if object is None: if object is None:
object_id = domain.generateNewIdWithGenerator(object=destination_path,gid=object_gid) object_id = domain.generateNewIdWithGenerator(object=destination_path,gid=object_gid)
#if object_id is not None: #if object_id is not None:
add_data = conduit.addNode(xml=data_subnode, object=destination_path, add_data = conduit.addNode(xml=data_subnode,
object_id=object_id) object=destination_path, object_id=object_id)
if add_data['conflict_list'] not in ('', None, []):
conflict_list += 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']
LOG('XMLSyncUtils, in ADD add_data',0,add_data) LOG('XMLSyncUtils, in ADD add_data',0,add_data)
signature.setPath(object.getPhysicalPath())
LOG('applyActionList',0,'object after add: %s' % repr(object)) LOG('applyActionList',0,'object after add: %s' % repr(object))
else: else:
#Object was retrieve but need to be updated without recreated #Object was retrieve but need to be updated without recreated
...@@ -957,6 +877,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -957,6 +877,7 @@ class XMLSyncUtilsMixin(SyncCode):
object=destination_path, object=destination_path,
object_id=object_id, object_id=object_id,
sub_object=object) sub_object=object)
if add_data['conflict_list'] not in ('', None, []):
conflict_list += add_data['conflict_list'] conflict_list += add_data['conflict_list']
if object is not None: if object is not None:
LOG('SyncModif',0,'addNode, found the object') LOG('SyncModif',0,'addNode, found the object')
...@@ -990,7 +911,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -990,7 +911,8 @@ class XMLSyncUtilsMixin(SyncCode):
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()+conflict_list) signature.setConflictList(signature.getConflictList() \
+ conflict_list)
string_io = StringIO() string_io = StringIO()
PrettyPrint(data_subnode,stream=string_io) PrettyPrint(data_subnode,stream=string_io)
data_subnode_string = string_io.getvalue() data_subnode_string = string_io.getvalue()
...@@ -1012,7 +934,11 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1012,7 +934,11 @@ class XMLSyncUtilsMixin(SyncCode):
elif next_action.nodeName == 'Delete': elif next_action.nodeName == 'Delete':
object_id = signature.getId() object_id = signature.getId()
conduit.deleteNode(xml=self.getDataSubNode(next_action), object=destination_path, if subscriber.getFlowType == 'text':
data_subnode = self.getDataText(next_action)
else:
data_subnode = self.getDataSubNode(next_action)
conduit.deleteNode(xml=data_subnode, object=destination_path,
object_id=object_id) object_id=object_id)
subscriber.delSignature(object_gid) subscriber.delSignature(object_gid)
xml_confirmation += self.SyncMLConfirmation(cmd_id, xml_confirmation += self.SyncMLConfirmation(cmd_id,
...@@ -1026,8 +952,8 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1026,8 +952,8 @@ class XMLSyncUtilsMixin(SyncCode):
signature.setPartialXML(previous_partial) signature.setPartialXML(previous_partial)
#LOG('SyncModif',0,'previous_partial: %s' % str(previous_partial)) #LOG('SyncModif',0,'previous_partial: %s' % str(previous_partial))
LOG('SyncModif',0,'waiting more data for :%s' % signature.getId()) LOG('SyncModif',0,'waiting more data for :%s' % signature.getId())
xml_confirmation += self.SyncMLConfirmation(cmd_id,object_gid, xml_confirmation += self.SyncMLConfirmation(cmd_id, object_gid,
self.WAITING_DATA,next_action.nodeName) self.WAITING_DATA, next_action.nodeName)
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)
...@@ -1121,9 +1047,11 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1121,9 +1047,11 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
if domain.domain_type == self.PUB: if domain.domain_type == self.PUB:
simulate = 1 simulate = 1
for subnode in xml_header.childNodes: for subnode in xml_header.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Source": if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == "Source":
for subnode2 in subnode.childNodes: for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'LocURI': if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == 'LocURI':
subscription_url = str(subnode2.childNodes[0].data) subscription_url = str(subnode2.childNodes[0].data)
subscriber = domain.getSubscriber(subscription_url) subscriber = domain.getSubscriber(subscription_url)
...@@ -1134,6 +1062,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1134,6 +1062,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
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:',0,"sending again...") LOG('SyncModif, no correct message:',0,"sending again...")
last_xml = subscriber.getLastSentMessage() last_xml = subscriber.getLastSentMessage()
LOG("last_xml :", 0, last_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
...@@ -1142,7 +1071,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1142,7 +1071,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
xml=last_xml,domain=domain) xml=last_xml,domain=domain)
elif domain.domain_type == self.SUB: elif domain.domain_type == self.SUB:
self.sendResponse(from_url=domain.subscription_url, self.sendResponse(from_url=domain.subscription_url,
to_url=domain.publication_url, sync_id=domain.getTitle(), xml=last_xml,domain=domain) to_url=domain.publication_url, sync_id=domain.getTitle(),
xml=last_xml, domain=domain)
return {'has_response':has_response,'xml':last_xml} return {'has_response':has_response,'xml':last_xml}
subscriber.setLastSentMessage('') subscriber.setLastSentMessage('')
...@@ -1164,7 +1094,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1164,7 +1094,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
globals(), locals(), ['']) globals(), locals(), [''])
conduit = getattr(conduit_module, conduit_name)() conduit = getattr(conduit_module, conduit_name)()
# Then apply the list of actions # Then apply the list of actions
(xml_confirmation,has_next_action,cmd_id) = self.applyActionList(cmd_id=cmd_id, (xml_confirmation,has_next_action,cmd_id) = self.applyActionList(
cmd_id=cmd_id,
domain=domain, domain=domain,
destination_path=destination_path, destination_path=destination_path,
subscriber=subscriber, subscriber=subscriber,
...@@ -1178,8 +1109,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin): ...@@ -1178,8 +1109,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
# syncml header # syncml header
if domain.domain_type == self.PUB: if domain.domain_type == self.PUB:
xml(self.SyncMLHeader(subscriber.getSessionId(), subscriber.incrementMessageId(), xml(self.SyncMLHeader(subscriber.getSessionId(),
subscriber.getSubscriptionUrl(), domain.getPublicationUrl())) subscriber.incrementMessageId(), subscriber.getSubscriptionUrl(),
domain.getPublicationUrl()))
elif domain.domain_type == self.SUB: elif domain.domain_type == self.SUB:
xml(self.SyncMLHeader(domain.getSessionId(), domain.incrementMessageId(), xml(self.SyncMLHeader(domain.getSessionId(), domain.incrementMessageId(),
domain.getPublicationUrl(), domain.getSubscriptionUrl())) domain.getPublicationUrl(), domain.getSubscriptionUrl()))
......
...@@ -114,7 +114,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -114,7 +114,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id_generator" value="<dtml-var getIdGenerator>" size="40" /> <input type="text" name="synchronization_id_generator" value="<dtml-var getSynchronizationIdGenerator>" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -127,6 +127,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -127,6 +127,24 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" /> <input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" />
</td> </td>
</tr> </tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Flow Type
</label></div>
</td>
<td align="left" valign="top">
<SELECT name="flow_type" size="1">
<dtml-if expr="getFlowType() != 'text'">
<OPTION value="xml" selected>XML</option>
<OPTION value="text">text</option>
<dtml-else>
<OPTION value="xml">XML</option>
<OPTION value="text" selected>text</option>
</dtml-if>
</SELECT>
</td>
</tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
......
...@@ -124,7 +124,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -124,7 +124,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id_generator" value="<dtml-var getIdGenerator>" size="40" /> <input type="text" name="synchronization_id_generator" value="<dtml-var getSynchronizationIdGenerator>" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -140,41 +140,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -140,41 +140,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Login Flow Type
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="login" value="<dtml-var getLogin>" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Password
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="password" name="password" value="<dtml-var getPassword>" size="40" /> <SELECT name="flow_type" size="1">
<dtml-if expr="getFlowType() != 'text'">
<OPTION value="xml" selected>XML</option>
<OPTION value="text">text</option>
<dtml-else>
<OPTION value="xml">XML</option>
<OPTION value="text" selected>text</option>
</dtml-if>
</SELECT>
</td> </td>
</tr> </tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Format authentication Login
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="authentication_format" value="<dtml-var getAuthenticationFormat>" size="40" /> <input type="text" name="login" value="<dtml-var getLogin>" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Type authentication Password
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="authentication_type" value="<dtml-var getAuthenticationType>" size="40" /> <input type="password" name="password" value="<dtml-var getPassword>" size="40" />
</td> </td>
</tr> </tr>
</table> </table>
......
...@@ -110,7 +110,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -110,7 +110,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id_generator" size="40" /> <input type="text" name="synchronization_id_generator" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -123,6 +123,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -123,6 +123,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="gid_generator" size="40" /> <input type="text" name="gid_generator" size="40" />
</td> </td>
</tr> </tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Flow Type
</label></div>
</td>
<td align="left" valign="top">
<SELECT name="flow_type" size="1">
<OPTION value="xml" selected>XML</option>
<OPTION value="text">text</option>
</SELECT>
</td>
</tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
......
...@@ -120,7 +120,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -120,7 +120,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id_generator" size="40" /> <input type="text" name="synchronization_id_generator" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -136,39 +136,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -136,39 +136,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Login Flow Type
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="login" size="40" /> </td> <SELECT name="flow_type" size="1">
</tr> <OPTION value="xml" selected>XML</option>
<tr> <OPTION value="text">text</option>
<td align="left" valign="top"> </SELECT>
<div class="form-label">
Password
</label></div>
</td>
<td align="left" valign="top">
<input type="password" name="password" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Format authentication Login
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="authentication_format" size="40" /> <input type="text" name="login" size="40" /> </td>
</td>
</tr> </tr>
<tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Type authentication Password
</label></div> </label></div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="authentication_type" size="40" /> <input type="password" name="password" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
......
...@@ -46,10 +46,11 @@ try: ...@@ -46,10 +46,11 @@ try:
from base64 import b64encode, b64decode from base64 import b64encode, b64decode
except ImportError: except ImportError:
from base64 import encodestring as b64encode, decodestring as b64decode from base64 import encodestring as b64encode, decodestring as b64decode
class TestERP5SyncML(ERP5TypeTestCase):
class TestERP5SyncMLMixin:
# Different variables used for this test # Different variables used for this test
run_all_test = 1
workflow_id = 'edit_workflow' workflow_id = 'edit_workflow'
first_name1 = 'Sebastien' first_name1 = 'Sebastien'
last_name1 = 'Robin' last_name1 = 'Robin'
...@@ -91,10 +92,6 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -91,10 +92,6 @@ class TestERP5SyncML(ERP5TypeTestCase):
#subscription_url1 = 'client1@localhost' #subscription_url1 = 'client1@localhost'
#subscription_url2 = 'client2@localhost' #subscription_url2 = 'client2@localhost'
def getTitle(self):
"""
"""
return "ERP5 SyncML"
def afterSetUp(self): def afterSetUp(self):
"""Setup.""" """Setup."""
...@@ -117,7 +114,7 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -117,7 +114,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
/person_client1 : empty /person_client1 : empty
/person_client2 : empty /person_client2 : empty
""" """
return ('erp5_base',) return ('erp5_base','fabien_bt')
def getSynchronizationTool(self): def getSynchronizationTool(self):
return getattr(self.getPortal(), 'portal_synchronizations', None) return getattr(self.getPortal(), 'portal_synchronizations', None)
...@@ -134,6 +131,194 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -134,6 +131,194 @@ class TestERP5SyncML(ERP5TypeTestCase):
def getPortalId(self): def getPortalId(self):
return self.getPortal().getId() return self.getPortal().getId()
def login(self, quiet=0):
uf = self.getPortal().acl_users
uf._doAddUser('fab', 'myPassword', ['Manager'], [])
uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], [])
uf._doAddUser('syncml', '', ['Manager'], [])
user = uf.getUserById('fab').__of__(uf)
newSecurityManager(None, user)
def populatePersonServer(self, quiet=0, run=0):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Populate Person Server ')
LOG('Testing... ',0,'populatePersonServer')
self.login()
portal = self.getPortal()
if not hasattr(portal,'person_server'):
portal.portal_types.constructContent(type_name = 'Person Module',
container = portal,
id = 'person_server')
if not hasattr(portal,'person_client1'):
portal.portal_types.constructContent(type_name = 'Person Module',
container = portal,
id = 'person_client1')
if not hasattr(portal,'person_client2'):
portal.portal_types.constructContent(type_name = 'Person Module',
container = portal,
id = 'person_client2')
person_id = ''
person_server = self.getPersonServer()
person1 = person_server.newContent(id=self.id1,portal_type='Person')
kw = {'first_name':self.first_name1,'last_name':self.last_name1,
'description':self.description1}
person1.edit(**kw)
person2 = person_server.newContent(id=self.id2,portal_type='Person')
kw = {'first_name':self.first_name2,'last_name':self.last_name2,
'description':self.description2}
person2.edit(**kw)
nb_person = len(person_server.objectValues())
self.failUnless(nb_person==2)
return nb_person
def synchronize(self, id, run=1):
"""
This just define how we synchronize, we have
to define it here because it is specific to the unit testing
"""
portal_sync = self.getSynchronizationTool()
subscription = portal_sync.getSubscription(id)
publication = None
for publication in portal_sync.getPublicationList():
if publication.getPublicationUrl()==subscription.getSubscriptionUrl():
publication = publication
self.failUnless(publication is not None)
# reset files, because we do sync by files
file = open('/tmp/sync_client1','w')
file.write('')
file.close()
file = open('/tmp/sync_client2','w')
file.write('')
file.close()
file = open('/tmp/sync','w')
file.write('')
file.close()
nb_message = 1
result = portal_sync.SubSync(subscription.getTitle())
while result['has_response']==1:
portal_sync.PubSync(publication.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
nb_message += 1 + result['has_response']
return nb_message
def synchronizeWithBrokenMessage(self, id, run=1):
"""
This just define how we synchronize, we have
to define it here because it is specific to the unit testing
"""
portal_sync = self.getSynchronizationTool()
#portal_sync.email = None # XXX To be removed
subscription = portal_sync.getSubscription(id)
publication = None
for publication in portal_sync.getPublicationList():
if publication.getPublicationUrl()==subscription.getSubscriptionUrl():
publication = publication
self.failUnless(publication is not None)
# reset files, because we do sync by files
file = open('/tmp/sync_client1','w')
file.write('')
file.close()
file = open('/tmp/sync_client2','w')
file.write('')
file.close()
file = open('/tmp/sync','w')
file.write('')
file.close()
nb_message = 1
result = portal_sync.SubSync(subscription.getTitle())
while result['has_response']==1:
# We do thing three times, so that we will test
# if we manage well duplicate messages
portal_sync.PubSync(publication.getTitle())
portal_sync.PubSync(publication.getTitle())
portal_sync.PubSync(publication.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
nb_message += 1 + result['has_response']
return nb_message
def checkSynchronizationStateIsSynchronized(self, quiet=0, run=1):
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
for person in person_server.objectValues():
state_list = portal_sync.getSynchronizationState(person)
for state in state_list:
self.failUnless(state[1]==state[0].SYNCHRONIZED)
person_client1 = self.getPersonClient1()
for person in person_client1.objectValues():
state_list = portal_sync.getSynchronizationState(person)
for state in state_list:
self.failUnless(state[1]==state[0].SYNCHRONIZED)
person_client2 = self.getPersonClient2()
for person in person_client2.objectValues():
state_list = portal_sync.getSynchronizationState(person)
for state in state_list:
self.failUnless(state[1]==state[0].SYNCHRONIZED)
# Check for each signature that the tempXML is None
for sub in portal_sync.getSubscriptionList():
for m in sub.getSignatureList():
self.assertEquals(m.getTempXML(),None)
self.assertEquals(m.getPartialXML(),None)
for pub in portal_sync.getPublicationList():
for sub in pub.getSubscriberList():
for m in sub.getSignatureList():
self.assertEquals(m.getPartialXML(),None)
def verifyFirstNameAndLastNameAreSynchronized(self, first_name,
last_name, person_server, person_client):
"""
verify if the first and last name are synchronized
"""
self.failUnless(person_server.getFirstName()==first_name)
self.failUnless(person_server.getLastName()==last_name)
self.failUnless(person_client.getFirstName()==first_name)
self.failUnless(person_client.getLastName()==last_name)
def verifyFirstNameAndLastNameAreNotSynchronized(self, first_name,
last_name, person_server, person_client):
"""
verify that the first and last name are NOT synchronized
"""
self.failUnless(person_server.getFirstName()!=first_name)
self.failUnless(person_server.getLastName()!=last_name)
self.failUnless(person_client.getFirstName()==first_name)
self.failUnless(person_client.getLastName()==last_name)
def checkFirstSynchronization(self, id=None, nb_person=0):
portal_sync = self.getSynchronizationTool()
subscription1 = portal_sync.getSubscription(self.sub_id1)
subscription2 = portal_sync.getSubscription(self.sub_id2)
self.failUnless(len(subscription1.getObjectList())==nb_person)
person_server = self.getPersonServer() # We also check we don't
# modify initial ob
person1_s = person_server._getOb(self.id1)
self.failUnless(person1_s.getId()==self.id1)
self.failUnless(person1_s.getFirstName()==self.first_name1)
self.failUnless(person1_s.getLastName()==self.last_name1)
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(id)
self.failUnless(person1_c.getId()==id)
self.failUnless(person1_c.getFirstName()==self.first_name1)
self.failUnless(person1_c.getLastName()==self.last_name1)
self.failUnless(len(subscription2.getObjectList())==nb_person)
person_client2 = self.getPersonClient2()
person2_c = person_client2._getOb(id)
self.failUnless(person2_c.getId()==id)
self.failUnless(person2_c.getFirstName()==self.first_name1)
self.failUnless(person2_c.getLastName()==self.last_name1)
class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
run_all_test = True
def getTitle(self):
"""
"""
return "ERP5 SyncML"
def test_01_HasEverything(self, quiet=0, run=run_all_test): def test_01_HasEverything(self, quiet=0, run=run_all_test):
# Test if portal_synchronizations was created # Test if portal_synchronizations was created
if not run: return if not run: return
...@@ -153,8 +338,8 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -153,8 +338,8 @@ class TestERP5SyncML(ERP5TypeTestCase):
portal_id = self.getPortalName() portal_id = self.getPortalName()
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
portal_sync.manage_addPublication(self.pub_id,self.publication_url, portal_sync.manage_addPublication(self.pub_id,self.publication_url,
'/%s/person_server' % portal_id,'objectValues', '/%s/person_server' % portal_id,'objectValues', self.xml_mapping,
self.xml_mapping,'ERP5Conduit','') 'ERP5Conduit','')
pub = portal_sync.getPublication(self.pub_id) pub = portal_sync.getPublication(self.pub_id)
self.failUnless(pub is not None) self.failUnless(pub is not None)
...@@ -165,7 +350,7 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -165,7 +350,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
LOG('Testing... ',0,'test_03_AddSubscription1') LOG('Testing... ',0,'test_03_AddSubscription1')
portal_id = self.getPortalId() portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id1,self.publication_url, portal_sync.manage_addSubscription(self.sub_id1, self.publication_url,
self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues', self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','') self.xml_mapping,'ERP5Conduit','')
sub = portal_sync.getSubscription(self.sub_id1) sub = portal_sync.getSubscription(self.sub_id1)
...@@ -184,53 +369,12 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -184,53 +369,12 @@ class TestERP5SyncML(ERP5TypeTestCase):
sub = portal_sync.getSubscription(self.sub_id2) sub = portal_sync.getSubscription(self.sub_id2)
self.failUnless(sub is not None) self.failUnless(sub is not None)
def login(self, quiet=0): def setupPublicationAndSubscription(self, quiet=0, run=run_all_test):
uf = self.getPortal().acl_users
uf._doAddUser('fab', 'myPassword', ['Manager'], [])
uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], [])
uf._doAddUser('syncml', '', ['Manager'], [])
user = uf.getUserById('fab').__of__(uf)
newSecurityManager(None, user)
def populatePersonServer(self, quiet=0, run=run_all_test):
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Populate Person Server ')
LOG('Testing... ',0,'populatePersonServer')
self.login()
portal = self.getPortal()
if not hasattr(portal,'person_server'):
portal.portal_types.constructContent(type_name = 'Person Module',
container = portal,
id = 'person_server')
if not hasattr(portal,'person_client1'):
portal.portal_types.constructContent(type_name = 'Person Module',
container = portal,
id = 'person_client1')
if not hasattr(portal,'person_client2'):
portal.portal_types.constructContent(type_name = 'Person Module',
container = portal,
id = 'person_client2')
person_id = ''
person_server = self.getPersonServer()
person1 = person_server.newContent(id=self.id1,portal_type='Person')
kw = {'first_name':self.first_name1,'last_name':self.last_name1,
'description':self.description1}
person1.edit(**kw)
person2 = person_server.newContent(id=self.id2,portal_type='Person')
kw = {'first_name':self.first_name2,'last_name':self.last_name2,
'description':self.description2}
person2.edit(**kw)
nb_person = len(person_server.objectValues())
self.failUnless(nb_person==2)
return nb_person
def setupPublicationAndSubscription(self, quiet=0, run=1):
self.test_02_AddPublication(quiet=1,run=1) self.test_02_AddPublication(quiet=1,run=1)
self.test_03_AddSubscription1(quiet=1,run=1) self.test_03_AddSubscription1(quiet=1,run=1)
self.test_04_AddSubscription2(quiet=1,run=1) self.test_04_AddSubscription2(quiet=1,run=1)
def setupPublicationAndSubscriptionAndGid(self, quiet=0, run=1): def setupPublicationAndSubscriptionAndGid(self, quiet=0, run=run_all_test):
self.setupPublicationAndSubscription(quiet=1,run=1) self.setupPublicationAndSubscription(quiet=1,run=1)
def getGid(object): def getGid(object):
return object.getTitle() return object.getTitle()
...@@ -241,9 +385,9 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -241,9 +385,9 @@ class TestERP5SyncML(ERP5TypeTestCase):
pub.setGidGenerator(getGid) pub.setGidGenerator(getGid)
sub1.setGidGenerator(getGid) sub1.setGidGenerator(getGid)
sub2.setGidGenerator(getGid) sub2.setGidGenerator(getGid)
pub.setIdGenerator('_generateNextId') pub.setSynchronizationIdGenerator('_generateNextId')
sub1.setIdGenerator('_generateNextId') sub1.setSynchronizationIdGenerator('_generateNextId')
sub2.setIdGenerator('_generateNextId') sub2.setSynchronizationIdGenerator('_generateNextId')
def test_05_GetSynchronizationList(self, quiet=0, run=run_all_test): def test_05_GetSynchronizationList(self, quiet=0, run=run_all_test):
# This test the getSynchronizationList, ie, # This test the getSynchronizationList, ie,
...@@ -315,73 +459,6 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -315,73 +459,6 @@ class TestERP5SyncML(ERP5TypeTestCase):
c_local_role = person_client1.get_local_roles() c_local_role = person_client1.get_local_roles()
self.assertEqual(s_local_role,c_local_role) self.assertEqual(s_local_role,c_local_role)
def synchronize(self, id, run=1):
"""
This just define how we synchronize, we have
to define it here because it is specific to the unit testing
"""
portal_sync = self.getSynchronizationTool()
subscription = portal_sync.getSubscription(id)
publication = None
for publication in portal_sync.getPublicationList():
if publication.getPublicationUrl()==subscription.getSubscriptionUrl():
publication = publication
self.failUnless(publication is not None)
# reset files, because we do sync by files
file = open('/tmp/sync_client1','w')
file.write('')
file.close()
file = open('/tmp/sync_client2','w')
file.write('')
file.close()
file = open('/tmp/sync','w')
file.write('')
file.close()
nb_message = 1
result = portal_sync.SubSync(subscription.getTitle())
while result['has_response']==1:
portal_sync.PubSync(publication.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
nb_message += 1 + result['has_response']
return nb_message
def synchronizeWithBrokenMessage(self, id, run=1):
"""
This just define how we synchronize, we have
to define it here because it is specific to the unit testing
"""
portal_sync = self.getSynchronizationTool()
#portal_sync.email = None # XXX To be removed
subscription = portal_sync.getSubscription(id)
publication = None
for publication in portal_sync.getPublicationList():
if publication.getPublicationUrl()==subscription.getSubscriptionUrl():
publication = publication
self.failUnless(publication is not None)
# reset files, because we do sync by files
file = open('/tmp/sync_client1','w')
file.write('')
file.close()
file = open('/tmp/sync_client2','w')
file.write('')
file.close()
file = open('/tmp/sync','w')
file.write('')
file.close()
nb_message = 1
result = portal_sync.SubSync(subscription.getTitle())
while result['has_response']==1:
# We do thing three times, so that we will test
# if we manage well duplicate messages
portal_sync.PubSync(publication.getTitle())
portal_sync.PubSync(publication.getTitle())
portal_sync.PubSync(publication.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
nb_message += 1 + result['has_response']
return nb_message
def test_08_FirstSynchronization(self, quiet=0, run=run_all_test): def test_08_FirstSynchronization(self, quiet=0, run=run_all_test):
# We will try to populate the folder person_client1 # We will try to populate the folder person_client1
# with the data form person_server # with the data form person_server
...@@ -408,26 +485,7 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -408,26 +485,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
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.failUnless(nb_message2==self.nb_message_first_synchronization) self.failUnless(nb_message2==self.nb_message_first_synchronization)
subscription1 = portal_sync.getSubscription(self.sub_id1) self.checkFirstSynchronization(id=self.id1, nb_person=nb_person)
subscription2 = portal_sync.getSubscription(self.sub_id2)
self.failUnless(len(subscription1.getObjectList())==nb_person)
person_server = self.getPersonServer() # We also check we don't
# modify initial ob
person1_s = person_server._getOb(self.id1)
self.failUnless(person1_s.getId()==self.id1)
self.failUnless(person1_s.getFirstName()==self.first_name1)
self.failUnless(person1_s.getLastName()==self.last_name1)
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1)
self.failUnless(person1_c.getId()==self.id1)
self.failUnless(person1_c.getFirstName()==self.first_name1)
self.failUnless(person1_c.getLastName()==self.last_name1)
self.failUnless(len(subscription2.getObjectList())==nb_person)
person_client2 = self.getPersonClient2()
person2_c = person_client2._getOb(self.id1)
self.failUnless(person2_c.getId()==self.id1)
self.failUnless(person2_c.getFirstName()==self.first_name1)
self.failUnless(person2_c.getLastName()==self.last_name1)
def test_09_FirstSynchronizationWithLongLines(self, quiet=0, run=run_all_test): def test_09_FirstSynchronizationWithLongLines(self, quiet=0, run=run_all_test):
# We will try to populate the folder person_client1 # We will try to populate the folder person_client1
...@@ -497,33 +555,6 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -497,33 +555,6 @@ class TestERP5SyncML(ERP5TypeTestCase):
# for each subscriber # for each subscriber
self.checkSynchronizationStateIsSynchronized() self.checkSynchronizationStateIsSynchronized()
def checkSynchronizationStateIsSynchronized(self, quiet=0, run=1):
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
for person in person_server.objectValues():
state_list = portal_sync.getSynchronizationState(person)
for state in state_list:
self.failUnless(state[1]==state[0].SYNCHRONIZED)
person_client1 = self.getPersonClient1()
for person in person_client1.objectValues():
state_list = portal_sync.getSynchronizationState(person)
for state in state_list:
self.failUnless(state[1]==state[0].SYNCHRONIZED)
person_client2 = self.getPersonClient2()
for person in person_client2.objectValues():
state_list = portal_sync.getSynchronizationState(person)
for state in state_list:
self.failUnless(state[1]==state[0].SYNCHRONIZED)
# Check for each signature that the tempXML is None
for sub in portal_sync.getSubscriptionList():
for m in sub.getSignatureList():
self.assertEquals(m.getTempXML(),None)
self.assertEquals(m.getPartialXML(),None)
for pub in portal_sync.getPublicationList():
for sub in pub.getSubscriberList():
for m in sub.getSignatureList():
self.assertEquals(m.getPartialXML(),None)
def checkSynchronizationStateIsConflict(self, quiet=0, run=1): def checkSynchronizationStateIsConflict(self, quiet=0, run=1):
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer() person_server = self.getPersonServer()
...@@ -987,7 +1018,7 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -987,7 +1018,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person_s.getDescription()==self.description3) self.failUnless(person_s.getDescription()==self.description3)
self.failUnless(person_c1.getDescription()==self.description3) self.failUnless(person_c1.getDescription()==self.description3)
def test_25_MultiNodeConflict(self, quiet=0, run=1): def test_25_MultiNodeConflict(self, quiet=0, run=run_all_test):
""" """
We will create conflicts with 3 differents nodes, and we will We will create conflicts with 3 differents nodes, and we will
solve it by taking one full version of documents. solve it by taking one full version of documents.
...@@ -1410,27 +1441,7 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA==' ...@@ -1410,27 +1441,7 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=='
sub.setAuthenticationFormat(auth_format) sub.setAuthenticationFormat(auth_format)
sub.setAuthenticationType(auth_type) sub.setAuthenticationType(auth_type)
def verifyFirstNameAndLastNameAreSynchronized(self, first_name, def test_35_authentication(self, quiet=0, run=run_all_test):
last_name, person_server, person_client):
"""
verify if the first and last name are synchronized
"""
self.failUnless(person_server.getFirstName()==first_name)
self.failUnless(person_server.getLastName()==last_name)
self.failUnless(person_client.getFirstName()==first_name)
self.failUnless(person_client.getLastName()==last_name)
def verifyFirstNameAndLastNameAreNotSynchronized(self, first_name,
last_name, person_server, person_client):
"""
verify that the first and last name are NOT synchronized
"""
self.failUnless(person_server.getFirstName()!=first_name)
self.failUnless(person_server.getLastName()!=last_name)
self.failUnless(person_client.getFirstName()==first_name)
self.failUnless(person_client.getLastName()==last_name)
def test_35_authentication(self, quiet=0, run=1):
""" """
we will test we will test
- if we can't synchronize without good authentication for an - if we can't synchronize without good authentication for an
...@@ -1508,7 +1519,6 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA==' ...@@ -1508,7 +1519,6 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=='
self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name1, self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name1,
self.last_name1, person1_s, person1_c) self.last_name1, person1_s, person1_c)
#with the good password #with the good password
self.addAuthenticationToSubscription(self.sub_id1, 'fab', 'myPassword', self.addAuthenticationToSubscription(self.sub_id1, 'fab', 'myPassword',
'b64', 'syncml:auth-basic') 'b64', 'syncml:auth-basic')
......
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