Commit 0085ffa1 authored by Fabien Morin's avatar Fabien Morin

remove gid_generator, now gid are generate in the Conduit


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@15715 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 2bd11dd9
...@@ -1166,3 +1166,16 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1166,3 +1166,16 @@ class ERP5Conduit(XMLSyncUtilsMixin):
xml_string = buf.getvalue() xml_string = buf.getvalue()
buf.close() buf.close()
return xml_string return xml_string
def getGidFromObject(self, object):
"""
return the Gid composed with the object informations
"""
return object.getId()
def getGidFromXML(self, xml, gid_from_xml_list):
"""
return the Gid composed with xml informations
"""
return None
##############################################################################
#
# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
# Fabien Morin <fabien.morin@gmail.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from Products.ERP5SyncML.SyncCode import SyncCode
from zLOG import LOG
class ERP5ConduitTitleGid(ERP5Conduit):
"""
ERP5ConduitTitleGid provides two methods who permit to have the GID
The Gid is composed by the title : "FirtName LastName"
this class is made for unit test
"""
# Declarative security
security = ClassSecurityInfo()
def getGidFromObject(self, object):
"""
return the Gid composed of FirstName and LastName generate with the object
"""
return object.getTitle()
# def getGidFromXML(self, xml):
# """
# return the Gid composed of FirstName and LastName generate with a peace of
# xml
# """
# #to be defined
##############################################################################
#
# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
# Fabien Morin <fabien.morin@gmail.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5SyncML.Conduit.VCardConduit import VCardConduit
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions
from Products.ERP5SyncML.SyncCode import SyncCode
from zLOG import LOG, INFO, DEBUG, TRACE
class SharedVCardConduit(VCardConduit, SyncCode):
"""
A conduit is in charge to read data from a particular structure,
and then to save this data in another structure.
SharedVCardConduit is a peace of code who provide GID.
This GID are the same for all subscriber, so a same object could be updated
by all the subscriber.
"""
# Declarative security
security = ClassSecurityInfo()
def getGidFromObject(self, object):
"""
return the Gid composed of FirstName_LastName generate with the object
"""
gid_list = []
if object.getFirstName() not in ('', None):
gid_list.append(object.getFirstName())
gid_list.append('_')
if object.getLastName() not in ('', None):
gid_list.append(object.getLastName())
sql_kw = {}
sql_kw['portal_type'] = 'Person'
sql_kw['title'] = object.getTitle()
sql_kw['id'] = '<'+object.getId()
results = object.portal_catalog.countResults(**sql_kw)[0][0]
LOG('getGidFromObject', DEBUG, 'getId:%s, getTitle:%s' % (object.getId(), object.getTitle()))
LOG('getGidFromObject, number of results :', DEBUG, results)
if int(results) > 0:
gid_list.append('__')
gid_list.append(str(int(results)+1))
gid = ''.join(gid_list)
LOG('getGidFromObject gid :', DEBUG, gid)
return gid
def getGidFromXML(self, vcard, gid_from_xml_list):
"""
return the Gid composed of FirstName and LastName generate with a vcard
"""
vcard_dict = self.vcard2Dict(vcard)
gid_from_vcard_list = []
if vcard_dict.has_key('first_name') and \
vcard_dict['first_name'] not in ('', None):
gid_from_vcard_list.append(vcard_dict['first_name'])
gid_from_vcard_list.append('_')
if vcard_dict.has_key('last_name') and \
vcard_dict['last_name'] not in ('', None):
gid_from_vcard_list.append(vcard_dict['last_name'])
gid_from_vcard = ''.join(gid_from_vcard_list)
LOG('getGidFromXML, gid_from_vcard :', DEBUG, gid_from_vcard)
number = len([item for item in gid_from_xml_list if item.startswith(gid_from_vcard)])
LOG('getGidFromXML, gid_from_xml_list :', DEBUG, gid_from_xml_list)
LOG('getGidFromXML, number :', DEBUG, number)
if number > 0:
gid_from_vcard_list.append('__')
gid_from_vcard_list.append(str(number+1))
#it's mean for 3 persons a a a, the gid will be
#a_, a___2 a___3
gid_from_vcard = ''.join(gid_from_vcard_list)
LOG('getGidFromXML, returned gid_from_vcard :', DEBUG, gid_from_vcard)
return gid_from_vcard
...@@ -64,6 +64,8 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -64,6 +64,8 @@ class VCardConduit(ERP5Conduit, SyncCode):
""" """
LOG('VCardConduit',0,'addNode, object=%s, object_id=%s, sub_object:%s, \ LOG('VCardConduit',0,'addNode, object=%s, object_id=%s, sub_object:%s, \
xml:\n%s' % (str(object), str(object_id), str(sub_object), xml)) xml:\n%s' % (str(object), str(object_id), str(sub_object), xml))
if not isinstance(xml, str):
xml = self.nodeToString(xml)
portal_type = 'Person' #the VCard can just use Person portal_type = 'Person' #the VCard can just use Person
if sub_object is None: if sub_object is None:
...@@ -135,21 +137,6 @@ class VCardConduit(ERP5Conduit, SyncCode): ...@@ -135,21 +137,6 @@ class VCardConduit(ERP5Conduit, SyncCode):
prefered_type = self.MEDIA_TYPE['TEXT_XVCARD'] prefered_type = self.MEDIA_TYPE['TEXT_XVCARD']
return prefered_type return prefered_type
def getGidFromXML(self, vcard):
"""
return the Gid composed of FirstName and LastName
"""
vcard_dict = self.vcard2Dict(vcard)
gid_from_vcard = []
if vcard_dict.has_key('first_name'):
gid_from_vcard.append(vcard_dict['first_name'])
gid_from_vcard.append(' ')
if vcard_dict.has_key('last_name'):
gid_from_vcard.append(vcard_dict['last_name'])
gid_from_vcard = ''.join(gid_from_vcard)
LOG('gid_from_vcard', 0, gid_from_vcard)
return gid_from_vcard
def changePropertyEncoding(self, property_parameters_list, def changePropertyEncoding(self, property_parameters_list,
property_value_list): property_value_list):
""" """
......
#!/usr/bin/python
# coding=UTF-8
import httplib
import urllib,urllib2, os
from Ft.Xml import Parse
import cStringIO
import string
import socket
import time
from optparse import OptionParser
try:
from Ft.Xml.Domlette import Print, PrettyPrint
except ImportError:
LOG('ERP5Conduit',0,"Can't import Print and PrettyPrint")
class Print:
def __init__(self, *args, **kw):
raise ImportError, "Sorry, it was not possible to import Ft library"
class PrettyPrint:
def __init__(self, *args, **kw):
raise ImportError, "Sorry, it was not possible to import Ft library"
class OptionParser(OptionParser):
def check_required (self, opt):
option = self.get_option(opt)
# Assumes the option's 'default' is set to None!
if getattr(self.values, option.dest) is None:
self.error("%s option not supplied" % option)
parser = OptionParser()
parser.add_option("--host", help="address of this small server (typically, it's the ip of this computer)")
parser.add_option("--publication", help="address of the publication (e.g. http://localhost:9080/erp5Serv)")
parser.add_option("-p", "--port", type="int", help="port used by this server (default is 1234)", default=1234)
(options, args) = parser.parse_args()
parser.check_required("--publication")
parser.check_required("--host")
#CONFIGURATION SECTION
#address of this small server :
#Host = '192.168.242.247'
Host=options.host
#address of the publication :
#publication_url = 'http://localhost:9080/erp5Serv'
publication_url = options.publication
#address use to transmit the message received from the external client :
to_url = publication_url+"/portal_synchronizations/readResponse"
#port of this server :
#Port = 1234
Port=options.port
#address of the this server :
syncml_server_url = 'http://'+Host+':'+str(Port)
#socket :
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
#END CONFIGURATION SECTION
CRLF = "\015\012"
#in unix, it's the same as \r\n, and on windows, it's the same as \n (\r on mac)
#this octal constant just increase a little this application portability
def nodeToString(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
def xml2wbxml(xml):
"""
convert xml string to wbxml using a temporary file
"""
import os
f = open('/tmp/xml2wbxml', 'w')
f.write(xml)
f.close()
os.system('/usr/bin/xml2wbxml -o /tmp/xml2wbxml /tmp/xml2wbxml')
f = open('/tmp/xml2wbxml', 'r')
wbxml = f.read()
f.close()
return wbxml
def wbxml2xml(wbxml):
"""
convert wbxml string to xml using a temporary file
"""
import os
f = open('/tmp/wbxml2xml', 'w')
f.write(wbxml)
f.close()
os.system('/usr/bin/wbxml2xml -o /tmp/wbxml2xml /tmp/wbxml2xml')
f = open('/tmp/wbxml2xml', 'r')
xml = f.read()
f.close()
return xml
def hexdump(raw=''):
"""
print raw in readable format without broke the terminal output !
"""
buf = ""
line = ""
start = 0
done = False
while not done:
end = start + 16
max = len(raw)
if end > max:
end = max
done = True
chunk = raw[start:end]
for i in xrange(len(chunk)):
if i > 0:
spacing = " "
else:
spacing = ""
buf += "%s%02x" % (spacing, ord(chunk[i]))
if done:
for i in xrange(16 - (end % 16)):
buf += " "
buf += " "
for c in chunk:
val = ord(c)
if val >= 33 and val <= 126:
buf += c
else:
buf += "."
buf += "\n"
start += 16
return buf
def getClientUrl(text):
"""
find the client url in the text and return it
"""
document = Parse(text)
client_url = document.xpath('string(//SyncHdr/Source/LocURI)').encode('utf-8')
return client_url
def sendResponse(text, to_url, client_url):
"""
send the message receive from the external client to erp5 server
"""
result = None
opener = urllib2.build_opener()
urllib2.install_opener(opener)
to_encode = {}
print '\nsendResponse...'
text=wbxml2xml(text)
text = text.replace(syncml_server_url, publication_url)
text = text.replace(client_url, syncml_server_url)
print "text = ",text
to_encode['text'] = text
to_encode['sync_id'] = 'Person'
headers = {'Content-type': 'application/vnd.syncml+xml'}
encoded = urllib.urlencode(to_encode)
data=encoded
request = urllib2.Request(url=to_url, data=data)
try:
result = urllib2.urlopen(request).read()
except socket.error, msg:
print 'error, url:%s ,data : %s'%(url, data)
except urllib2.URLError, msg:
print "sendResponse, can't open url : %s" % to_url
return result
def main():
sock.bind((Host,Port))
# we just listen to one and unique connection
sock.listen(1)
text = ''
# the script stop here until a client connect to him
print 'wait for a client connection...'
client, address = sock.accept()
print "the host ",address," is connected."
while 1:
print('\n\nwait for message ...')
msg = client.recv(1024) # we receive 1024 caracter max
if not msg: # if we receive nothing
break
elif not msg.startswith('POST'):
text = text + msg
if text.endswith('\x01\x01'):
client_url = getClientUrl(wbxml2xml(text))
response = sendResponse(text=text, to_url=to_url, client_url=client_url)
if response not in ('', None):
response = response.replace(syncml_server_url, client_url)
response = response.replace(publication_url, syncml_server_url)
print "\nresponse = \n",response
response = xml2wbxml(response)
print "response send to the phone :\n", hexdump(response)
date_to_print = time.strftime("%a, %d %b %Y %H:%M:%S GMT")
head = CRLF.join((
"HTTP/1.1 200 OK",
"Date: %s GMT" % date_to_print,
"Server: myPythonServer",
"Content-Length: %s" % len(response),
"Content-Type: application/vnd.syncml+wbxml",
))
message = "%s%s%s%s" % (head, CRLF, CRLF, response)
#here it's necessary to have 2 CRLF, for more details
#see http://www.w3.org/Protocols/rfc2616/rfc2616.html
client.send(message)
text=''
else:
print "this message is a POST header."
sock.close()
if __name__ == "__main__":
main()
...@@ -110,7 +110,7 @@ class IConduit(Interface): ...@@ -110,7 +110,7 @@ class IConduit(Interface):
return the Gid composed with the object informations return the Gid composed with the object informations
""" """
def getGidFromXML(self, xml): def getGidFromXML(self, xml, gid_from_xml_list):
""" """
return the Gid composed with xml informations return the Gid composed with xml informations
""" """
...@@ -144,7 +144,7 @@ class Publication(Subscription): ...@@ -144,7 +144,7 @@ class Publication(Subscription):
# Constructor # 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, source_uri, query, xml_mapping, conduit, gpg_key, id_generator,
gid_generator, media_type, authentication_format, media_type, authentication_format,
authentication_type, activity_enabled, synchronize_with_erp5_sites, authentication_type, activity_enabled, synchronize_with_erp5_sites,
sync_content_type): sync_content_type):
""" """
...@@ -159,7 +159,6 @@ class Publication(Subscription): ...@@ -159,7 +159,6 @@ class Publication(Subscription):
self.xml_mapping = xml_mapping self.xml_mapping = xml_mapping
self.domain_type = self.PUB self.domain_type = self.PUB
self.gpg_key = gpg_key self.gpg_key = gpg_key
self.setGidGenerator(gid_generator)
self.setMediaType(media_type) self.setMediaType(media_type)
self.setSynchronizationIdGenerator(id_generator) self.setSynchronizationIdGenerator(id_generator)
self.setConduit(conduit) self.setConduit(conduit)
......
...@@ -234,7 +234,10 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -234,7 +234,10 @@ class PublicationSynchronization(XMLSyncUtils):
result = self.PubSyncInit(publication,xml_client,subscriber=subscriber, result = self.PubSyncInit(publication,xml_client,subscriber=subscriber,
sync_type=self.SLOW_SYNC) sync_type=self.SLOW_SYNC)
elif self.checkAlert(xml_client) and \ elif self.checkAlert(xml_client) and \
alert_code in (self.TWO_WAY, self.SLOW_SYNC, self.ONE_WAY_FROM_SERVER): alert_code in (self.TWO_WAY, self.SLOW_SYNC, \
self.ONE_WAY_FROM_SERVER):
subscriber.setXMLMapping(publication.getXMLMapping())
subscriber.setConduit(publication.getConduit())
result = self.PubSyncInit(publication=publication, result = self.PubSyncInit(publication=publication,
xml_client=xml_client, subscriber=subscriber, sync_type=alert_code) xml_client=xml_client, subscriber=subscriber, sync_type=alert_code)
else: else:
......
...@@ -649,7 +649,7 @@ class Subscription(Folder, SyncCode): ...@@ -649,7 +649,7 @@ class Subscription(Folder, SyncCode):
# Constructor # Constructor
def __init__(self, id, title, publication_url, subscription_url, def __init__(self, id, title, publication_url, subscription_url,
destination_path, source_uri, target_uri, query, xml_mapping, destination_path, source_uri, target_uri, query, xml_mapping,
conduit, gpg_key, id_generator, gid_generator, media_type, login, conduit, gpg_key, id_generator, media_type, login,
password, activity_enabled, alert_code, synchronize_with_erp5_sites, password, activity_enabled, alert_code, synchronize_with_erp5_sites,
sync_content_type): sync_content_type):
""" """
...@@ -677,7 +677,6 @@ class Subscription(Folder, SyncCode): ...@@ -677,7 +677,6 @@ class Subscription(Folder, SyncCode):
self.password=password self.password=password
self.domain_type = self.SUB self.domain_type = self.SUB
self.gpg_key = gpg_key self.gpg_key = gpg_key
self.setGidGenerator(gid_generator)
self.setSynchronizationIdGenerator(id_generator) self.setSynchronizationIdGenerator(id_generator)
self.setConduit(conduit) self.setConduit(conduit)
Folder.__init__(self, id) Folder.__init__(self, id)
...@@ -944,22 +943,6 @@ class Subscription(Folder, SyncCode): ...@@ -944,22 +943,6 @@ class Subscription(Folder, SyncCode):
xml = func() xml = func()
return xml return xml
def setGidGenerator(self, method):
"""
This set the method name wich allows to find a gid
from any object
"""
if method in (None, '', 'None'):
method = 'getId'
self.gid_generator = method
def getGidGenerator(self):
"""
This get the method name wich allows to find a gid
from any object
"""
return self.gid_generator
def getMediaType(self): def getMediaType(self):
""" """
This method return the type of media used in this session, This method return the type of media used in this session,
...@@ -1046,17 +1029,25 @@ class Subscription(Folder, SyncCode): ...@@ -1046,17 +1029,25 @@ class Subscription(Folder, SyncCode):
""" """
o_base = aq_base(object) o_base = aq_base(object)
o_gid = None o_gid = None
gid_gen = self.getGidGenerator() conduit_name = self.getConduit()
conduit = self.getConduitByName(conduit_name)
gid_gen = getattr(conduit, 'getGidFromObject', None)
LOG('getGidFromObject, Conduit :', DEBUG, conduit_name)
LOG('getGidFromObject, gid_gen:', DEBUG, gid_gen)
if callable(gid_gen): if callable(gid_gen):
o_gid = gid_gen(object) o_gid = gid_gen(object)
elif getattr(o_base, gid_gen, None) is not None: else:
generator = getattr(object, gid_gen) raise ValueError, "The conduit "+conduit_name+"seems to no have a \
o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant getGidFromObject method and it must"
elif gid_gen is not None: # elif getattr(o_base, gid_gen, None) is not None:
# It might be a script python # generator = getattr(object, gid_gen)
generator = getattr(object,gid_gen) # o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant
o_gid = generator() # XXX - used to be o_gid = generator(object=object) which is redundant # elif gid_gen is not None:
# # 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
o_gid = b16encode(o_gid) o_gid = b16encode(o_gid)
LOG('getGidFromObject returning', DEBUG, o_gid)
return o_gid return o_gid
def getObjectFromGid(self, gid): def getObjectFromGid(self, gid):
...@@ -1490,3 +1481,23 @@ class Subscription(Folder, SyncCode): ...@@ -1490,3 +1481,23 @@ class Subscription(Folder, SyncCode):
retrun the user logged in retrun the user logged in
""" """
return getattr(self, 'user', None) return getattr(self, 'user', None)
def getConduitByName(self, conduit_name):
"""
Get Conduit Object by given name.
The Conduit can be located in Any Products according to naming Convention
Products.<Product Name>.Conduit.<Conduit Module> ,if conduit_name equal module's name.
By default Conduit must be defined in Products.ERP5SyncML.Conduit.<Conduit Module>
"""
from Products.ERP5SyncML import Conduit
if conduit_name.startswith('Products'):
path = conduit_name
conduit_name = conduit_name.split('.')[-1]
conduit_module = __import__(path, globals(), locals(), [''])
conduit = getattr(conduit_module, conduit_name)()
else:
conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
globals(), locals(), [''])
conduit = getattr(conduit_module, conduit_name)()
return conduit
...@@ -72,7 +72,7 @@ class SyncCode(Persistent): ...@@ -72,7 +72,7 @@ class SyncCode(Persistent):
PUB_CONFLICT_CLIENT_WIN = 8 PUB_CONFLICT_CLIENT_WIN = 8
MAX_LINES = 5000 MAX_LINES = 5000
MAX_OBJECTS = 100 MAX_OBJECTS = 300
action_tag = 'workflow_action' action_tag = 'workflow_action'
#NOT_EDITABLE_PROPERTY = ('id','object','uid','xupdate:element',action_tag, #NOT_EDITABLE_PROPERTY = ('id','object','uid','xupdate:element',action_tag,
......
...@@ -178,7 +178,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -178,7 +178,7 @@ class SynchronizationTool( SubscriptionSynchronization,
def manage_addPublication(self, title, publication_url, def manage_addPublication(self, title, publication_url,
destination_path, source_uri, query, xml_mapping, destination_path, source_uri, query, xml_mapping,
conduit, gpg_key, conduit, gpg_key,
synchronization_id_generator=None, gid_generator=None, synchronization_id_generator=None,
media_type=None, authentication_format='b64', media_type=None, authentication_format='b64',
authentication_type='syncml:auth-basic', authentication_type='syncml:auth-basic',
RESPONSE=None, activity_enabled = False, RESPONSE=None, activity_enabled = False,
...@@ -195,7 +195,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -195,7 +195,7 @@ class SynchronizationTool( SubscriptionSynchronization,
pub = Publication(new_id, title, publication_url, pub = Publication(new_id, title, publication_url,
destination_path, source_uri, query, xml_mapping, destination_path, source_uri, query, xml_mapping,
conduit, gpg_key, synchronization_id_generator, conduit, gpg_key, synchronization_id_generator,
gid_generator, media_type, media_type,
authentication_format, authentication_format,
authentication_type, authentication_type,
activity_enabled, synchronize_with_erp5_sites, activity_enabled, synchronize_with_erp5_sites,
...@@ -212,7 +212,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -212,7 +212,7 @@ class SynchronizationTool( SubscriptionSynchronization,
def manage_addSubscription(self, title, publication_url, subscription_url, def manage_addSubscription(self, title, publication_url, subscription_url,
destination_path, source_uri, target_uri, query, destination_path, source_uri, target_uri, query,
xml_mapping, conduit, gpg_key, xml_mapping, conduit, gpg_key,
synchronization_id_generator=None, gid_generator=None, synchronization_id_generator=None,
media_type=None, login=None, password=None, media_type=None, login=None, password=None,
RESPONSE=None, activity_enabled=False, RESPONSE=None, activity_enabled=False,
alert_code=SyncCode.TWO_WAY, alert_code=SyncCode.TWO_WAY,
...@@ -230,7 +230,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -230,7 +230,7 @@ class SynchronizationTool( SubscriptionSynchronization,
sub = Subscription(new_id, title, publication_url, subscription_url, sub = Subscription(new_id, title, publication_url, subscription_url,
destination_path, source_uri, target_uri, query, destination_path, source_uri, target_uri, query,
xml_mapping, conduit, gpg_key, xml_mapping, conduit, gpg_key,
synchronization_id_generator, gid_generator, media_type, synchronization_id_generator, media_type,
login, password, activity_enabled, alert_code, login, password, activity_enabled, alert_code,
synchronize_with_erp5_sites, sync_content_type) synchronize_with_erp5_sites, sync_content_type)
folder._setObject( new_id, sub ) folder._setObject( new_id, sub )
...@@ -245,7 +245,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -245,7 +245,7 @@ class SynchronizationTool( SubscriptionSynchronization,
def manage_editPublication(self, title, publication_url, def manage_editPublication(self, title, publication_url,
destination_path, source_uri, query, xml_mapping, destination_path, source_uri, query, xml_mapping,
conduit, gpg_key, synchronization_id_generator, conduit, gpg_key, synchronization_id_generator,
gid_generator, media_type=None, media_type=None,
authentication_format='b64', authentication_format='b64',
authentication_type='syncml:auth-basic', authentication_type='syncml:auth-basic',
RESPONSE=None, activity_enabled=False, RESPONSE=None, activity_enabled=False,
...@@ -265,7 +265,6 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -265,7 +265,6 @@ class SynchronizationTool( SubscriptionSynchronization,
pub.setXMLMapping(xml_mapping) pub.setXMLMapping(xml_mapping)
pub.setGPGKey(gpg_key) pub.setGPGKey(gpg_key)
pub.setSynchronizationIdGenerator(synchronization_id_generator) pub.setSynchronizationIdGenerator(synchronization_id_generator)
pub.setGidGenerator(gid_generator)
pub.setMediaType(media_type) pub.setMediaType(media_type)
pub.setAuthenticationFormat(authentication_format) pub.setAuthenticationFormat(authentication_format)
pub.setAuthenticationType(authentication_type) pub.setAuthenticationType(authentication_type)
...@@ -279,7 +278,7 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -279,7 +278,7 @@ class SynchronizationTool( SubscriptionSynchronization,
'manage_editSubscription') 'manage_editSubscription')
def manage_editSubscription(self, title, publication_url, subscription_url, def manage_editSubscription(self, title, publication_url, subscription_url,
destination_path, source_uri, target_uri, query, xml_mapping, conduit, destination_path, source_uri, target_uri, query, xml_mapping, conduit,
gpg_key, synchronization_id_generator, gid_generator, media_type=None, gpg_key, synchronization_id_generator, media_type=None,
login='', password='', RESPONSE=None, activity_enabled=False, login='', password='', RESPONSE=None, activity_enabled=False,
alert_code=SyncCode.TWO_WAY, synchronize_with_erp5_sites=False, alert_code=SyncCode.TWO_WAY, synchronize_with_erp5_sites=False,
sync_content_type='application/vnd.syncml+xml'): sync_content_type='application/vnd.syncml+xml'):
...@@ -299,7 +298,6 @@ class SynchronizationTool( SubscriptionSynchronization, ...@@ -299,7 +298,6 @@ class SynchronizationTool( SubscriptionSynchronization,
sub.setGPGKey(gpg_key) sub.setGPGKey(gpg_key)
sub.setSubscriptionUrl(subscription_url) sub.setSubscriptionUrl(subscription_url)
sub.setSynchronizationIdGenerator(synchronization_id_generator) sub.setSynchronizationIdGenerator(synchronization_id_generator)
sub.setGidGenerator(gid_generator)
sub.setMediaType(media_type) sub.setMediaType(media_type)
sub.setLogin(login) sub.setLogin(login)
sub.setPassword(password) sub.setPassword(password)
......
...@@ -778,10 +778,28 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -778,10 +778,28 @@ class XMLSyncUtilsMixin(SyncCode):
object_list = domain.getObjectList() object_list = domain.getObjectList()
object_path_list = map(lambda x: x.getPhysicalPath(),object_list) object_path_list = map(lambda x: x.getPhysicalPath(),object_list)
subscriber.setRemainingObjectPathList(object_path_list) subscriber.setRemainingObjectPathList(object_path_list)
if subscriber.getMediaType() == self.MEDIA_TYPE['TEXT_VCARD']:
#here the method getGidFromObject don't return the good gid because
#the conduit use the catalog to determine it and object are not yet
#cataloged so if there is many times the same gid, we must count it
gid_not_encoded_list = []
for object in object_list:
LOG('getSyncMLData :', DEBUG, 'object:%s, object_list:%s, objectTitle:%s, local_gid_list:%s' % (object, object_list, object.getTitle(), local_gid_list))
gid = b16decode(domain.getGidFromObject(object))
if gid in gid_not_encoded_list:
number = len([item for item in gid_not_encoded_list if item.startswith(gid)])
if number > 0:
gid = gid+'__'+str(number+1)
gid_not_encoded_list.append(gid)
local_gid_list.append(b16encode(gid))
LOG('getSyncMLData :', DEBUG,'gid_not_encoded_list:%s, local_gid_list:%s, gid:%s' % (gid_not_encoded_list, local_gid_list, gid))
else:
local_gid_list = map(lambda x: domain.getGidFromObject(x),object_list)
local_gid_list = map(lambda x: domain.getGidFromObject(x),object_list)
# Objects to remove # Objects to remove
LOG('remove object to remove ...', DEBUG, '') LOG('remove object to remove ...', DEBUG, '')
object_gid_deleted = []
for object_gid in subscriber.getGidList(): for object_gid in subscriber.getGidList():
if object_gid not in local_gid_list: if object_gid not in local_gid_list:
# This is an object to remove # This is an object to remove
...@@ -792,6 +810,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -792,6 +810,7 @@ class XMLSyncUtilsMixin(SyncCode):
if xml_object is not None: # This prevent to delete an object that if xml_object is not None: # This prevent to delete an object that
# we were not able to create # we were not able to create
rid = signature.getRid() rid = signature.getRid()
object_gid_deleted.append(object_gid)
syncml_data += self.deleteXMLObject( syncml_data += self.deleteXMLObject(
xml_object=signature.getXML() or '', xml_object=signature.getXML() or '',
object_gid=object_gid, object_gid=object_gid,
...@@ -1022,6 +1041,7 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1022,6 +1041,7 @@ class XMLSyncUtilsMixin(SyncCode):
""" """
xml_confirmation = '' xml_confirmation = ''
has_next_action = 0 has_next_action = 0
gid_from_xml_list = []
destination = self.unrestrictedTraverse(domain.getDestinationPath()) destination = self.unrestrictedTraverse(domain.getDestinationPath())
LOG('applyActionList args', DEBUG, 'domain : %s\n subscriber : %s\n cmd_id : %s' % (domain.getPath(), subscriber.getPath(), cmd_id)) LOG('applyActionList args', DEBUG, 'domain : %s\n subscriber : %s\n cmd_id : %s' % (domain.getPath(), subscriber.getPath(), cmd_id))
LOG('applyActionList', DEBUG, self.getSyncActionList(remote_xml)) LOG('applyActionList', DEBUG, self.getSyncActionList(remote_xml))
...@@ -1034,8 +1054,13 @@ class XMLSyncUtilsMixin(SyncCode): ...@@ -1034,8 +1054,13 @@ class XMLSyncUtilsMixin(SyncCode):
partial_data = self.getPartialData(action) partial_data = self.getPartialData(action)
rid = self.getActionId(action) rid = self.getActionId(action)
if action.nodeName != 'Delete': if action.nodeName != 'Delete':
if hasattr(conduit, 'getGidFromXML'): if hasattr(conduit, 'getGidFromXML') and \
gid = b16encode(conduit.getGidFromXML(self.getDataText(action))) conduit.getGidFromXML(self.getDataText(action),
gid_from_xml_list) not in ('', None):
gid = conduit.getGidFromXML(self.getDataText(action),
gid_from_xml_list)
gid_from_xml_list.append(gid)
gid = b16encode(gid)
else: else:
gid=rid gid=rid
else: else:
......
...@@ -158,16 +158,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -158,16 +158,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="synchronization_id_generator" value="<dtml-var getSynchronizationIdGenerator>" size="40" /> <input type="text" name="synchronization_id_generator" value="<dtml-var getSynchronizationIdGenerator>" size="40" />
</td> </td>
</tr> </tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Gid Generator
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" />
</td>
</tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
......
...@@ -195,16 +195,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -195,16 +195,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="synchronization_id_generator" value="<dtml-var getSynchronizationIdGenerator>" size="40" /> <input type="text" name="synchronization_id_generator" value="<dtml-var getSynchronizationIdGenerator>" size="40" />
</td> </td>
</tr> </tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Gid Generator
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="gid_generator" value="<dtml-var getGidGenerator>" size="40" />
</td>
</tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
......
...@@ -153,16 +153,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -153,16 +153,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="synchronization_id_generator" size="40" /> <input type="text" name="synchronization_id_generator" size="40" />
</td> </td>
</tr> </tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Gid Generator
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="gid_generator" size="40" />
</td>
</tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
......
...@@ -190,16 +190,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -190,16 +190,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<input type="text" name="synchronization_id_generator" size="40" /> <input type="text" name="synchronization_id_generator" size="40" />
</td> </td>
</tr> </tr>
<tr>
<td align="left" valign="top">
<div class="form-label">
Gid Generator
</label></div>
</td>
<td align="left" valign="top">
<input type="text" name="gid_generator" size="40" />
</td>
</tr>
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
......
...@@ -346,7 +346,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -346,7 +346,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
xml_mapping=self.xml_mapping, xml_mapping=self.xml_mapping,
conduit='ERP5Conduit', conduit='ERP5Conduit',
gpg_key='', gpg_key='',
gid_generator='getId',
activity_enabled=False, activity_enabled=False,
authentication_format='b64', authentication_format='b64',
authentication_type='syncml:auth-basic') authentication_type='syncml:auth-basic')
...@@ -370,7 +369,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -370,7 +369,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
xml_mapping=self.xml_mapping, xml_mapping=self.xml_mapping,
conduit='ERP5Conduit', conduit='ERP5Conduit',
gpg_key='', gpg_key='',
gid_generator='getId',
activity_enabled=False, activity_enabled=False,
login='fab', login='fab',
password='myPassword') password='myPassword')
...@@ -394,7 +392,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -394,7 +392,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
xml_mapping=self.xml_mapping, xml_mapping=self.xml_mapping,
conduit='ERP5Conduit', conduit='ERP5Conduit',
gpg_key='', gpg_key='',
gid_generator='getId',
activity_enabled=False, activity_enabled=False,
login='fab', login='fab',
password='myPassword') password='myPassword')
...@@ -408,15 +405,13 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -408,15 +405,13 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
def setupPublicationAndSubscriptionAndGid(self, quiet=0, run=run_all_test): def setupPublicationAndSubscriptionAndGid(self, quiet=0, run=run_all_test):
self.setupPublicationAndSubscription(quiet=1,run=1) self.setupPublicationAndSubscription(quiet=1,run=1)
def getGid(object):
return object.getTitle()
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
sub1 = portal_sync.getSubscription(self.sub_id1) sub1 = portal_sync.getSubscription(self.sub_id1)
sub2 = portal_sync.getSubscription(self.sub_id2) sub2 = portal_sync.getSubscription(self.sub_id2)
pub = portal_sync.getPublication(self.pub_id) pub = portal_sync.getPublication(self.pub_id)
pub.setGidGenerator(getGid) sub1.setConduit('ERP5ConduitTitleGid')
sub1.setGidGenerator(getGid) sub2.setConduit('ERP5ConduitTitleGid')
sub2.setGidGenerator(getGid) pub.setConduit('ERP5ConduitTitleGid')
pub.setSynchronizationIdGenerator('_generateNextId') pub.setSynchronizationIdGenerator('_generateNextId')
sub1.setSynchronizationIdGenerator('_generateNextId') sub1.setSynchronizationIdGenerator('_generateNextId')
sub2.setSynchronizationIdGenerator('_generateNextId') sub2.setSynchronizationIdGenerator('_generateNextId')
...@@ -1342,7 +1337,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -1342,7 +1337,6 @@ class TestERP5SyncML(TestERP5SyncMLMixin, ERP5TypeTestCase):
xml_mapping=self.xml_mapping, xml_mapping=self.xml_mapping,
conduit='ERP5Conduit', conduit='ERP5Conduit',
gpg_key='', gpg_key='',
gid_generator='getId',
activity_enabled=False, activity_enabled=False,
alert_code = SyncCode.ONE_WAY_FROM_SERVER, alert_code = SyncCode.ONE_WAY_FROM_SERVER,
login = 'fab', login = 'fab',
......
...@@ -66,13 +66,22 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -66,13 +66,22 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase):
if not run: return if not run: return
if not quiet: if not quiet:
ZopeTestCase._print('\nTest Add a VCard Publication ') ZopeTestCase._print('\nTest Add a VCard Publication ')
LOG('Testing... ',0,'test_36_AddVCardPublication') LOG('Testing... ',0,'test_01_AddVCardPublication')
portal_id = self.getPortalName() portal_id = self.getPortalName()
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
portal_sync.manage_addPublication(self.pub_id, self.publication_url, portal_sync.manage_addPublication(title=self.pub_id,
'/%s/person_server' % portal_id, 'Person', 'objectValues', publication_url=self.publication_url,
'Person_exportAsVCard', 'VCardConduit', '', 'generateNewId', destination_path='/%s/person_server' % portal_id,
'getId', SyncCode.MEDIA_TYPE['TEXT_VCARD']) source_uri='Person',
query='objectValues',
xml_mapping='Person_exportAsVCard',
conduit='SharedVCardConduit',
gpg_key='',
synchronization_id_generator='generateNewId',
media_type='text/vcard',
activity_enabled=False,
authentication_format='b64',
authentication_type='syncml:auth-basic')
pub = portal_sync.getPublication(self.pub_id) pub = portal_sync.getPublication(self.pub_id)
self.failUnless(pub is not None) self.failUnless(pub is not None)
...@@ -83,11 +92,21 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -83,11 +92,21 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase):
LOG('Testing... ',0,'test_02_AddVCardSubscription1') LOG('Testing... ',0,'test_02_AddVCardSubscription1')
portal_id = self.getPortalId() portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id1, self.publication_url, portal_sync.manage_addSubscription(title=self.sub_id1,
self.subscription_url1, '/%s/person_client1' % portal_id, publication_url=self.publication_url,
'Person', 'Person', 'objectValues', 'Person_exportAsVCard', subscription_url=self.subscription_url1,
'VCardConduit', '', 'generateNewId', 'getId', destination_path='/%s/person_client1' % portal_id,
SyncCode.MEDIA_TYPE['TEXT_VCARD']) source_uri='Person',
target_uri='Person',
query='objectValues',
xml_mapping='Person_exportAsVCard',
conduit='SharedVCardConduit',
gpg_key='',
synchronization_id_generator='generateNewId',
media_type='text/vcard',
activity_enabled=False,
login='fab',
password='myPassword')
sub = portal_sync.getSubscription(self.sub_id1) sub = portal_sync.getSubscription(self.sub_id1)
self.failUnless(sub is not None) self.failUnless(sub is not None)
...@@ -98,11 +117,21 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -98,11 +117,21 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase):
LOG('Testing... ',0,'test_03_AddVCardSubscription2') LOG('Testing... ',0,'test_03_AddVCardSubscription2')
portal_id = self.getPortalId() portal_id = self.getPortalId()
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
portal_sync.manage_addSubscription(self.sub_id2, self.publication_url, portal_sync.manage_addSubscription(title=self.sub_id2,
self.subscription_url2, '/%s/person_client2' % portal_id, publication_url=self.publication_url,
'Person', 'Person', 'objectValues', 'Person_exportAsVCard', subscription_url=self.subscription_url2,
'VCardConduit', '', 'generateNewId', 'getId', destination_path='/%s/person_client2' % portal_id,
SyncCode.MEDIA_TYPE['TEXT_VCARD']) source_uri='Person',
target_uri='Person',
query='objectValues',
xml_mapping='Person_exportAsVCard',
conduit='SharedVCardConduit',
gpg_key='',
synchronization_id_generator='generateNewId',
media_type='text/vcard',
activity_enabled=False,
login='fab',
password='myPassword')
sub = portal_sync.getSubscription(self.sub_id2) sub = portal_sync.getSubscription(self.sub_id2)
self.failUnless(sub is not None) self.failUnless(sub is not None)
...@@ -143,7 +172,7 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -143,7 +172,7 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase):
if not run: return if not run: return
if not quiet: if not quiet:
ZopeTestCase._print('\nTest Basic VCard Synchronization') ZopeTestCase._print('\nTest Basic VCard Synchronization ')
LOG('Testing... ',0,'test_05_basicVCardSynchronization') LOG('Testing... ',0,'test_05_basicVCardSynchronization')
self.test_04_FirstVCardSynchronization(quiet=True, run=True) self.test_04_FirstVCardSynchronization(quiet=True, run=True)
...@@ -179,7 +208,7 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase): ...@@ -179,7 +208,7 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin, ERP5TypeTestCase):
""" """
if not run: return if not run: return
if not quiet: if not quiet:
ZopeTestCase._print('\nTest No Duplicate Data When Adding') ZopeTestCase._print('\nTest No Duplicate Data When Adding ')
LOG('Testing... ',0,'test_05_verifyNoDuplicateDataWhenAdding') LOG('Testing... ',0,'test_05_verifyNoDuplicateDataWhenAdding')
self.test_04_FirstVCardSynchronization(quiet=True, run=True) self.test_04_FirstVCardSynchronization(quiet=True, run=True)
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
......
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