[Erp5-report] r15715 - in /erp5/trunk/products/ERP5SyncML: ./ Conduit/ Interface/ dtml/ tests/

nobody at svn.erp5.org nobody at svn.erp5.org
Thu Aug 16 19:10:06 CEST 2007


Author: fabien
Date: Thu Aug 16 19:10:06 2007
New Revision: 15715

URL: http://svn.erp5.org?rev=15715&view=rev
Log:
remove gid_generator, now gid are generate in the Conduit

Added:
    erp5/trunk/products/ERP5SyncML/Conduit/ERP5ConduitTitleGid.py
    erp5/trunk/products/ERP5SyncML/Conduit/SharedVCardConduit.py   (with props)
    erp5/trunk/products/ERP5SyncML/ERP5SyncMLMobileServer.py   (with props)
Modified:
    erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py
    erp5/trunk/products/ERP5SyncML/Conduit/VCardConduit.py
    erp5/trunk/products/ERP5SyncML/Interface/IConduit.py
    erp5/trunk/products/ERP5SyncML/Publication.py
    erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py
    erp5/trunk/products/ERP5SyncML/Subscription.py
    erp5/trunk/products/ERP5SyncML/SyncCode.py
    erp5/trunk/products/ERP5SyncML/SynchronizationTool.py
    erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
    erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml
    erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml
    erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml
    erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml
    erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py
    erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py

Modified: erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py (original)
+++ erp5/trunk/products/ERP5SyncML/Conduit/ERP5Conduit.py Thu Aug 16 19:10:06 2007
@@ -1166,3 +1166,16 @@
     xml_string = buf.getvalue()
     buf.close() 
     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
+

Added: erp5/trunk/products/ERP5SyncML/Conduit/ERP5ConduitTitleGid.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Conduit/ERP5ConduitTitleGid.py?rev=15715&view=auto
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Conduit/ERP5ConduitTitleGid.py (added)
+++ erp5/trunk/products/ERP5SyncML/Conduit/ERP5ConduitTitleGid.py Thu Aug 16 19:10:06 2007
@@ -1,0 +1,57 @@
+##############################################################################
+#
+# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
+#          Fabien Morin <fabien.morin at 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

Added: erp5/trunk/products/ERP5SyncML/Conduit/SharedVCardConduit.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Conduit/SharedVCardConduit.py?rev=15715&view=auto
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Conduit/SharedVCardConduit.py (added)
+++ erp5/trunk/products/ERP5SyncML/Conduit/SharedVCardConduit.py Thu Aug 16 19:10:06 2007
@@ -1,0 +1,99 @@
+##############################################################################
+#
+# Copyright (c) 2007 Nexedi SARL and Contributors. All Rights Reserved.
+#          Fabien Morin <fabien.morin at 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
+  

Propchange: erp5/trunk/products/ERP5SyncML/Conduit/SharedVCardConduit.py
------------------------------------------------------------------------------
    svn:executable = *

Modified: erp5/trunk/products/ERP5SyncML/Conduit/VCardConduit.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Conduit/VCardConduit.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Conduit/VCardConduit.py (original)
+++ erp5/trunk/products/ERP5SyncML/Conduit/VCardConduit.py Thu Aug 16 19:10:06 2007
@@ -64,6 +64,8 @@
     """
     LOG('VCardConduit',0,'addNode, object=%s, object_id=%s, sub_object:%s, \
         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
     if sub_object is None: 
 
@@ -134,21 +136,6 @@
     """
     prefered_type = self.MEDIA_TYPE['TEXT_XVCARD']
     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, 
       property_value_list):

Added: erp5/trunk/products/ERP5SyncML/ERP5SyncMLMobileServer.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/ERP5SyncMLMobileServer.py?rev=15715&view=auto
==============================================================================
--- erp5/trunk/products/ERP5SyncML/ERP5SyncMLMobileServer.py (added)
+++ erp5/trunk/products/ERP5SyncML/ERP5SyncMLMobileServer.py Thu Aug 16 19:10:06 2007
@@ -1,0 +1,237 @@
+#!/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()

Propchange: erp5/trunk/products/ERP5SyncML/ERP5SyncMLMobileServer.py
------------------------------------------------------------------------------
    svn:executable = *

Modified: erp5/trunk/products/ERP5SyncML/Interface/IConduit.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Interface/IConduit.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Interface/IConduit.py (original)
+++ erp5/trunk/products/ERP5SyncML/Interface/IConduit.py Thu Aug 16 19:10:06 2007
@@ -110,7 +110,7 @@
     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
     """

Modified: erp5/trunk/products/ERP5SyncML/Publication.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Publication.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Publication.py (original)
+++ erp5/trunk/products/ERP5SyncML/Publication.py Thu Aug 16 19:10:06 2007
@@ -144,7 +144,7 @@
   # Constructor
   def __init__(self, id, title, publication_url, destination_path,
       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,
       sync_content_type):
     """
@@ -159,7 +159,6 @@
     self.xml_mapping = xml_mapping
     self.domain_type = self.PUB
     self.gpg_key = gpg_key
-    self.setGidGenerator(gid_generator)
     self.setMediaType(media_type)
     self.setSynchronizationIdGenerator(id_generator)
     self.setConduit(conduit)

Modified: erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py (original)
+++ erp5/trunk/products/ERP5SyncML/PublicationSynchronization.py Thu Aug 16 19:10:06 2007
@@ -234,7 +234,10 @@
         result = self.PubSyncInit(publication,xml_client,subscriber=subscriber,
             sync_type=self.SLOW_SYNC)
       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, 
             xml_client=xml_client, subscriber=subscriber, sync_type=alert_code)
       else:

Modified: erp5/trunk/products/ERP5SyncML/Subscription.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/Subscription.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/Subscription.py (original)
+++ erp5/trunk/products/ERP5SyncML/Subscription.py Thu Aug 16 19:10:06 2007
@@ -649,7 +649,7 @@
   # Constructor
   def __init__(self, id, title, publication_url, subscription_url,
       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,
       sync_content_type):
     """
@@ -677,7 +677,6 @@
     self.password=password
     self.domain_type = self.SUB
     self.gpg_key = gpg_key
-    self.setGidGenerator(gid_generator)
     self.setSynchronizationIdGenerator(id_generator)
     self.setConduit(conduit)
     Folder.__init__(self, id)
@@ -944,22 +943,6 @@
         xml = func()
     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):
     """
     This method return the type of media used in this session,
@@ -1046,17 +1029,25 @@
     """
     o_base = aq_base(object)
     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):
       o_gid = gid_gen(object)
-    elif getattr(o_base, gid_gen, None) is not None:
-      generator = getattr(object, gid_gen)
-      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
+    else:
+      raise ValueError, "The conduit "+conduit_name+"seems to no have a \
+          getGidFromObject method and it must"
+#    elif getattr(o_base, gid_gen, None) is not None:
+#      generator = getattr(object, gid_gen)
+#      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)
+    LOG('getGidFromObject returning', DEBUG, o_gid)
     return o_gid
 
   def getObjectFromGid(self, gid):
@@ -1490,3 +1481,23 @@
       retrun the user logged in
     """
     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
+

Modified: erp5/trunk/products/ERP5SyncML/SyncCode.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/SyncCode.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/SyncCode.py (original)
+++ erp5/trunk/products/ERP5SyncML/SyncCode.py Thu Aug 16 19:10:06 2007
@@ -72,7 +72,7 @@
   PUB_CONFLICT_CLIENT_WIN = 8
 
   MAX_LINES = 5000
-  MAX_OBJECTS = 100
+  MAX_OBJECTS = 300
 
   action_tag = 'workflow_action'
   #NOT_EDITABLE_PROPERTY = ('id','object','uid','xupdate:element',action_tag,

Modified: erp5/trunk/products/ERP5SyncML/SynchronizationTool.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/SynchronizationTool.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/SynchronizationTool.py (original)
+++ erp5/trunk/products/ERP5SyncML/SynchronizationTool.py Thu Aug 16 19:10:06 2007
@@ -178,7 +178,7 @@
   def manage_addPublication(self, title, publication_url, 
             destination_path, source_uri, query, xml_mapping, 
             conduit, gpg_key, 
-            synchronization_id_generator=None, gid_generator=None, 
+            synchronization_id_generator=None, 
             media_type=None, authentication_format='b64', 
             authentication_type='syncml:auth-basic', 
             RESPONSE=None, activity_enabled = False,
@@ -195,7 +195,7 @@
     pub = Publication(new_id, title, publication_url,
                       destination_path, source_uri, query, xml_mapping,
                       conduit, gpg_key, synchronization_id_generator,
-                      gid_generator, media_type, 
+                      media_type, 
                       authentication_format, 
                       authentication_type,
                       activity_enabled, synchronize_with_erp5_sites,
@@ -212,7 +212,7 @@
   def manage_addSubscription(self, title, publication_url, subscription_url,
                        destination_path, source_uri, target_uri, query,
                        xml_mapping, conduit, gpg_key,
-                       synchronization_id_generator=None, gid_generator=None,
+                       synchronization_id_generator=None,
                        media_type=None, login=None, password=None,
                        RESPONSE=None, activity_enabled=False,
                        alert_code=SyncCode.TWO_WAY,
@@ -230,7 +230,7 @@
     sub = Subscription(new_id, title, publication_url, subscription_url,
                        destination_path, source_uri, target_uri, query,
                        xml_mapping, conduit, gpg_key,
-                       synchronization_id_generator, gid_generator, media_type,
+                       synchronization_id_generator, media_type,
                        login, password, activity_enabled, alert_code, 
                        synchronize_with_erp5_sites, sync_content_type)
     folder._setObject( new_id, sub )
@@ -245,7 +245,7 @@
   def manage_editPublication(self, title, publication_url,
                             destination_path, source_uri, query, xml_mapping,
                             conduit, gpg_key, synchronization_id_generator,
-                            gid_generator,  media_type=None,
+                            media_type=None,
                             authentication_format='b64', 
                             authentication_type='syncml:auth-basic',
                             RESPONSE=None, activity_enabled=False,
@@ -265,7 +265,6 @@
     pub.setXMLMapping(xml_mapping)
     pub.setGPGKey(gpg_key)
     pub.setSynchronizationIdGenerator(synchronization_id_generator)
-    pub.setGidGenerator(gid_generator)
     pub.setMediaType(media_type)
     pub.setAuthenticationFormat(authentication_format)
     pub.setAuthenticationType(authentication_type)
@@ -279,7 +278,7 @@
       'manage_editSubscription')
   def manage_editSubscription(self, title, publication_url, subscription_url,
       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, 
       alert_code=SyncCode.TWO_WAY, synchronize_with_erp5_sites=False, 
       sync_content_type='application/vnd.syncml+xml'):
@@ -299,7 +298,6 @@
     sub.setGPGKey(gpg_key)
     sub.setSubscriptionUrl(subscription_url)
     sub.setSynchronizationIdGenerator(synchronization_id_generator)
-    sub.setGidGenerator(gid_generator)
     sub.setMediaType(media_type)
     sub.setLogin(login)
     sub.setPassword(password)

Modified: erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py (original)
+++ erp5/trunk/products/ERP5SyncML/XMLSyncUtils.py Thu Aug 16 19:10:06 2007
@@ -778,10 +778,28 @@
       object_list = domain.getObjectList()
       object_path_list = map(lambda x: x.getPhysicalPath(),object_list)
       subscriber.setRemainingObjectPathList(object_path_list)
-
-      local_gid_list = map(lambda x: domain.getGidFromObject(x),object_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)
+
       # Objects to remove
       LOG('remove object to remove ...', DEBUG, '')
+      object_gid_deleted = []
       for object_gid in subscriber.getGidList():
         if object_gid not in local_gid_list:
           # This is an object to remove
@@ -792,6 +810,7 @@
             if xml_object is not None: # This prevent to delete an object that
                                        # we were not able to create
               rid = signature.getRid()
+              object_gid_deleted.append(object_gid)
               syncml_data += self.deleteXMLObject(
                                       xml_object=signature.getXML() or '',
                                       object_gid=object_gid,
@@ -1022,6 +1041,7 @@
     """
     xml_confirmation = ''
     has_next_action = 0
+    gid_from_xml_list = []
     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', DEBUG, self.getSyncActionList(remote_xml))
@@ -1034,8 +1054,13 @@
       partial_data = self.getPartialData(action)
       rid = self.getActionId(action)
       if action.nodeName != 'Delete':
-        if hasattr(conduit, 'getGidFromXML'):
-          gid = b16encode(conduit.getGidFromXML(self.getDataText(action)))
+        if hasattr(conduit, 'getGidFromXML') and \
+            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:
           gid=rid
       else:

Modified: erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/managePublications.dtml Thu Aug 16 19:10:06 2007
@@ -161,16 +161,6 @@
       <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>
-        <td align="left" valign="top">
-        <div class="form-label">
         Media Type
         </label></div>
         </td>

Modified: erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/manageSubscriptions.dtml Thu Aug 16 19:10:06 2007
@@ -198,16 +198,6 @@
       <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>
-        <td align="left" valign="top">
-        <div class="form-label">
         Media Type
         </label></div>
         </td>

Modified: erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/manage_addPublication.dtml Thu Aug 16 19:10:06 2007
@@ -156,16 +156,6 @@
   <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>
-    <td align="left" valign="top">
-    <div class="form-label">
     Media Type
     </label></div>
     </td>

Modified: erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml (original)
+++ erp5/trunk/products/ERP5SyncML/dtml/manage_addSubscription.dtml Thu Aug 16 19:10:06 2007
@@ -193,16 +193,6 @@
   <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>
-    <td align="left" valign="top">
-    <div class="form-label">
     Media Type
     </label></div>
     </td>

Modified: erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py (original)
+++ erp5/trunk/products/ERP5SyncML/tests/testERP5SyncML.py Thu Aug 16 19:10:06 2007
@@ -346,7 +346,6 @@
         xml_mapping=self.xml_mapping, 
         conduit='ERP5Conduit',
         gpg_key='',
-        gid_generator='getId',
         activity_enabled=False,
         authentication_format='b64',
         authentication_type='syncml:auth-basic')
@@ -370,7 +369,6 @@
         xml_mapping=self.xml_mapping, 
         conduit='ERP5Conduit', 
         gpg_key='',
-        gid_generator='getId',
         activity_enabled=False,
         login='fab',
         password='myPassword')
@@ -394,7 +392,6 @@
         xml_mapping=self.xml_mapping, 
         conduit='ERP5Conduit', 
         gpg_key='',
-        gid_generator='getId',
         activity_enabled=False,
         login='fab',
         password='myPassword')
@@ -408,15 +405,13 @@
       
   def setupPublicationAndSubscriptionAndGid(self, quiet=0, run=run_all_test):
     self.setupPublicationAndSubscription(quiet=1,run=1)
-    def getGid(object):
-      return object.getTitle()
     portal_sync = self.getSynchronizationTool()
     sub1 = portal_sync.getSubscription(self.sub_id1)
     sub2 = portal_sync.getSubscription(self.sub_id2)
     pub = portal_sync.getPublication(self.pub_id)
-    pub.setGidGenerator(getGid)
-    sub1.setGidGenerator(getGid)
-    sub2.setGidGenerator(getGid)
+    sub1.setConduit('ERP5ConduitTitleGid')
+    sub2.setConduit('ERP5ConduitTitleGid')
+    pub.setConduit('ERP5ConduitTitleGid')
     pub.setSynchronizationIdGenerator('_generateNextId')
     sub1.setSynchronizationIdGenerator('_generateNextId')
     sub2.setSynchronizationIdGenerator('_generateNextId')
@@ -1342,7 +1337,6 @@
         xml_mapping=self.xml_mapping,
         conduit='ERP5Conduit',
         gpg_key='',
-        gid_generator='getId',
         activity_enabled=False,
         alert_code = SyncCode.ONE_WAY_FROM_SERVER,
         login = 'fab',

Modified: erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py?rev=15715&r1=15714&r2=15715&view=diff
==============================================================================
--- erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py (original)
+++ erp5/trunk/products/ERP5SyncML/tests/testERP5SyncMLVCard.py Thu Aug 16 19:10:06 2007
@@ -66,13 +66,22 @@
     if not run: return
     if not quiet:
       ZopeTestCase._print('\nTest Add a VCard Publication ')
-      LOG('Testing... ',0,'test_36_AddVCardPublication')
+      LOG('Testing... ',0,'test_01_AddVCardPublication')
     portal_id = self.getPortalName()
     portal_sync = self.getSynchronizationTool()
-    portal_sync.manage_addPublication(self.pub_id, self.publication_url, 
-        '/%s/person_server' % portal_id, 'Person', 'objectValues', 
-        'Person_exportAsVCard', 'VCardConduit', '', 'generateNewId', 
-        'getId', SyncCode.MEDIA_TYPE['TEXT_VCARD'])
+    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='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)
     self.failUnless(pub is not None)
 
@@ -83,11 +92,21 @@
       LOG('Testing... ',0,'test_02_AddVCardSubscription1')
     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,
-        'Person', 'Person', 'objectValues', 'Person_exportAsVCard', 
-        'VCardConduit', '', 'generateNewId', 'getId', 
-        SyncCode.MEDIA_TYPE['TEXT_VCARD'])
+    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='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)
     self.failUnless(sub is not None)
 
@@ -98,11 +117,21 @@
       LOG('Testing... ',0,'test_03_AddVCardSubscription2')
     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,
-        'Person', 'Person', 'objectValues', 'Person_exportAsVCard', 
-        'VCardConduit', '', 'generateNewId', 'getId', 
-        SyncCode.MEDIA_TYPE['TEXT_VCARD'])
+    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='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)
     self.failUnless(sub is not None)
 
@@ -143,7 +172,7 @@
 
     if not run: return
     if not quiet:
-      ZopeTestCase._print('\nTest Basic VCard Synchronization')
+      ZopeTestCase._print('\nTest Basic VCard Synchronization ')
       LOG('Testing... ',0,'test_05_basicVCardSynchronization')
 
     self.test_04_FirstVCardSynchronization(quiet=True, run=True)
@@ -179,7 +208,7 @@
     """
     if not run: return
     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')
     self.test_04_FirstVCardSynchronization(quiet=True, run=True)
     portal_sync = self.getSynchronizationTool()




More information about the Erp5-report mailing list