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
from Products.ERP5SyncML.XupdateUtils import XupdateUtils
from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Type.Accessor.TypeDefinition import list_types
from xml.dom.ext.reader.Sax2 import FromXml
from xml.dom.minidom import parse, parseString
from Ft.Xml import Parse
from DateTime.DateTime import DateTime
from email.MIMEBase import MIMEBase
from email import Encoders
......@@ -44,10 +43,12 @@ from Products.ERP5Type import Permissions
from Globals import PersistentMapping
import pickle
import string
from xml.dom.ext import PrettyPrint
from cStringIO import StringIO
from xml.sax.saxutils import escape, unescape
import re, copy
import cStringIO
from Ft.Xml.Domlette import Print, PrettyPrint
from zLOG import LOG
......@@ -132,7 +133,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return {'conflict_list':conflict_list, 'object':sub_object}
LOG('addNode',0,'xml_reconstitued: %s' % str(xml))
# 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
for element in self.getXupdateElementList(xml):
xml = self.getElementFromXupdate(element)
......@@ -160,7 +162,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
portal_type = self.getObjectType(xml)
elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD: # 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(
object=sub_object,
xml=xml,
......@@ -274,9 +277,9 @@ class ERP5Conduit(XMLSyncUtilsMixin):
LOG('updateNode, force: ',0,force)
# we have an xupdate xml
if xml.nodeName == 'xupdate:modifications':
conflict_list += self.applyXupdate(object=object,xupdate=xml,conduit=self,
previous_xml=previous_xml, force=force, simulate=simulate,
**kw)
conflict_list += self.applyXupdate(object=object, xupdate=xml,
conduit=self,previous_xml=previous_xml, force=force,
simulate=simulate, **kw)
# we may have only the part of an xupdate
else:
args = {}
......@@ -342,7 +345,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
# - current_data : the data actually on this box
isConflict = 0
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 = self.getProperty(object, keyword)
LOG('updateNode',0,'Conflict data: %s' % str(data))
......@@ -383,13 +387,13 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if keyword == 'object':
# This is the case where we have to call addNode
LOG('updateNode',0,'we will add sub-object')
conflict_list += self.addNode(xml=xml,object=object,force=force,
simulate=simulate, **kw)['conflict_list']
conflict_list += self.addNode(xml=xml, object=object, force=force,
simulate=simulate, **kw)['conflict_list']
elif keyword == self.history_tag and not simulate:
# This is the case where we have to call addNode
LOG('updateNode',0,'we will add history')
conflict_list += self.addNode(xml=subnode,object=object,force=force,
simulate=simulate,**kw)['conflict_list']
simulate=simulate,**kw)['conflict_list']
elif keyword in (self.local_role_tag,self.local_permission_tag) and not simulate:
# This is the case where we have to update Roles or update permission
LOG('updateNode',0,'we will add a local role')
......@@ -397,8 +401,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
#roles = self.convertXmlValue(data,data_type='tokens')
#object.manage_setLocalRoles(user,roles)
xml = self.getElementFromXupdate(xml)
conflict_list += self.addNode(xml=xml,object=object,force=force,
simulate=simulate,**kw)['conflict_list']
conflict_list += self.addNode(xml=xml, object=object, force=force,
simulate=simulate,**kw)['conflict_list']
elif self.isSubObjectModification(xml):
# We should find the object corresponding to
# this update, so we have to look in the previous_xml
......@@ -421,8 +425,21 @@ class ERP5Conduit(XMLSyncUtilsMixin):
sub_xml = self.getSubObjectXupdate(xml)
LOG('updateNode',0,'sub_xml: %s' % str(sub_xml))
# Then do the udpate
conflict_list += self.updateNode(xml=sub_xml,object=sub_object, force=force,
previous_xml=sub_previous_xml,simulate=simulate, **kw)
conflict_list += self.updateNode(xml=sub_xml, object=sub_object, force=force,
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:
sub_object = None
try:
......@@ -438,7 +455,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
**kw)
return conflict_list
security.declareProtected(Permissions.AccessContentsInformation,'getFormatedArgs')
security.declareProtected(Permissions.AccessContentsInformation,
'getFormatedArgs')
def getFormatedArgs(self, args=None):
"""
This lookd inside the args dictionnary and then
......@@ -484,19 +502,21 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return 0
return 1
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectXupdate')
security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectXupdate')
def getSubObjectXupdate(self, xml):
"""
This will change the xml in order to change the update
from the object to the subobject
"""
xml = copy.deepcopy(xml)
for subnode in self.getAttributeNodeList(xml):
xml_copy = xml.cloneNode(True) #make a deepcopy of the node xml
for subnode in self.getAttributeNodeList(xml_copy):
if subnode.nodeName=='select':
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):
bad_list = (self.history_exp,)
for subnode in self.getAttributeNodeList(xml):
......@@ -510,7 +530,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return -1
return 0
security.declareProtected(Permissions.AccessContentsInformation,'isSubObjectModification')
security.declareProtected(Permissions.AccessContentsInformation,
'isSubObjectModification')
def isSubObjectModification(self, xml):
"""
Check if it is a modification from an subobject
......@@ -524,7 +545,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return 1
return 0
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectDepth')
security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectDepth')
def getSubObjectDepth(self, xml):
"""
Give the Depth of a subobject modification
......@@ -555,7 +577,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return (1 - i)
return 0
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectSelect')
security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectSelect')
def getSubObjectSelect(self, select):
"""
Return a string wich is the selection for the subobject
......@@ -571,7 +594,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
select = new_value
return select
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectId')
security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectId')
def getSubObjectId(self, xml):
"""
Return the id of the subobject in an xupdate modification
......@@ -587,7 +611,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return object_id
return object_id
security.declareProtected(Permissions.AccessContentsInformation,'getHistoryIdFromSelect')
security.declareProtected(Permissions.AccessContentsInformation,
'getHistoryIdFromSelect')
def getHistoryIdFromSelect(self, xml):
"""
Return the id of the subobject in an xupdate modification
......@@ -604,7 +629,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return object_id
return object_id
security.declareProtected(Permissions.AccessContentsInformation,'getSubObjectXml')
security.declareProtected(Permissions.AccessContentsInformation,
'getSubObjectXml')
def getSubObjectXml(self, object_id, xml):
"""
Return the xml of the subobject which as the id object_id
......@@ -624,7 +650,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
"""
for attribute in self.getAttributeNodeList(xml):
if attribute.nodeName == param:
data = attribute.childNodes[0].data
data = attribute.value
return self.convertXmlValue(data,data_type='string')
return None
......@@ -635,7 +661,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
"""
for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'docid':
data = subnode.childNodes[0].data
data = subnode.childNodes[0].value
return self.convertXmlValue(data)
return None
......@@ -669,7 +695,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
LOG('Conduit.convertToXml xml',0,repr(xml))
if type(xml) is type(u'a'):
xml = xml.encode('utf-8')
xml = parseString(xml)
xml = Parse(xml)
LOG('Conduit.convertToXml not failed',0,'ok')
xml = xml.childNodes[0] # Because we just created a new xml
# If we have the xml from the node erp5, we just take the subnode
......@@ -811,7 +837,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
#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 = self.nodeToString(xml)
xml_string = unicode(xml_string,encoding='utf-8')
#if type(xml_string) is type (u'a'):
# xml_string = xml_string.encode('utf-8')
......@@ -840,12 +866,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if select_id is not None:
result += ' id=%s' % select_id
result += '>'
# Then dumps the xml and remove what we does'nt want
#xml_string = StringIO()
#PrettyPrint(xml,xml_string)
#xml_string = xml_string.getvalue()
#xml_string = unicode(xml_string,encoding='utf-8')
xml_string = xml.toxml(encoding='utf-8')
xml_string = self.nodeToString(xml)
xml_string = unicode(xml_string,encoding='utf-8')
maxi = xml_string.find('>')+1
result += xml_string[maxi:xml_string.find('</%s>' % xml.nodeName)]
......@@ -929,7 +950,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
"""
conflict_list = []
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
if self.isMixedXupdate(xupdate):
#return to updateNode with only one line
......@@ -967,7 +988,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
nb_sub = len(subnode_list)
comp = 0
for subnode in subnode_list:
value = subnode.getAttribute('select')
value = self.getAttribute(subnode, 'select')
if re.search(self.object_exp, value):
comp += 1
if nb_sub == comp:
......@@ -1043,7 +1064,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if wf_id is None: # History added by xupdate
wf_id = self.getHistoryIdFromSelect(xml)
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))
xml = self.getElementNodeList(xml)[0]
LOG('addNode, workflow_history id:',0,wf_id)
......@@ -1152,3 +1173,14 @@ class ERP5Conduit(XMLSyncUtilsMixin):
# conflict.setRemoteValue(status)
# conflict_list += [conflict]
# 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):
# Constructor
def __init__(self, id, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, auth_required=False,
authentication_format='', authentication_type=''):
query, xml_mapping, conduit, gpg_key, id_generator, gid_generator,
flow_type, auth_required=False, authentication_format='',
authentication_type=''):
"""
constructor
"""
......@@ -166,8 +167,9 @@ class Publication(Subscription):
#self.list_subscribers = PersistentMapping()
self.domain_type = self.PUB
self.gpg_key = gpg_key
self.setGidGenerator(None)
self.setIdGenerator(None)
self.setGidGenerator(gid_generator)
self.setFlowType(flow_type)
self.setSynchronizationIdGenerator(id_generator)
self.setConduit(conduit)
Folder.__init__(self, id)
self.title = title
......
......@@ -29,8 +29,7 @@
import smtplib # to send emails
from Publication import Publication,Subscriber
from Subscription import Signature
from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml
from xml.dom.minidom import parse, parseString
from Ft.Xml import Parse
from XMLSyncUtils import XMLSyncUtils
from Conduit.ERP5Conduit import ERP5Conduit
from Products.CMFCore.utils import getToolByName
......@@ -142,6 +141,13 @@ class PublicationSynchronization(XMLSyncUtils):
xml(' <SyncBody>\n')
xml(self.SyncMLStatus(cmd_id, subscriber.getSubscriptionUrl(),
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('</SyncML>\n')
xml_a = ''.join(xml_list)
......@@ -221,7 +227,7 @@ class PublicationSynchronization(XMLSyncUtils):
if xml_client is not None:
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]
if first_node.nodeName != "SyncML":
......
......@@ -642,8 +642,9 @@ class Subscription(Folder, SyncCode):
)
# Constructor
def __init__(self, id, title, publication_url, subscription_url, destination_path, query, xml_mapping, conduit, gpg_key, login, password,
authentication_format='', authentication_type=''):
def __init__(self, id, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key, id_generator,
gid_generator, flow_type, login, password):
"""
We need to create a dictionnary of
signatures of documents which belong to the synchronisation
......@@ -660,14 +661,13 @@ class Subscription(Folder, SyncCode):
#self.signatures = PersistentMapping()
self.last_anchor = '00000000T000000Z'
self.next_anchor = '00000000T000000Z'
self.login=login
self.flow_type = flow_type
self.login = login
self.password=password
self.authentication_format=authentication_format
self.authentication_type=authentication_type
self.domain_type = self.SUB
self.gpg_key = gpg_key
self.setGidGenerator(None)
self.setIdGenerator(None)
self.setGidGenerator(gid_generator)
self.setSynchronizationIdGenerator(id_generator)
self.setConduit(conduit)
Folder.__init__(self, id)
self.title = title
......@@ -715,7 +715,7 @@ class Subscription(Folder, SyncCode):
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 == '':
value = None
......@@ -884,6 +884,20 @@ class Subscription(Folder, SyncCode):
"""
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):
"""
This method return the login of this subscription
......@@ -954,7 +968,7 @@ class Subscription(Folder, SyncCode):
# It might be a script python
generator = getattr(object,gid_gen)
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
def getObjectFromGid(self, gid):
......@@ -1018,10 +1032,7 @@ class Subscription(Folder, SyncCode):
"""
This tries to generate a new Id
"""
# LOG('generateNewId, object: ',0,object.getPhysicalPath())
id_generator = self.getIdGenerator()
# LOG('generateNewId, id_generator: ',0,id_generator)
# LOG('generateNewId, portal_object: ',0,object.getPortalObject())
id_generator = self.getSynchronizationIdGenerator()
if id_generator is not None:
o_base = aq_base(object)
new_id = None
......@@ -1038,20 +1049,20 @@ class Subscription(Folder, SyncCode):
return new_id
return None
def setIdGenerator(self, method):
def setSynchronizationIdGenerator(self, method):
"""
This set the method name wich allows to generate
a new id
"""
if method in ('','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
"""
return self.id_generator
return getattr(self, 'synchronization_id_generator', None)
def getSubscriptionUrl(self):
"""
......@@ -1185,7 +1196,7 @@ class Subscription(Folder, SyncCode):
"""
if signature.getGid() in self.objectIds():
self._delObject(signature.getGid())
self._setObject( signature.getGid(), aq_base(signature) )
self._setObject(signature.getGid(), aq_base(signature) )
def delSignature(self, gid):
"""
......@@ -1321,7 +1332,7 @@ class Subscription(Folder, SyncCode):
#elif format is .... put here the other formats
else:#if there is no format corresponding with format, raise an error
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):
"""
......
......@@ -28,9 +28,7 @@
import smtplib # to send emails
from Subscription import Subscription,Signature
from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml
from xml.dom.minidom import parse, parseString
from xml.dom.ext import PrettyPrint
from Ft.Xml import Parse
from XMLSyncUtils import XMLSyncUtils
import commands
from Conduit.ERP5Conduit import ERP5Conduit
......@@ -99,13 +97,21 @@ class SubscriptionSynchronization(XMLSyncUtils):
else:
xml_client = msg
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)
#LOG('readResponse, next status :',0,next_status)
if next_status is not None:
status_code = self.getStatusCode(next_status)
#LOG('readResponse status code :',0,status_code)
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')
response = self.SubSyncCred(id, xml_client)
elif status_code == self.UNAUTHORIZED:
......
......@@ -40,8 +40,7 @@ from Products.ERP5SyncML import Conduit
from Publication import Publication,Subscriber
from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2
from Subscription import Subscription,Signature
from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml
from xml.dom.minidom import parse, parseString
from Ft.Xml import Parse
from Products.ERP5Type import Permissions
from PublicationSynchronization import PublicationSynchronization
from SubscriptionSynchronization import SubscriptionSynchronization
......@@ -50,7 +49,6 @@ from AccessControl.SecurityManagement import newSecurityManager
from AccessControl.SecurityManagement import noSecurityManager
from AccessControl.User import UnrestrictedUser
from Acquisition import aq_base
from xml.parsers.expat import ExpatError # parseString error
import urllib
import urllib2
import socket
......@@ -162,9 +160,11 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent,
'manage_addPublication')
def manage_addPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, auth_required=0,
authentication_format='', authentication_type='', RESPONSE=None):
"""
query, xml_mapping, conduit, gpg_key,
synchronization_id_generator=None, gid_generator=None,
flow_type='xml', auth_required=0, authentication_format='',
authentication_type='', RESPONSE=None):
"""
create a new publication
"""
#if not('publications' in self.objectIds()):
......@@ -173,8 +173,9 @@ class SynchronizationTool( SubscriptionSynchronization,
folder = self.getObjectContainer()
new_id = self.getPublicationIdFromTitle(title)
pub = Publication(new_id, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, auth_required,
authentication_format, authentication_type)
query, xml_mapping, conduit, gpg_key,
synchronization_id_generator, gid_generator, flow_type,
auth_required, authentication_format, authentication_type)
folder._setObject( new_id, pub )
#if len(self.list_publications) == 0:
# self.list_publications = PersistentMapping()
......@@ -186,8 +187,9 @@ class SynchronizationTool( SubscriptionSynchronization,
'manage_addSubscription')
def manage_addSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key,
login=None, password=None, authentication_format='',
authentication_type='',RESPONSE=None):
synchronization_id_generator=None, gid_generator=None,
flow_type='xml', login=None, password=None,
RESPONSE=None):
"""
XXX should be renamed as addSubscription
create a new subscription
......@@ -199,8 +201,8 @@ class SynchronizationTool( SubscriptionSynchronization,
new_id = self.getSubscriptionIdFromTitle(title)
sub = Subscription(new_id, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key,
login, password, authentication_format,
authentication_type)
synchronization_id_generator, gid_generator, flow_type,
login, password)
folder._setObject( new_id, sub )
#if len(self.list_subscriptions) == 0:
# self.list_subscriptions = PersistentMapping()
......@@ -211,9 +213,11 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent,
'manage_editPublication')
def manage_editPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key, id_generator,
gid_generator, auth_required=0, authentication_format='',
authentication_type='', RESPONSE=None):
query, xml_mapping, conduit, gpg_key,
synchronization_id_generator, gid_generator,
flow_type='xml', auth_required=0,
authentication_format='', authentication_type='',
RESPONSE=None):
"""
modify a publication
"""
......@@ -225,8 +229,9 @@ class SynchronizationTool( SubscriptionSynchronization,
pub.setConduit(conduit)
pub.setXMLMapping(xml_mapping)
pub.setGPGKey(gpg_key)
pub.setIdGenerator(id_generator)
pub.setSynchronizationIdGenerator(synchronization_id_generator)
pub.setGidGenerator(gid_generator)
pub.setFlowType(flow_type)
pub.setAuthentication(auth_required)
pub.setAuthenticationFormat(authentication_format)
pub.setAuthenticationType(authentication_type)
......@@ -237,9 +242,9 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent,
'manage_editSubscription')
def manage_editSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key, id_generator,
gid_generator,login='', password='', authentication_format='',
authentication_type='', RESPONSE=None):
destination_path, query, xml_mapping, conduit, gpg_key,
synchronization_id_generator, gid_generator, flow_type='xml', login='',
password='', RESPONSE=None):
"""
modify a subscription
"""
......@@ -252,12 +257,11 @@ class SynchronizationTool( SubscriptionSynchronization,
sub.setXMLMapping(xml_mapping)
sub.setGPGKey(gpg_key)
sub.setSubscriptionUrl(subscription_url)
sub.setIdGenerator(id_generator)
sub.setSynchronizationIdGenerator(synchronization_id_generator)
sub.setGidGenerator(gid_generator)
sub.setFlowType(flow_type)
sub.setLogin(login)
sub.setPassword(password)
sub.setAuthenticationFormat(authentication_format)
sub.setAuthenticationType(authentication_type)
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
......@@ -613,6 +617,7 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.AccessContentsInformation,
'getSubscriberDocumentPath')
def getSubscriberDocumentPath(self, conflict):
"""
apply the publisher value for all conflict of the given document
......@@ -974,7 +979,7 @@ class SynchronizationTool( SubscriptionSynchronization,
commands.getstatusoutput('rm -f /tmp/%s.gz.gpg' % filename)
# Get the target and then find the corresponding publication or
# Subscription
xml = parseString(text)
xml = Parse(text)
#XXX this function is not very optimized and should be improved
url = self.getTarget(xml)
for publication in self.getPublicationList():
......
......@@ -29,8 +29,7 @@
import smtplib
from Products.ERP5SyncML.SyncCode import SyncCode
from Products.ERP5SyncML.Subscription import Signature
from xml.dom.ext.reader.Sax2 import FromXml
from xml.dom.minidom import parse, parseString
from Ft.Xml import Parse
from DateTime import DateTime
from cStringIO import StringIO
from xml.dom.ext import PrettyPrint
......@@ -200,7 +199,9 @@ class XMLSyncUtilsMixin(SyncCode):
xml = xml_list.append
xml(' <Add>\n')
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(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % gid)
......@@ -227,8 +228,8 @@ class XMLSyncUtilsMixin(SyncCode):
xml(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % object_gid)
xml(' </Source>\n')
xml(' <Data>\n')
xml(' </Data>\n')
#xml(' <Data>\n') #this 2 lines seems to be useless
#xml(' </Data>\n')
xml(' </Item>\n')
xml(' </Delete>\n')
xml_a = ''.join(xml_list)
......@@ -243,7 +244,9 @@ class XMLSyncUtilsMixin(SyncCode):
xml = xml_list.append
xml(' <Replace>\n')
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(' <Source>\n')
xml(' <LocURI>%s</LocURI>\n' % str(gid))
......@@ -290,10 +293,13 @@ class XMLSyncUtilsMixin(SyncCode):
if xml_mapping is not None:
if hasattr(object,xml_mapping):
xml_method = getattr(object,xml_mapping)
elif hasattr(object,'manage_FTPget'):
xml_method = getattr(object,'manage_FTPget')
#elif hasattr(object,'manage_FTPget'):
# xml_method = getattr(object,'manage_FTPget')
if xml_method is not None:
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
def getSessionId(self, xml):
......@@ -301,28 +307,17 @@ class XMLSyncUtilsMixin(SyncCode):
We will retrieve the session id of the message
"""
session_id = 0
for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'SyncML':
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)
session_id = xml.xpath('string(/SyncML/SyncHdr/SessionID)')
session_id = int(session_id)
return session_id
def getMessageId(self, xml):
"""
We will retrieve the message id of the message
"""
message_id = 0
for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'SyncML':
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)
message_id = xml.xpath('string(/SyncML/SyncHdr/MsgID)')
message_id = int(message_id)
return message_id
def getTarget(self, xml):
......@@ -330,18 +325,10 @@ class XMLSyncUtilsMixin(SyncCode):
return the target in the SyncHdr section
"""
url = ''
for subnode in self.getElementNodeList(xml):
if subnode.nodeName == 'SyncML':
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
url = xml.xpath('string(/SyncML/SyncHdr/Target/LocURI)')
url = url.encode('utf-8')
return url
def getAlertLastAnchor(self, xml_stream):
"""
Return the value of the last anchor, in the
......@@ -351,23 +338,8 @@ class XMLSyncUtilsMixin(SyncCode):
# Get informations from the body
client_body = first_node.childNodes[3]
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 == "Last":
last_anchor = subnode5.childNodes[0].data
last_anchor = client_body.xpath('string(/Alert/Item/Meta/Anchor/Last)')
last_anchor = last_anchor.encode('utf-8')
return last_anchor
def getAlertNextAnchor(self, xml_stream):
......@@ -381,61 +353,33 @@ class XMLSyncUtilsMixin(SyncCode):
# Get informations from the body
client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody":
print "This is not a SyncML Body"
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
next_anchor = client_body.xpath('string(/Alert/Item/Meta/Anchor/Next)')
next_anchor = next_anchor.encode('utf-8')
return next_anchor
def getStatusTarget(self, xml):
"""
Return the value of the alert code inside the xml_stream
"""
# Get informations from the body
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
return xml.xpath('string(TargetRef)')
def getStatusCode(self, xml):
"""
Return the value of the alert code inside the xml_stream
"""
# Get informations from the body
if xml.nodeName=='Status':
for subnode in xml.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == 'Data':
return int(subnode.childNodes[0].data)
status_code = xml.xpath('string(Data)')
if status_code not in ('', None, []):
return int(status_code)
return None
def getStatusCommand(self, xml):
"""
Return the value of the command inside the xml_stream
"""
# Get informations from the body
if xml.nodeName=='Status':
for subnode in xml.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Cmd':
return subnode.childNodes[0].data
return None
return xml.xpath('string(//Status/Cmd)')
else:
return None
def getCred(self, xml):
"""
......@@ -444,111 +388,84 @@ class XMLSyncUtilsMixin(SyncCode):
format=''
type=''
data=''
first_node = xml.childNodes[0]
if first_node.nodeName != "SyncML":
print "This is not a SyncML message"
# Get informations from the header
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"
format = first_node.xpath('string(/SyncML/SyncHdr/Cred/Meta/Format)')
type = first_node.xpath('string(/SyncML/SyncHdr/Cred/Meta/Type)')
data = first_node.xpath('string(/SyncML/SyncHdr/Cred/Data)')
for subnode in xml_header.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName=='Cred':
for subnode2 in subnode.childNodes:
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
format = format.encode('utf-8')
type = type.encode('utf-8')
data = data.encode('utf-8')
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
first_node = xml_stream.childNodes[0]
client_body = first_node.childNodes[3]
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
if xml_stream.xpath('string(SyncML/SyncHdr/Cred)') not in ('', None, []):
return True
return False
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
"""
format=''
type=''
first_node = xml.childNodes[0]
format = first_node.xpath('string(/SyncML/SyncBody/Status/Chal/Meta/Format)')
type = first_node.xpath('string(/SyncML/SyncBody/Status/Chal/Meta/Type)')
format = format.encode('utf-8')
type = type.encode('utf-8')
return (format, type)
def checkChal(self, xml_stream):
"""
first_node = xml_stream.childNodes[0]
# Get informations from the header
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"
cred = 0
for subnode in xml_header.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Cred":
cred=1
return cred
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):
"""
Check if there's an Alert section in the xml_stream
"""
first_node = xml_stream.childNodes[0]
client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody":
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
alert = False
if xml_stream.xpath('string(SyncML/SyncBody/Alert)') not in ('', None, []):
alert = True
return alert
def checkSync(self, xml_stream):
"""
Check if there's an Sync section in the xml_xtream
"""
first_node = xml_stream.childNodes[0]
client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody":
LOG('checkSync',0,"This is not a SyncML Body")
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
sync = False
if xml_stream.xpath('string(SyncML/SyncBody/Sync)') not in ('', None, []):
sync = True
return sync
def CheckStatus(self, xml_stream):
"""
Check if there's a Status section in the xml_xtream
"""
first_node = xml_stream.childNodes[0]
client_body = first_node.childNodes[3]
if client_body.nodeName != "SyncBody":
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"
status = False
if xml_stream.xpath('string(SyncML/SyncBody/Status)') not in ('', None, []):
status = True
return status
def getNextSyncAction(self, xml_stream, last_action):
......@@ -563,18 +480,22 @@ class XMLSyncUtilsMixin(SyncCode):
print "This is not a SyncML Body"
next_action = None
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 last_action == None and len(subnode.childNodes) > 1:
next_action = subnode.childNodes[1]
else:
found = None
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
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
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
break
return next_action
......@@ -593,7 +514,8 @@ class XMLSyncUtilsMixin(SyncCode):
next_status = None
found = None
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 last_status == None:
next_status = subnode
......@@ -604,27 +526,32 @@ class XMLSyncUtilsMixin(SyncCode):
return subnode
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):
"""
Return the node starting with <object....> of the action
"""
for subnode in action.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Item':
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'Data':
for subnode3 in subnode2.childNodes:
#if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == 'object':
if subnode3.nodeType == subnode3.ELEMENT_NODE:
return subnode3
if action.xpath('Item/Data') not in ([], None):
data_node = action.xpath('Item/Data')[0]
if data_node.hasChildNodes() and data_node.childNodes.__len__()>1:
return data_node.childNodes[1]
return None
def getPartialData(self, action):
"""
Return the node starting with <object....> of the action
"""
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:
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:
#if subnode3.nodeType == subnode3.ELEMENT_NODE and subnode3.nodeName == 'object':
if subnode3.nodeType == subnode3.COMMENT_NODE:
......@@ -639,60 +566,40 @@ class XMLSyncUtilsMixin(SyncCode):
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):
"""
Return the rid of the object described by the action
"""
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:
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:
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)
def checkActionMoreData(self, action):
"""
Return the rid of the object described by the action
"""
for subnode in action.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == 'Item':
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'MoreData':
return 1
return 0
if action.xpath('Item/MoreData') not in ([],None) :
return True
return False
def getActionType(self, action):
"""
Return the type of the object described by the action
"""
for subnode in action.childNodes:
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)
return action.xpath('string(Meta/Type)')
def getElementNodeList(self, node):
"""
Return childNodes that are ElementNode
"""
#return node.getElementsByTagName('*')
subnode_list = []
for subnode in node.childNodes or []:
if subnode.nodeType == subnode.ELEMENT_NODE:
subnode_list += [subnode]
return subnode_list
return node.xpath('*')
def getTextNodeList(self, node):
"""
......@@ -703,16 +610,12 @@ class XMLSyncUtilsMixin(SyncCode):
if subnode.nodeType == subnode.TEXT_NODE:
subnode_list += [subnode]
return subnode_list
def getAttributeNodeList(self, node):
"""
Return childNodes that are ElementNode
"""
attribute_list = []
for subnode in node.attributes.values() or []:
if subnode.nodeType == subnode.ATTRIBUTE_NODE:
attribute_list += [subnode]
return attribute_list
return node.xpath('@*')
def getSyncMLData(self, domain=None,remote_xml=None,cmd_id=0,
subscriber=None,destination_path=None,
......@@ -730,7 +633,6 @@ class XMLSyncUtilsMixin(SyncCode):
if subscriber.getRemainingObjectPathList() is None:
object_list = domain.getObjectList()
object_path_list = map(lambda x: x.getPhysicalPath(),object_list)
LOG('getSyncMLData, object_path_list',0,object_path_list)
subscriber.setRemainingObjectPathList(object_path_list)
#object_gid = domain.getGidFromObject(object)
......@@ -744,10 +646,10 @@ class XMLSyncUtilsMixin(SyncCode):
if signature.getStatus()!=self.PARTIAL: # If partial, then we have a signature
# but no local object
xml_object = signature.getXML()
if xml_object is not None: # This prevent to delete an object that we
# were not able to create
syncml_data += self.deleteXMLObject(xml_object=signature.getXML() or '',
object_gid=object_gid,cmd_id=cmd_id)
if xml_object is not None: # This prevent to delete an object that
# we were not able to create
syncml_data += self.deleteXMLObject(xml_object=signature.getXML()\
or '', object_gid=object_gid,cmd_id=cmd_id)
local_gid_list = []
#for object in domain.getObjectList():
......@@ -765,14 +667,16 @@ class XMLSyncUtilsMixin(SyncCode):
#if gid_generator is not None:
# object_gid = gid_generator()
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, 'FlowType: %s' % str(subscriber.getFlowType()))
#LOG('getSyncMLData',0,'code: %s' % str(self.getAlertCode(remote_xml)))
#LOG('getSyncMLData',0,'gid_list: %s' % str(local_gid_list))
#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))
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
if signature is not None:
signature.checkSynchronizationNeeded(object)
......@@ -781,11 +685,12 @@ class XMLSyncUtilsMixin(SyncCode):
# For the case it was never synchronized, we have to send everything
if signature is not None and signature.getXMLMapping()==None:
pass
elif signature==None or (signature.getXML()==None and signature.getStatus()!=self.PARTIAL) or \
self.getAlertCode(remote_xml)==self.SLOW_SYNC:
elif signature == None or (signature.getXML() == None and \
signature.getStatus() != self.PARTIAL) or \
self.getAlertCode(remote_xml) == self.SLOW_SYNC:
#LOG('PubSyncModif',0,'Current object.getPath: %s' % object.getPath())
LOG('getSyncMLData',0,'no signature for gid: %s' % object_gid)
xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping)
xml_object = self.getXMLObject(object=object,
xml_mapping=domain.xml_mapping)
xml_string = xml_object
signature = Signature(gid=object_gid,id=object.getId(),object=object)
signature.setTempXML(xml_object)
......@@ -806,14 +711,15 @@ class XMLSyncUtilsMixin(SyncCode):
status =self.PARTIAL
signature.setAction('Add')
xml_string = '<!--' + short_string + '-->'
syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,gid=object_gid,
xml_string=xml_string, more_data=more_data)
syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,
gid=object_gid, xml_string=xml_string, more_data=more_data)
cmd_id += 1
signature.setStatus(status)
subscriber.addSignature(signature)
elif signature.getStatus()==self.NOT_SYNCHRONIZED \
or signature.getStatus()==self.PUB_CONFLICT_MERGE: # We don't have synchronized this object yet
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,'getStatus: %s' % str(signature.getStatus()))
if signature.getStatus()==self.PUB_CONFLICT_MERGE:
......@@ -842,8 +748,11 @@ class XMLSyncUtilsMixin(SyncCode):
signature.setAction('Replace')
xml_string = '<!--' + short_string + '-->'
signature.setStatus(status)
syncml_data += self.replaceXMLObject(cmd_id=cmd_id,object=object,gid=object_gid,
xml_string=xml_string, more_data=more_data)
if(subscriber.getFlowType() == 'text'):
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
signature.setTempXML(xml_object)
# Now we can apply the xupdate from the subscriber
......@@ -851,17 +760,17 @@ class XMLSyncUtilsMixin(SyncCode):
#LOG('getSyncMLData subscriber_xupdate',0,subscriber_xupdate)
if subscriber_xupdate is not None:
old_xml = signature.getXML()
conduit.updateNode(xml=subscriber_xupdate, object=object,
previous_xml=old_xml,force=(domain.getDomainType==self.SUB),
simulate=0)
xml_object = self.getXMLObject(object=object,xml_mapping=domain.xml_mapping)
conduit.updateNode(xml=subscriber_xupdate, object=object,
previous_xml=old_xml, force=(domain.getDomainType==self.SUB),
simulate=0)
xml_object = self.getXMLObject(object=object,
xml_mapping=domain.xml_mapping)
signature.setTempXML(xml_object)
if set_synchronized: # We have to do that after this previous update
# We should not have this case when we are in CONFLICT_MERGE
signature.setStatus(self.SYNCHRONIZED)
elif signature.getStatus()==self.PUB_CONFLICT_CLIENT_WIN:
# 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
# some modification was already made and the update
# may not apply correctly
......@@ -889,12 +798,16 @@ class XMLSyncUtilsMixin(SyncCode):
xml_string = xml_string.replace('--','@-@@-@')
xml_string = '<!--' + xml_string + '-->'
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':
syncml_data += self.replaceXMLObject(cmd_id=cmd_id,object=object,gid=object_gid,
xml_string=xml_string, more_data=more_data)
syncml_data += self.replaceXMLObject(cmd_id=cmd_id, object=object,
gid=object_gid, xml_string=xml_string, more_data=more_data)
elif signature.getAction()=='Add':
syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,gid=object_gid,
xml_string=xml_string, more_data=more_data)
syncml_data += self.addXMLObject(cmd_id=cmd_id, object=object,
gid=object_gid, xml_string=xml_string, more_data=more_data)
return (syncml_data,xml_confirmation,cmd_id)
def applyActionList(self, domain=None, subscriber=None,destination_path=None,
......@@ -918,7 +831,8 @@ class XMLSyncUtilsMixin(SyncCode):
object = domain.getObjectFromGid(object_gid)
if signature == None:
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)
force = signature.getForce()
LOG('applyActionList',0,'object: %s' % repr(object))
......@@ -932,22 +846,28 @@ class XMLSyncUtilsMixin(SyncCode):
data_subnode = partial_data
LOG('SyncModif',0,'data_subnode: %s' % data_subnode)
#data_subnode = FromXml(data_subnode)
data_subnode = parseString(data_subnode)
data_subnode = data_subnode.childNodes[0] # Because we just created a new xml
if subscriber.getFlowType() == 'xml':
data_subnode = Parse(data_subnode)
data_subnode = data_subnode.childNodes[0] # Because we just created a new xml
# document, with childNodes[0] a DocumentType and childNodes[1] the Element Node
else:
data_subnode = self.getDataSubNode(next_action)
if subscriber.getFlowType() == 'text':
data_subnode = self.getDataText(next_action)
else:
data_subnode = self.getDataSubNode(next_action)
if next_action.nodeName == 'Add':
# Then store the xml of this new subobject
if object is None:
object_id = domain.generateNewIdWithGenerator(object=destination_path,gid=object_gid)
#if object_id is not None:
add_data = conduit.addNode(xml=data_subnode, object=destination_path,
object_id=object_id)
conflict_list += add_data['conflict_list']
add_data = conduit.addNode(xml=data_subnode,
object=destination_path, object_id=object_id)
if add_data['conflict_list'] not in ('', None, []):
conflict_list += add_data['conflict_list']
# Retrieve directly the object from addNode
object = add_data['object']
LOG('XMLSyncUtils, in ADD add_data',0,add_data)
signature.setPath(object.getPhysicalPath())
LOG('applyActionList',0,'object after add: %s' % repr(object))
else:
#Object was retrieve but need to be updated without recreated
......@@ -957,7 +877,8 @@ class XMLSyncUtilsMixin(SyncCode):
object=destination_path,
object_id=object_id,
sub_object=object)
conflict_list += add_data['conflict_list']
if add_data['conflict_list'] not in ('', None, []):
conflict_list += add_data['conflict_list']
if object is not None:
LOG('SyncModif',0,'addNode, found the object')
#mapping = getattr(object,domain.getXMLMapping(),None)
......@@ -990,7 +911,8 @@ class XMLSyncUtilsMixin(SyncCode):
if conflict_list != []:
status_code = self.CONFLICT
signature.setStatus(self.CONFLICT)
signature.setConflictList(signature.getConflictList()+conflict_list)
signature.setConflictList(signature.getConflictList() \
+ conflict_list)
string_io = StringIO()
PrettyPrint(data_subnode,stream=string_io)
data_subnode_string = string_io.getvalue()
......@@ -1012,11 +934,15 @@ class XMLSyncUtilsMixin(SyncCode):
elif next_action.nodeName == 'Delete':
object_id = signature.getId()
conduit.deleteNode(xml=self.getDataSubNode(next_action), object=destination_path,
object_id=object_id)
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)
subscriber.delSignature(object_gid)
xml_confirmation += self.SyncMLConfirmation(cmd_id,
object_gid,status_code,'Delete')
xml_confirmation += self.SyncMLConfirmation(cmd_id,
object_gid,status_code,'Delete')
else: # We want to retrieve more data
signature.setStatus(self.PARTIAL)
#LOG('SyncModif',0,'setPartialXML: %s' % str(previous_partial))
......@@ -1026,8 +952,8 @@ class XMLSyncUtilsMixin(SyncCode):
signature.setPartialXML(previous_partial)
#LOG('SyncModif',0,'previous_partial: %s' % str(previous_partial))
LOG('SyncModif',0,'waiting more data for :%s' % signature.getId())
xml_confirmation += self.SyncMLConfirmation(cmd_id,object_gid,
self.WAITING_DATA,next_action.nodeName)
xml_confirmation += self.SyncMLConfirmation(cmd_id, object_gid,
self.WAITING_DATA, next_action.nodeName)
if conflict_list != [] and signature is not None:
# We had a conflict
signature.setStatus(self.CONFLICT)
......@@ -1121,11 +1047,13 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
if domain.domain_type == self.PUB:
simulate = 1
for subnode in xml_header.childNodes:
if subnode.nodeType == subnode.ELEMENT_NODE and subnode.nodeName == "Source":
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and subnode2.nodeName == 'LocURI':
subscription_url = str(subnode2.childNodes[0].data)
subscriber = domain.getSubscriber(subscription_url)
if subnode.nodeType == subnode.ELEMENT_NODE and \
subnode.nodeName == "Source":
for subnode2 in subnode.childNodes:
if subnode2.nodeType == subnode2.ELEMENT_NODE and \
subnode2.nodeName == 'LocURI':
subscription_url = str(subnode2.childNodes[0].data)
subscriber = domain.getSubscriber(subscription_url)
# We have to check if this message was not already, this can be dangerous
# to update two times the same object
......@@ -1134,6 +1062,7 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
if not correct_message: # We need to send again the message
LOG('SyncModif, no correct message:',0,"sending again...")
last_xml = subscriber.getLastSentMessage()
LOG("last_xml :", 0, last_xml)
if last_xml != '':
has_response = 1
if domain.domain_type == self.PUB: # We always reply
......@@ -1142,7 +1071,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
xml=last_xml,domain=domain)
elif domain.domain_type == self.SUB:
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}
subscriber.setLastSentMessage('')
......@@ -1164,7 +1094,8 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
globals(), locals(), [''])
conduit = getattr(conduit_module, conduit_name)()
# 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,
destination_path=destination_path,
subscriber=subscriber,
......@@ -1178,8 +1109,9 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
# syncml header
if domain.domain_type == self.PUB:
xml(self.SyncMLHeader(subscriber.getSessionId(), subscriber.incrementMessageId(),
subscriber.getSubscriptionUrl(), domain.getPublicationUrl()))
xml(self.SyncMLHeader(subscriber.getSessionId(),
subscriber.incrementMessageId(), subscriber.getSubscriptionUrl(),
domain.getPublicationUrl()))
elif domain.domain_type == self.SUB:
xml(self.SyncMLHeader(domain.getSessionId(), domain.incrementMessageId(),
domain.getPublicationUrl(), domain.getSubscriptionUrl()))
......@@ -1192,11 +1124,11 @@ class XMLSyncUtils(XMLSyncUtilsMixin):
if has_next_action == 0 and not \
(domain.domain_type==self.SUB and alert_code==self.SLOW_SYNC):
(syncml_data,xml_confirmation,cmd_id) = self.getSyncMLData(domain=domain,
remote_xml=remote_xml,
subscriber=subscriber,
destination_path=destination_path,
cmd_id=cmd_id,xml_confirmation=xml_confirmation,
conduit=conduit)
remote_xml=remote_xml,
subscriber=subscriber,
destination_path=destination_path,
cmd_id=cmd_id,xml_confirmation=xml_confirmation,
conduit=conduit)
# syncml body
xml(' <SyncBody>\n')
......
......@@ -114,7 +114,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div>
</td>
<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>
</tr>
<tr>
......@@ -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" />
</td>
</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>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -124,7 +124,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div>
</td>
<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>
</tr>
<tr>
......@@ -140,41 +140,39 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr>
<td align="left" valign="top">
<div class="form-label">
Login
</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
Flow Type
</label></div>
</td>
<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>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Format authentication
Login
</label></div>
</td>
<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>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Type authentication
Password
</label></div>
</td>
<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>
</tr>
</table>
......
......@@ -110,7 +110,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="id_generator" size="40" />
<input type="text" name="synchronization_id_generator" size="40" />
</td>
</tr>
<tr>
......@@ -123,6 +123,19 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="gid_generator" size="40" />
</td>
</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>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -120,7 +120,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="id_generator" size="40" />
<input type="text" name="synchronization_id_generator" size="40" />
</td>
</tr>
<tr>
......@@ -136,39 +136,33 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr>
<td align="left" valign="top">
<div class="form-label">
Login
Flow Type
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="login" size="40" /> </td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Password
</label></div>
</td>
<td align="left" valign="top">
<input type="password" name="password" size="40" />
<SELECT name="flow_type" size="1">
<OPTION value="xml" selected>XML</option>
<OPTION value="text">text</option>
</SELECT>
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Format authentication
Login
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="authentication_format" size="40" />
</td>
</tr>
<input type="text" name="login" size="40" /> </td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Type authentication
Password
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="authentication_type" size="40" />
<input type="password" name="password" size="40" />
</td>
</tr>
<tr>
......
......@@ -46,10 +46,11 @@ try:
from base64 import b64encode, b64decode
except ImportError:
from base64 import encodestring as b64encode, decodestring as b64decode
class TestERP5SyncML(ERP5TypeTestCase):
class TestERP5SyncMLMixin:
# Different variables used for this test
run_all_test = 1
workflow_id = 'edit_workflow'
first_name1 = 'Sebastien'
last_name1 = 'Robin'
......@@ -91,10 +92,6 @@ class TestERP5SyncML(ERP5TypeTestCase):
#subscription_url1 = 'client1@localhost'
#subscription_url2 = 'client2@localhost'
def getTitle(self):
"""
"""
return "ERP5 SyncML"
def afterSetUp(self):
"""Setup."""
......@@ -117,7 +114,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
/person_client1 : empty
/person_client2 : empty
"""
return ('erp5_base',)
return ('erp5_base','fabien_bt')
def getSynchronizationTool(self):
return getattr(self.getPortal(), 'portal_synchronizations', None)
......@@ -134,6 +131,194 @@ class TestERP5SyncML(ERP5TypeTestCase):
def getPortalId(self):
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):
# Test if portal_synchronizations was created
if not run: return
......@@ -152,9 +337,9 @@ class TestERP5SyncML(ERP5TypeTestCase):
LOG('Testing... ',0,'test_02_AddPublication')
portal_id = self.getPortalName()
portal_sync = self.getSynchronizationTool()
portal_sync.manage_addPublication(self.pub_id,self.publication_url,
'/%s/person_server' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
portal_sync.manage_addPublication(self.pub_id,self.publication_url,
'/%s/person_server' % portal_id,'objectValues', self.xml_mapping,
'ERP5Conduit','')
pub = portal_sync.getPublication(self.pub_id)
self.failUnless(pub is not None)
......@@ -165,9 +350,9 @@ class TestERP5SyncML(ERP5TypeTestCase):
LOG('Testing... ',0,'test_03_AddSubscription1')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id1,self.publication_url,
self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
portal_sync.manage_addSubscription(self.sub_id1, self.publication_url,
self.subscription_url1,'/%s/person_client1' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
sub = portal_sync.getSubscription(self.sub_id1)
self.failUnless(sub is not None)
......@@ -178,59 +363,18 @@ class TestERP5SyncML(ERP5TypeTestCase):
LOG('Testing... ',0,'test_04_AddSubscription2')
portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id2,self.publication_url,
self.subscription_url2,'/%s/person_client2' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
portal_sync.manage_addSubscription(self.sub_id2,self.publication_url,
self.subscription_url2,'/%s/person_client2' % portal_id,'objectValues',
self.xml_mapping,'ERP5Conduit','')
sub = portal_sync.getSubscription(self.sub_id2)
self.failUnless(sub is not None)
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=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):
def setupPublicationAndSubscription(self, quiet=0, run=run_all_test):
self.test_02_AddPublication(quiet=1,run=1)
self.test_03_AddSubscription1(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)
def getGid(object):
return object.getTitle()
......@@ -241,9 +385,9 @@ class TestERP5SyncML(ERP5TypeTestCase):
pub.setGidGenerator(getGid)
sub1.setGidGenerator(getGid)
sub2.setGidGenerator(getGid)
pub.setIdGenerator('_generateNextId')
sub1.setIdGenerator('_generateNextId')
sub2.setIdGenerator('_generateNextId')
pub.setSynchronizationIdGenerator('_generateNextId')
sub1.setSynchronizationIdGenerator('_generateNextId')
sub2.setSynchronizationIdGenerator('_generateNextId')
def test_05_GetSynchronizationList(self, quiet=0, run=run_all_test):
# This test the getSynchronizationList, ie,
......@@ -315,73 +459,6 @@ class TestERP5SyncML(ERP5TypeTestCase):
c_local_role = person_client1.get_local_roles()
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):
# We will try to populate the folder person_client1
# with the data form person_server
......@@ -408,26 +485,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
self.failUnless(nb_message2==self.nb_message_first_synchronization)
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(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)
self.checkFirstSynchronization(id=self.id1, nb_person=nb_person)
def test_09_FirstSynchronizationWithLongLines(self, quiet=0, run=run_all_test):
# We will try to populate the folder person_client1
......@@ -497,33 +555,6 @@ class TestERP5SyncML(ERP5TypeTestCase):
# for each subscriber
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):
portal_sync = self.getSynchronizationTool()
person_server = self.getPersonServer()
......@@ -987,7 +1018,7 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person_s.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
solve it by taking one full version of documents.
......@@ -1410,27 +1441,7 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=='
sub.setAuthenticationFormat(auth_format)
sub.setAuthenticationType(auth_type)
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 test_35_authentication(self, quiet=0, run=1):
def test_35_authentication(self, quiet=0, run=run_all_test):
"""
we will test
- if we can't synchronize without good authentication for an
......@@ -1507,7 +1518,6 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=='
self.synchronize(self.sub_id1)
self.verifyFirstNameAndLastNameAreNotSynchronized(self.first_name1,
self.last_name1, person1_s, person1_c)
#with the good password
self.addAuthenticationToSubscription(self.sub_id1, 'fab', 'myPassword',
......
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