Commit b14f6814 authored by Sebastien Robin's avatar Sebastien Robin
Browse files

- add source_uri and target_uri fields in the dtml files

- change the subscriber property to use id, gid and rid
- encode the gid in base16
- change some parts to make VCard synchronization working
- remove some logs
- change the status implementation to use xpath expressions
- use utf-8 everywhere


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@14954 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 6b7e714c
......@@ -139,7 +139,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
xml = self.convertToXml(xml)
if xml is None:
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:
......@@ -153,7 +152,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if object_id is None:
object_id = self.getAttribute(xml,'id')
docid = self.getObjectDocid(xml)
#LOG('addNode',0,'object_id: %s' % object_id)
if object_id is not None:
if sub_object is None:
try:
......@@ -181,7 +179,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
elif xml.nodeName in self.XUPDATE_INSERT_OR_ADD \
and self.getSubObjectDepth(xml)>=1:
sub_object_id = self.getSubObjectId(xml)
#LOG('addNode',0,'getSubObjectModification number: %s' % sub_object_id)
if previous_xml is not None and sub_object_id is not None:
#LOG('addNode',0,'previous xml is not none and also sub_object_id')
# Find the previous xml corresponding to this subobject
......@@ -242,7 +239,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
sub_object = object._getOb(sub_object_id)
sub_xml = self.getSubObjectXupdate(xml)
conflict_list += self.deleteNode(xml=sub_xml,object=sub_object,
force=force, simulate=simulate, **kw)
force=force, simulate=simulate, **kw)
except (KeyError, AttributeError, TypeError):
#LOG('ERP5Conduit',0,'deleteNode, Unable to delete SubObject: %s' % str(sub_object_id))
pass
......@@ -385,7 +382,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
#subscriber_value=data)] # not needed any more
# We will now apply the argument with the method edit
if args != {} and (isConflict==0 or force) and (not simulate):
#LOG('updateNode',0,'object._edit, args: %s' % str(args))
#object._edit(**args)
self.editDocument(object=object,**args)
# It is sometimes required to do something after an edit
......@@ -394,12 +390,10 @@ 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']
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']
elif keyword in (self.local_role_tag,self.local_permission_tag) and not simulate:
......@@ -433,8 +427,9 @@ 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:
......@@ -470,7 +465,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
This lookd inside the args dictionnary and then
convert any unicode string to string
"""
#LOG('ERP5Conduit.getFormatedArgs',0,'args: %s' % str(args))
new_args = {}
for keyword in args.keys():
data = args[keyword]
......@@ -646,7 +640,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
xml = self.convertToXml(xml)
for subnode in self.getElementNodeList(xml):
if subnode.nodeName==self.xml_object_tag:
LOG('getSub0bjectXml: object_id:',0,object_id)
if object_id == self.getAttribute(subnode,'id'):
return subnode
return None
......@@ -700,7 +693,6 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if xml is None:
return
if type(xml) in (type('a'),type(u'a')):
#LOG('Conduit.convertToXml xml',0,repr(xml))
if type(xml) is type(u'a'):
xml = xml.encode('utf-8')
xml = Parse(xml)
......@@ -981,7 +973,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
force=force, simulate=simulate, **kw)['conflict_list']
elif subnode.nodeName in self.XUPDATE_DEL:
conflict_list += conduit.deleteNode(xml=sub_xupdate, object=object, \
force=force, simulate=simulate, **kw)
force=force, simulate=simulate, **kw)
elif subnode.nodeName in self.XUPDATE_UPDATE:
conflict_list += conduit.updateNode(xml=sub_xupdate, object=object, \
force=force, simulate=simulate, **kw)
......@@ -1065,27 +1057,19 @@ class ERP5Conduit(XMLSyncUtilsMixin):
This is really usefull if you want to write your own Conduit.
"""
conflict_list = []
#LOG('addNode, workflow_history isHistoryAdd:',0,self.isHistoryAdd(xml))
# We want to add a workflow action
wf_tool = getToolByName(object,'portal_workflow')
wf_id = self.getAttribute(xml,'id')
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())#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)
#LOG('addNode, workflow_history xml:',0,xml)
#for action in self.getWorkflowActionFromXml(xml):
status = self.getStatusFromXml(xml)
#LOG('addNode, status:',0,status)
add_action = self.isWorkflowActionAddable(object=object,
status=status,wf_tool=wf_tool,
wf_id=wf_id,xml=xml)
#LOG('addNode, workflow_history add_action:',0,add_action)
if add_action and not simulate:
#LOG('addNode, setting status:',0,'ok')
wf_tool.setStatusOf(wf_id,object,status)
# Specific CPS, try to remove duplicate lines in portal_repository._histories
......@@ -1191,4 +1175,3 @@ class ERP5Conduit(XMLSyncUtilsMixin):
xml_string = buf.getvalue()
buf.close()
return xml_string
......@@ -152,7 +152,7 @@ class Publication(Subscription):
constructors = (addPublication,)
# Constructor
def __init__(self, id, title, publication_url, destination_path,
def __init__(self, id, title, publication_url, destination_path, source_uri,
query, xml_mapping, conduit, gpg_key, id_generator, gid_generator,
media_type, auth_required=False, authentication_format='',
authentication_type=''):
......@@ -162,6 +162,7 @@ class Publication(Subscription):
self.id = id
self.publication_url = publication_url
self.destination_path = destination_path
self.setSourceURI(source_uri)
self.setQuery(query)
self.xml_mapping = xml_mapping
#self.list_subscribers = PersistentMapping()
......
......@@ -110,7 +110,7 @@ class PublicationSynchronization(XMLSyncUtils):
if authentication_format == publication.getAuthenticationFormat():
if authentication_type == publication.getAuthenticationType():
decoded = subscriber.decode(authentication_format, data)
if decoded not in ('', None) and decoded.__contains__(':'):
if decoded not in ('', None) and ':' in decoded:
(login, password) = decoded.split(':')
uf = self.getPortalObject().acl_users
for plugin_name, plugin in uf._getOb('plugins').listPlugins(
......@@ -124,6 +124,8 @@ class PublicationSynchronization(XMLSyncUtils):
newSecurityManager(None, user)
subscriber.setUser(login)
break
else:
auth_code=self.UNAUTHORIZED
#in all others cases, the auth_code is set to UNAUTHORIZED
......@@ -148,6 +150,13 @@ class PublicationSynchronization(XMLSyncUtils):
subscriber.getSubscriptionUrl(), publication.getPublicationUrl(),
subscriber.getLastAnchor(), subscriber.getNextAnchor()))
cmd_id += 1
else:
# chal message
xml(self.SyncMLChal(cmd_id, "SyncHdr",
publication.getPublicationUrl(), subscriber.getSubscriptionUrl(),
publication.getAuthenticationFormat(),
publication.getAuthenticationType(), self.AUTH_REQUIRED))
cmd_id += 1
xml(' </SyncBody>\n')
xml('</SyncML>\n')
xml_a = ''.join(xml_list)
......
......@@ -42,9 +42,10 @@ from zLOG import LOG
import md5
try:
from base64 import b64encode, b64decode
from base64 import b64encode, b64decode, b16encode, b16decode
except ImportError:
from base64 import encodestring as b64encode, decodestring as b64decode
from base64 import encodestring as b64encode, decodestring as b64decode, \
encodestring as b16encode, decodestring as b16decode
#class Conflict(SyncCode, Implicit):
class Conflict(SyncCode, Base):
......@@ -250,13 +251,16 @@ class Signature(Folder,SyncCode):
isPortalContent = 0 # Make sure RAD generated accessors at the class level
# Constructor
def __init__(self,gid=None, id=None, status=None, xml_string=None,object=None):
self.setGid(gid)
def __init__(self, id=None, rid=None, status=None, xml_string=None,
object=None):
if object is not None:
self.setPath(object.getPhysicalPath())
self.setObjectId(object.getId())
else:
self.setPath(None)
self.setId(id)
self.setGid(id)
self.setRid(rid)
self.status = status
self.setXML(xml_string)
self.partial_xml = None
......@@ -280,7 +284,7 @@ class Signature(Folder,SyncCode):
if temp_xml is not None:
# This happens when we have sent the xml
# and we just get the confirmation
self.setXML(self.getTempXML())
self.setXML(temp_xml)
self.setTempXML(None)
self.setPartialXML(None)
self.setSubscriberXupdate(None)
......@@ -367,7 +371,7 @@ class Signature(Folder,SyncCode):
def getXML(self):
"""
set the XML corresponding to the object
get the XML corresponding to the object
"""
xml = getattr(self,'xml',None)
if xml == '':
......@@ -437,18 +441,22 @@ class Signature(Folder,SyncCode):
"""
set the rid
"""
if rid is type(u'a'):
rid = rid.encode('utf-8')
self.rid = rid
def getRid(self):
"""
get the rid
"""
return self.rid
return getattr(self, 'rid', None)
def setId(self, id):
"""
set the id
"""
if id is type(u'a'):
id = id.encode('utf-8')
self.id = id
def getId(self):
......@@ -459,16 +467,32 @@ class Signature(Folder,SyncCode):
def setGid(self, gid):
"""
set the id
set the gid
"""
if gid is type(u'a'):
gid = gid.encode('utf-8')
self.gid = gid
def getGid(self):
"""
get the id
get the gid
"""
return self.gid
def setObjectId(self, id):
"""
set the id of the object associated to this signature
"""
if id is type(u'a'):
id = id.encode('utf-8')
self.object_id = id
def getObjectId(self):
"""
get the id of the object associated to this signature
"""
return getattr(self, 'object_id', None)
def setPartialXML(self, xml):
"""
Set the partial string we will have to
......@@ -545,7 +569,7 @@ class Signature(Folder,SyncCode):
"""
Returns the object corresponding to this signature
"""
return self.getParentValue().getObjectFromGid(self.getGid())
return self.getParentValue().getObjectIdGid(self.getObjectId())
def checkSynchronizationNeeded(self, object):
"""
......@@ -643,8 +667,9 @@ class Subscription(Folder, SyncCode):
# Constructor
def __init__(self, id, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key, id_generator,
gid_generator, media_type, login, password):
destination_path, source_uri, target_uri, query, xml_mapping,
conduit, gpg_key, id_generator, gid_generator, media_type, login,
password):
"""
We need to create a dictionnary of
signatures of documents which belong to the synchronisation
......@@ -654,6 +679,8 @@ class Subscription(Folder, SyncCode):
self.publication_url = (publication_url)
self.subscription_url = str(subscription_url)
self.destination_path = str(destination_path)
self.setSourceURI(source_uri)
self.setTargetURI(target_uri)
self.setQuery(query)
self.setXMLMapping(xml_mapping)
self.anchor = None
......@@ -685,15 +712,31 @@ class Subscription(Folder, SyncCode):
setter for title
"""
self.title = value
def setSourceURI(self, value):
"""
setter for source_uri
"""
self.source_uri = value
def getSourceURI(self):
"""
getter for the source_uri (the local path of the subscription)
"""
return getattr(self, 'source_uri', None)
def setTargetURI(self, value):
"""
setter for target_uri
"""
self.target_uri = value
# Accessors
def getRemoteId(self, id, path=None):
def getTargetURI(self):
"""
Returns the remote id from a know local id
Returns None if...
path allows to implement recursive sync
getter for the target_uri (the distant Publication we want to synchronize
with)
"""
pass
return getattr(self, 'target_uri', None)
def getSynchronizationType(self, default=None):
"""
......@@ -749,7 +792,7 @@ class Subscription(Folder, SyncCode):
self.last_message_id = message_id
return True
def initLastMessageId(self, last_message_id=None):
def initLastMessageId(self, last_message_id=0):
"""
set the last message id to 0
"""
......@@ -767,12 +810,11 @@ class Subscription(Folder, SyncCode):
"""
self.last_sent_message = xml
def getLocalId(self, rid, path=None):
def getDomainType(self):
"""
Returns the local id from a know remote id
Returns None if...
return the ID
"""
pass
return self.domain_type
def getId(self):
"""
......@@ -780,12 +822,6 @@ class Subscription(Folder, SyncCode):
"""
return self.id
def getDomainType(self):
"""
return the ID
"""
return self.domain_type
def setId(self, id):
"""
set the ID
......@@ -934,13 +970,13 @@ class Subscription(Folder, SyncCode):
"""
return the format of authentication
"""
return getattr(self, 'authentication_format', '')
return getattr(self, 'authentication_format', 'b64')
def getAuthenticationType(self):
"""
return the type of authentication
"""
return getattr(self, 'authentication_type', '')
return getattr(self, 'authentication_type', 'syncml:auth-basic')
def setAuthenticationFormat(self, authentication_format):
"""
......@@ -969,7 +1005,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))
o_gid = b16encode(o_gid)
return o_gid
def getObjectFromGid(self, gid):
......@@ -977,16 +1013,13 @@ class Subscription(Folder, SyncCode):
This tries to get the object with the given gid
This uses the query if it exist
"""
signature = self.getSignature(gid)
signature = self.getSignatureFromGid(gid)
# First look if we do already have the mapping between
# the id and the gid
object_list = self.getObjectList()
destination = self.getDestination()
# LOG('getObjectFromGid', 0, 'self: %s' % self)
# LOG('getObjectFromGid',0,'gid: %s' % repr(gid))
# LOG('getObjectFromGid oject_list',0,object_list)
if signature is not None and signature.getId() is not None:
o_id = signature.getId()
if signature is not None and signature.getObjectId() is not None:
o_id = signature.getObjectId()
o = None
try:
o = destination._getOb(o_id)
......@@ -998,7 +1031,18 @@ class Subscription(Folder, SyncCode):
o_gid = self.getGidFromObject(o)
if o_gid == gid:
return o
# LOG('getObjectFromGid',0,'returning None')
LOG('getObjectFromGid',0,'returning None')
return None
def getObjectFromId(self, id):
"""
return the object corresponding to the id
"""
object_list = self.getObjectList()
#XXX very slow with lot of objects
for object in object_list:
if object.getId() == id:
return object
return None
# def setOneWaySyncFromServer(self,value):
......@@ -1195,28 +1239,83 @@ class Subscription(Folder, SyncCode):
"""
add a Signature to the subscription
"""
if signature.getGid() in self.objectIds():
self._delObject(signature.getGid())
self._setObject(signature.getGid(), aq_base(signature) )
if signature.getGid() in self.getGidList():
self.delSignature(signature.getGid())
self._setObject(signature.getGid(), aq_base(signature))
def delSignature(self, gid):
"""
add a Signature to the subscription
del a Signature of the subscription
"""
#del self.signatures[gid]
self._delObject(gid)
def getSignature(self, gid):
def getSignatureFromObjectId(self, id):
"""
add a Signature to the subscription
return the signature corresponding to the gid
"""
o = None
# XXX very slow
for signature in self.getSignatureList():
if id == signature.getObjectId():
o = signature
break
return o
def getSignatureFromGid(self, gid):
"""
return the signature corresponding to the gid
"""
o = None
# XXX very slow
for signature in self.getSignatureList():
if gid == signature.getGid():
o = signature
break
return o
def getSignatureFromRid(self, rid):
"""
return the signature corresponding to the rid
"""
o = None
if gid in self.objectIds():
o = self._getOb(gid)
#if o is not None:
# return o.__of__(self)
# XXX very slow
for signature in self.getSignatureList():
if rid == signature.getRid():
o = signature
break
return o
def getObjectIdList(self):
"""
Returns the list of gids from signature
"""
object_id_list = []
for signature in self.getSignatureList():
if signature.getObjectId() is not None:
object_id_list.append(signature.getObjectId())
return object_id_list
def getGidList(self):
"""
Returns the list of gids from signature
"""
gid_list = []
for signature in self.getSignatureList():
if signature.getGid() is not None:
gid_list.append(signature.getGid())
return gid_list
def getRidList(self):
"""
Returns the list of rids from signature
"""
rid_list = []
for signature in self.getSignatureList():
if signature.getRid() is not None:
rid_list.append(signature.getRid())
return rid_list
def getSignatureList(self):
"""
add a Signature to the subscription
......@@ -1238,12 +1337,6 @@ class Subscription(Folder, SyncCode):
for id in self.objectIds():
self._delObject(id)
def getGidList(self):
"""
Returns the list of ids from signature
"""
return self.objectIds()
def getConflictList(self):
"""
Return the list of all conflicts from all signatures
......@@ -1280,20 +1373,6 @@ class Subscription(Folder, SyncCode):
new_list.append(o)
self.setRemainingObjectPathList(new_list)
# def getCurrentObject(self):
# """
# When we send some partial data, then we should
# always synchronize the same object until it is finished
# """
# getattr(self,'current_object',None)
#
# def setCurrentObject(self,object):
# """
# When we send some partial data, then we should
# always synchronize the same object until it is finished
# """
# setattr(self,'current_object',object)
def startSynchronization(self):
"""
Set the status of every object as NOT_SYNCHRONIZED
......
......@@ -49,7 +49,7 @@ class SubscriptionSynchronization(XMLSyncUtils):
# syncml header
xml(self.SyncMLHeader(subscription.incrementSessionId(),
subscription.incrementMessageId(), subscription.getPublicationUrl(),
subscription.getSubscriptionUrl()))
subscription.getSubscriptionUrl(), source_name=subscription.getLogin()))
# syncml body
xml(' <SyncBody>\n')
......@@ -59,16 +59,15 @@ class SubscriptionSynchronization(XMLSyncUtils):
# alert message
xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
subscription.getPublicationUrl(),
subscription.getDestinationPath(),
subscription.getTargetURI(),
subscription.getSourceURI(),
subscription.getLastAnchor(),
subscription.getNextAnchor()))
cmd_id += 1
xml(' <Put>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id)
cmd_id += 1
xml(' </Put>\n')
syncml_put = self.SyncMLPut(cmd_id, subscription)
if syncml_put not in ('', None):
xml(syncml_put)
cmd_id += 1
xml(' </SyncBody>\n')
xml('</SyncML>\n')
xml_a = ''.join(xml_list)
......@@ -79,20 +78,17 @@ class SubscriptionSynchronization(XMLSyncUtils):
return {'has_response':1,'xml':xml_a}
def SubSync(self, id, msg=None, RESPONSE=None):
def SubSync(self, subscription, msg=None, RESPONSE=None):
"""
This is the synchronization method for the client
"""
#LOG('SubSync',0,'starting... id: %s' % str(id))
#LOG('SubSync',0,'starting... msg: %s' % str(msg))
response = None #check if subsync replies to this messages
subscription = self.getSubscription(id)
if msg==None and (subscription.getSubscriptionUrl()).find('file')>=0:
msg = self.readResponse(sync_id=id,
msg = self.readResponse(sync_id=subscription.getSourceURI(),
from_url=subscription.getSubscriptionUrl())
if msg==None:
response = self.SubSyncInit(self.getSubscription(id))
response = self.SubSyncInit(subscription)
else:
xml_client = msg
if isinstance(xml_client, str) or isinstance(xml_client, unicode):
......@@ -105,21 +101,24 @@ class SubscriptionSynchronization(XMLSyncUtils):
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)
#LOG('auth_required :',0, 'format:%s, type:%s' % (authentication_format, authentication_type))
if authentication_format is not None and \
authentication_type is not None:
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)
response = self.SubSyncCred(subscription, xml_client)
elif status_code == self.UNAUTHORIZED:
#LOG('readResponse', 0, 'Bad authentication')
LOG('readResponse', 0, 'Bad authentication')
return {'has_response':0,'xml':xml_client}
else:
response = self.SubSyncModif(self.getSubscription(id), xml_client)
response = self.SubSyncModif(subscription, xml_client)
else:
response = self.SubSyncModif(self.getSubscription(id), xml_client)
response = self.SubSyncModif(subscription, xml_client)
if RESPONSE is not None:
......@@ -127,43 +126,43 @@ class SubscriptionSynchronization(XMLSyncUtils):
else:
return response
def SubSyncCred (self, id, msg=None, RESPONSE=None):
def SubSyncCred (self, subscription, msg=None, RESPONSE=None):
"""
This method send crendentials
"""
#LOG('SubSyncCred',0,'starting... id: %s' % str(id))
#LOG('SubSyncCred',0,'starting... msg: %s' % str(msg))
cmd_id = 1 # specifies a SyncML message-unique command identifier
subscription = self.getSubscription(id)
xml_list = []
xml = xml_list.append
xml('<SyncML>\n')
# syncml header
data = "%s:%s" % (subscription.getLogin(), subscription.getPassword())
data=subscription.encode(subscription.getAuthenticationFormat(), data)
xml(self.SyncMLHeader(subscription.getSessionId(),
subscription.incrementMessageId(), subscription.getPublicationUrl(),
subscription.getSubscriptionUrl(), dataCred=data,
xml(self.SyncMLHeader(
subscription.incrementSessionId(),
subscription.incrementMessageId(),
subscription.getPublicationUrl(),
subscription.getSubscriptionUrl(),
source_name=subscription.getLogin(),
dataCred=data,
authentication_format=subscription.getAuthenticationFormat(),
authentication_type=subscription.getAuthenticationType()))
# syncml body
xml(' <SyncBody>\n')
# We have to set every object as NOT_SYNCHRONIZED
subscription.startSynchronization()
# alert message
xml(self.SyncMLAlert(cmd_id, subscription.getSynchronizationType(),
subscription.getPublicationUrl(),
subscription.getDestinationPath(),
subscription.getTargetURI(),
subscription.getSourceURI(),
subscription.getLastAnchor(),
subscription.getNextAnchor()))
cmd_id += 1
xml(' <Put>\n')
xml(' <CmdID>%s</CmdID>\n' % cmd_id)
xml(self.SyncMLPut(cmd_id, subscription))
cmd_id += 1
xml(' </Put>\n')
xml(' <Final/>\n')
xml(' </SyncBody>\n')
xml('</SyncML>\n')
xml_a = ''.join(xml_list)
......
......@@ -41,6 +41,8 @@ class SyncCode(Persistent):
# SyncML Status Codes
SUCCESS = 200
ITEM_ADDED = 201
CHUNK_OK = 214
CONFLICT = 409 # A conflict is detected
CONFLICT_MERGE = 207 # We have merged the two versions, sending
......
......@@ -161,7 +161,7 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent,
'manage_addPublication')
def manage_addPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key,
source_uri, query, xml_mapping, conduit, gpg_key,
synchronization_id_generator=None, gid_generator=None,
media_type=None, auth_required=0, authentication_format='',
authentication_type='', RESPONSE=None):
......@@ -174,7 +174,7 @@ 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,
source_uri, query, xml_mapping, conduit, gpg_key,
synchronization_id_generator, gid_generator, media_type,
auth_required, authentication_format, authentication_type)
folder._setObject( new_id, pub )
......@@ -187,7 +187,8 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent,
'manage_addSubscription')
def manage_addSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key,
destination_path, source_uri, target_uri, query,
xml_mapping, conduit, gpg_key,
synchronization_id_generator=None, gid_generator=None,
media_type=None, login=None, password=None,
RESPONSE=None):
......@@ -201,7 +202,8 @@ class SynchronizationTool( SubscriptionSynchronization,
folder = self.getObjectContainer()
new_id = self.getSubscriptionIdFromTitle(title)
sub = Subscription(new_id, title, publication_url, subscription_url,
destination_path, query, xml_mapping, conduit, gpg_key,
destination_path, source_uri, target_uri, query,
xml_mapping, conduit, gpg_key,
synchronization_id_generator, gid_generator, media_type,
login, password)
folder._setObject( new_id, sub )
......@@ -214,7 +216,7 @@ class SynchronizationTool( SubscriptionSynchronization,
security.declareProtected(Permissions.ModifyPortalContent,
'manage_editPublication')
def manage_editPublication(self, title, publication_url, destination_path,
query, xml_mapping, conduit, gpg_key,
source_uri, query, xml_mapping, conduit, gpg_key,
synchronization_id_generator, gid_generator,
media_type=None, auth_required=0,
authentication_format='', authentication_type='',
......@@ -226,6 +228,7 @@ class SynchronizationTool( SubscriptionSynchronization,
pub.setTitle(title)
pub.setPublicationUrl(publication_url)
pub.setDestinationPath(destination_path)
pub.setSourceURI(source_uri)
pub.setQuery(query)
pub.setConduit(conduit)
pub.setXMLMapping(xml_mapping)
......@@ -243,9 +246,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,
synchronization_id_generator, gid_generator, media_type=None,login='',
password='', RESPONSE=None):
destination_path, source_uri, target_uri, query, xml_mapping, conduit,
gpg_key, synchronization_id_generator, gid_generator, media_type=None,
login='', password='', RESPONSE=None):
"""
modify a subscription
"""
......@@ -253,6 +256,8 @@ class SynchronizationTool( SubscriptionSynchronization,
sub.setTitle(title)
sub.setPublicationUrl(publication_url)
sub.setDestinationPath(destination_path)
sub.setSourceURI(source_uri)
sub.setTargetURI(target_uri)
sub.setQuery(query)
sub.setConduit(conduit)
sub.setXMLMapping(xml_mapping)
......@@ -319,7 +324,7 @@ class SynchronizationTool( SubscriptionSynchronization,
"""
reset a subscription
"""
self.SubSync(title)
self.SubSync(self.getSubscription(title))
if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions')
......@@ -371,7 +376,7 @@ class SynchronizationTool( SubscriptionSynchronization,
def getSubscription(self, title):
"""
Returns the subscription with this id
Returns the subscription with this title
"""
for s in self.getSubscriptionList():
if s.getTitle() == title:
......@@ -489,7 +494,7 @@ class SynchronizationTool( SubscriptionSynchronization,
subscriber_list = [domain]
#LOG('getSynchronizationState, subscriber_list:',0,subscriber_list)
for subscriber in subscriber_list:
signature = subscriber.getSignature(o_id)
signature = subscriber.getSignatureFromObjectId(o_id)
if signature is not None:
state = signature.getStatus()
#LOG('getSynchronizationState:',0,'sub.dest :%s, state: %s' % \
......@@ -514,7 +519,7 @@ class SynchronizationTool( SubscriptionSynchronization,
subscriber = conflict.getSubscriber()
# get the signature:
#LOG('p_sync.applyPublisherValue, subscriber: ',0,subscriber)
signature = subscriber.getSignature(object.getId()) # XXX may be change for rid
signature = subscriber.getSignatureFromObjectId(object.getId()) # XXX may be change for rid
copy_path = conflict.getCopyPath()
#LOG('p_sync.applyPublisherValue, copy_path: ',0,copy_path)
signature.delConflict(conflict)
......@@ -690,7 +695,7 @@ class SynchronizationTool( SubscriptionSynchronization,
subscriber = conflict.getSubscriber()
# get the signature:
#LOG('p_sync.setRemoteObject, subscriber: ',0,subscriber)
signature = subscriber.getSignature(object.getId()) # XXX may be change for rid
signature = subscriber.getSignatureFromObjectId(object.getId()) # XXX may be change for rid
# Import the conduit and get it
conduit_name = subscriber.getConduit()
conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
......@@ -885,12 +890,22 @@ class SynchronizationTool( SubscriptionSynchronization,
opener = urllib2.build_opener(proxy_handler, proxy_auth_handler,
auth_handler, urllib2.HTTPHandler)
urllib2.install_opener(opener)
to_encode = {'text':xml,'sync_id':sync_id}
encoded = urllib.urlencode(to_encode)
to_encode = {}
head = '<?xml version="1.0" encoding="UTF-8"?>'
to_encode['text'] = head + xml
to_encode['sync_id'] = sync_id
headers = {'Content-type': 'application/vnd.syncml+xml'}
#XXX bad hack for synchronization with erp5
if to_url.find('readResponse')<0:
to_url = to_url + '/portal_synchronizations/readResponse'
request = urllib2.Request(url=to_url,data=encoded)
#result = urllib2.urlopen(request).read()
encoded = urllib.urlencode(to_encode)
data=encoded
request = urllib2.Request(url=to_url, data=data)
#XXX only to synchronize with other server than erp5 (must be improved):
# data=head+xml
# request = urllib2.Request(to_url, data, headers)
try:
result = urllib2.urlopen(request).read()
except socket.error, msg:
......@@ -898,10 +913,12 @@ class SynchronizationTool( SubscriptionSynchronization,
sync_id=sync_id, xml=xml, domain=domain)
LOG('sendHttpResponse, socket ERROR:',0,msg)
return
except urllib2.URLError, msg:
LOG("sendHttpResponse, can't open url %s :" % to_url, 0, msg)
return
#LOG('sendHttpResponse, before result, domain:',0,domain)
#LOG('sendHttpResponse, result:',0,result)
if domain is not None:
if domain.domain_type == self.SUB:
gpg_key = domain.getGPGKey()
......@@ -929,7 +946,7 @@ class SynchronizationTool( SubscriptionSynchronization,
if len(message_list) == 0:
for subscription in self.getSubscriptionList():
#LOG('sync, subcription:',0,subscription)
self.activate(activity='RAMQueue').SubSync(subscription.getTitle())
self.activate(activity='RAMQueue').SubSync(subscription)
security.declarePublic('readResponse')
def readResponse(self, text=None, sync_id=None, to_url=None, from_url=None):
......@@ -937,9 +954,6 @@ class SynchronizationTool( SubscriptionSynchronization,
We will look at the url and we will see if we need to send mail, http
response, or just copy to a file.
"""
#LOG('readResponse, ',0,'starting')
#LOG('readResponse, self.getPhysicalPath: ',0,self.getPhysicalPath())
#LOG('readResponse, sync_id: ',0,sync_id)
# Login as a manager to make sure we can create objects
uf = self.acl_users
user = uf.getUserById('syncml').__of__(uf)
......@@ -994,9 +1008,9 @@ class SynchronizationTool( SubscriptionSynchronization,
for subscription in self.getSubscriptionList():
if subscription.getSubscriptionUrl()==url and \
subscription.getTitle()==sync_id:
result = self.activate(activity='RAMQueue').SubSync(sync_id,
text)
#result = self.SubSync(sync_id,xml)
result = self.activate(activity='RAMQueue').SubSync(\
self.getSubscription(sync_id), text)
#result = self.SubSync(self.getSubscription(sync_id),xml)
# we use from only if we have a file
elif isinstance(from_url, str):
......@@ -1041,24 +1055,4 @@ class SynchronizationTool( SubscriptionSynchronization,
conduit_object = getattr(conduit_module, conduit)()
return conduit_object.addNode(**kw)
# security.declarePrivate('notify_sync')
# def notify_sync(self, event_type, object, infos):
# """Notification from the event service.
#
# # XXX very specific to cps
#
# Called when an object is added/deleted/modified.
# Update the date of sync
# """
# from Products.CPSCore.utils import _isinstance
# from Products.CPSCore.ProxyBase import ProxyBase
#
# if event_type in ('sys_modify_object',
# 'modify_object'):
# if not(_isinstance(object, ProxyBase)):
# repotool = getToolByName(self, 'portal_repository')
# if repotool.isObjectInRepository(object):
# object_id = object.getId()
InitializeClass( SynchronizationTool )
This diff is collapsed.
......@@ -67,6 +67,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="destination_path" value="<dtml-var getDestinationPath>" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Source URI
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="source_uri" size="40" value="<dtml-var getSourceURI>" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -77,6 +77,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="destination_path" value="<dtml-var getDestinationPath>" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Source URI
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="source_uri" size="40" value="<dtml-var getSourceURI>" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Target URI
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="target_uri" size="40" value="<dtml-var getTargetURI>" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -63,6 +63,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="destination_path" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Source URI
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="source_uri" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -73,6 +73,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="destination_path" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Source URI
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="source_uri" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Target URI
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="target_uri" size="40" />
</td>
</tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
......
......@@ -43,9 +43,10 @@ from Products.ERP5SyncML.SyncCode import SyncCode
from zLOG import LOG
try:
from base64 import b64encode, b64decode
from base64 import b64encode, b64decode, b16encode, b16decode
except ImportError:
from base64 import encodestring as b64encode, decodestring as b64decode
from base64 import encodestring as b64encode, decodestring as b64decode, \
encodestring as b16encode, decodestring as b16decode
class TestERP5SyncMLMixin:
......@@ -195,10 +196,10 @@ class TestERP5SyncMLMixin:
file.write('')
file.close()
nb_message = 1
result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription)
while result['has_response']==1:
portal_sync.PubSync(publication.getTitle())
result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription)
nb_message += 1 + result['has_response']
return nb_message
......@@ -226,16 +227,16 @@ class TestERP5SyncMLMixin:
file.write('')
file.close()
nb_message = 1
result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription)
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())
result = portal_sync.SubSync(subscription)
result = portal_sync.SubSync(subscription)
result = portal_sync.SubSync(subscription)
nb_message += 1 + result['has_response']
return nb_message
......@@ -337,9 +338,15 @@ class TestERP5SyncML(TestERP5SyncMLMixin, 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(title=self.pub_id,
publication_url=self.publication_url,
destination_path='/%s/person_server' % portal_id,
source_uri='Person',
query='objectValues',
xml_mapping=self.xml_mapping,
conduit='ERP5Conduit',
gpg_key='',
gid_generator='getId')
pub = portal_sync.getPublication(self.pub_id)
self.failUnless(pub is not None)
......@@ -350,9 +357,17 @@ class TestERP5SyncML(TestERP5SyncMLMixin, 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(title=self.sub_id1,
publication_url=self.publication_url,
subscription_url=self.subscription_url1,
destination_path='/%s/person_client1' % portal_id,
source_uri='Person',
target_uri='Person',
query='objectValues',
xml_mapping=self.xml_mapping,
conduit='ERP5Conduit',
gpg_key='',
gid_generator='getId')
sub = portal_sync.getSubscription(self.sub_id1)
self.failUnless(sub is not None)
......@@ -363,9 +378,17 @@ class TestERP5SyncML(TestERP5SyncMLMixin, 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(title=self.sub_id2,
publication_url=self.publication_url,
subscription_url=self.subscription_url2,
destination_path='/%s/person_client2' % portal_id,
source_uri='Person',
target_uri='Person',
query='objectValues',
xml_mapping=self.xml_mapping,
conduit='ERP5Conduit',
gpg_key='',
gid_generator='getId')
sub = portal_sync.getSubscription(self.sub_id2)
self.failUnless(sub is not None)
......@@ -530,7 +553,7 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
# By default we can just give the id
portal_sync = self.getSynchronizationTool()
publication = portal_sync.getPublication(self.pub_id)
object = publication.getObjectFromGid(self.id1)
object = publication.getObjectFromId(self.id1)
self.failUnless(object is not None)
self.failUnless(object.getId()==self.id1)
......@@ -994,10 +1017,11 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
publication = portal_sync.getPublication(self.pub_id)
self.failUnless(len(publication.getObjectList())==nb_person)
gid = self.first_name1 + ' ' + self.last_name1 # ie the title 'Sebastien Robin'
gid = b16encode(gid)
person_c1 = subscription1.getObjectFromGid(gid)
id_c1 = person_c1.getId()
self.failUnless(id_c1 in ('1','2')) # id given by the default generateNewId
person_s = publication.getObjectFromGid(gid)
person_s = publication.getSubscriber(self.subscription_url1).getObjectFromGid(gid)
id_s = person_s.getId()
self.failUnless(id_s==self.id1)
# This will test updating object
......@@ -1014,7 +1038,7 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
self.checkSynchronizationStateIsSynchronized()
self.failUnless(len(subscription1.getObjectList())==(nb_person-1))
self.failUnless(len(publication.getObjectList())==(nb_person-1))
person_s = publication.getObjectFromGid(gid)
person_s = publication.getSubscriber(self.subscription_url1).getObjectFromGid(gid)
person_c1 = subscription1.getObjectFromGid(gid)
self.failUnless(person_s.getDescription()==self.description3)
self.failUnless(person_c1.getDescription()==self.description3)
......@@ -1299,9 +1323,17 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
LOG('Testing... ',0,'test_32_AddOneWaySubscription')
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', '', 'ERP5Conduit', '')
portal_sync.manage_addSubscription(title=self.sub_id1,
publication_url=self.publication_url,
subscription_url=self.subscription_url1,
destination_path='/%s/person_client1' % portal_id,
source_uri='Person',
target_uri='Person',
query='objectValues',
xml_mapping='',
conduit='ERP5Conduit',
gpg_key='',
gid_generator='getId')
sub = portal_sync.getSubscription(self.sub_id1)
self.failUnless(sub is not None)
......
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