Commit fb9162fb authored by Sebastien Robin's avatar Sebastien Robin

modified the syncml tool so that it is a folder. Now ERP5Sycml use

folders instead of dictionnaries


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@1003 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent f3a5bd3b
...@@ -29,6 +29,10 @@ ...@@ -29,6 +29,10 @@
from Globals import Persistent, PersistentMapping from Globals import Persistent, PersistentMapping
from SyncCode import SyncCode from SyncCode import SyncCode
from Subscription import Subscription from Subscription import Subscription
from Products.ERP5Type import Permissions
from Products.ERP5Type.Document.Folder import Folder
from AccessControl import ClassSecurityInfo
from Products.ERP5Type import PropertySheet
class Subscriber(Subscription): class Subscriber(Subscription):
...@@ -44,7 +48,7 @@ class Subscriber(Subscription): ...@@ -44,7 +48,7 @@ class Subscriber(Subscription):
next_anchor - it defines the id of the current synchronisation next_anchor - it defines the id of the current synchronisation
""" """
def __init__(self, subscription_url): def __init__(self, id, subscription_url):
""" """
constructor constructor
""" """
...@@ -53,6 +57,7 @@ class Subscriber(Subscription): ...@@ -53,6 +57,7 @@ class Subscriber(Subscription):
self.next_anchor = '00000000T000000Z' self.next_anchor = '00000000T000000Z'
self.session_id = 0 self.session_id = 0
self.signatures = {} self.signatures = {}
Folder.__init__(self, id)
def ReceiveDocuments(self): def ReceiveDocuments(self):
""" """
...@@ -75,6 +80,16 @@ class Subscriber(Subscription): ...@@ -75,6 +80,16 @@ class Subscriber(Subscription):
as conflicting) as conflicting)
""" """
def addPublication( self, id, title='', REQUEST=None ):
"""
Add a new Category and generate UID by calling the
ZSQLCatalog
"""
o = Publication( id ,'','','','','')
self._setObject( id, o )
if REQUEST is not None:
return self.manage_main(self, REQUEST, update_menu=1)
return o
class Publication(Subscription): class Publication(Subscription):
""" """
...@@ -93,11 +108,32 @@ class Publication(Subscription): ...@@ -93,11 +108,32 @@ class Publication(Subscription):
list_subscribers -- a list of subsbribtions list_subscribers -- a list of subsbribtions
""" """
# Default Values meta_type='ERP5 Publication'
list_subscribers = PersistentMapping() portal_type='Publication' # may be useful in the future...
isPortalContent = 1
isRADContent = 1
icon = None
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.SimpleItem )
allowed_types = ( 'Signatures',)
# Declarative security
security = ClassSecurityInfo()
security.declareProtected(Permissions.ManagePortal,
'manage_editProperties',
'manage_changeProperties',
'manage_propertiesForm',
)
# Declarative constructors
constructors = (addPublication,)
# Constructor # Constructor
def __init__(self, id, publication_url, destination_path, query, xml_mapping, gpg_key): def __init__(self, id, title, publication_url, destination_path, query, xml_mapping, gpg_key):
""" """
constructor constructor
""" """
...@@ -106,11 +142,13 @@ class Publication(Subscription): ...@@ -106,11 +142,13 @@ class Publication(Subscription):
self.destination_path = destination_path self.destination_path = destination_path
self.setQuery(query) self.setQuery(query)
self.xml_mapping = xml_mapping self.xml_mapping = xml_mapping
self.list_subscribers = PersistentMapping() #self.list_subscribers = PersistentMapping()
self.domain_type = self.PUB self.domain_type = self.PUB
self.gpg_key = gpg_key self.gpg_key = gpg_key
self.setGidGenerator(None) self.setGidGenerator(None)
self.setIdGenerator(None) self.setIdGenerator(None)
Folder.__init__(self, id)
self.title = title
def getPublicationUrl(self): def getPublicationUrl(self):
""" """
...@@ -137,51 +175,43 @@ class Publication(Subscription): ...@@ -137,51 +175,43 @@ class Publication(Subscription):
""" """
# We have to remove the subscriber if it already exist (there were probably a reset on the client) # We have to remove the subscriber if it already exist (there were probably a reset on the client)
self.delSubscriber(subscriber.getSubscriptionUrl()) self.delSubscriber(subscriber.getSubscriptionUrl())
if len(self.list_subscribers) == 0: new_id = str(self.generateNewId())
self.list_subscribers = [] subscriber.id = new_id
self.list_subscribers = self.list_subscribers + [subscriber] #if len(self.list_subscribers) == 0:
# self.list_subscribers = []
def searchSubscriber(self, subscription_url): #self.list_subscribers = self.list_subscribers + [subscriber]
""" self._setObject(new_id,subscriber)
search if subscriber is in the list or not
"""
for f in range(len(self.list_subscribers)):
if self.list_subscribers[f].subscription_url == subscription_url:
return 1
return None
def getSubscriber(self, subscription_url): def getSubscriber(self, subscription_url):
""" """
return the subscriber corresponding the to subscription_url return the subscriber corresponding the to subscription_url
""" """
for f in range(len(self.list_subscribers)): for o in self.objectValues():
if self.list_subscribers[f].subscription_url == subscription_url: if o.getSubscriptionUrl() == subscription_url:
return self.list_subscribers[f].__of__(self) return o
return None return None
def getSubscriberList(self): def getSubscriberList(self):
""" """
Get the list of subscribers Get the list of subscribers
""" """
list_subscribers = [] return self.objectValues()
for f in range(len(self.list_subscribers)):
list_subscribers += [self.list_subscribers[f]]
return list_subscribers
def delSubscriber(self, subscription_url): def delSubscriber(self, subscription_url):
""" """
Delete a subscriber for this publication Delete a subscriber for this publication
""" """
for f in range(len(self.list_subscribers)): for o in self.objectValues():
if self.list_subscribers[f].subscription_url == subscription_url: if o.getSubscriptionUrl() == subscription_url:
self.list_subscribers = self.list_subscribers[0:f] + \ self._delObject(o.id)
self.list_subscribers[f+1:len(self.list_subscribers)]
def resetAllSubscribers(self): def resetAllSubscribers(self):
""" """
Reset all subscribers Reset all subscribers
""" """
self.list_subscribers = PersistentMapping() for o in self.objectValues():
self._delObject(o.id)
def getConflictList(self): def getConflictList(self):
""" """
......
...@@ -138,7 +138,7 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -138,7 +138,7 @@ class PublicationSynchronization(XMLSyncUtils):
# Get the subscriber or create it if not already in the list # Get the subscriber or create it if not already in the list
subscriber = self.getPublication(id).getSubscriber(subscription_url) subscriber = self.getPublication(id).getSubscriber(subscription_url)
if subscriber == None: if subscriber == None:
subscriber = Subscriber(subscription_url) subscriber = Subscriber(self.generateNewId(),subscription_url)
subscriber.setXMLMapping(publication.getXMLMapping()) subscriber.setXMLMapping(publication.getXMLMapping())
self.getPublication(id).addSubscriber(subscriber) self.getPublication(id).addSubscriber(subscriber)
# first synchronization # first synchronization
...@@ -156,8 +156,6 @@ class PublicationSynchronization(XMLSyncUtils): ...@@ -156,8 +156,6 @@ class PublicationSynchronization(XMLSyncUtils):
result = self.PubSyncInit(publication=self.getPublication(id), result = self.PubSyncInit(publication=self.getPublication(id),
xml_client=None, subscriber=subscriber,sync_type=self.TWO_WAY) xml_client=None, subscriber=subscriber,sync_type=self.TWO_WAY)
has_response = 1 #pubsync always replies to messages
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
elif result is not None: elif result is not None:
......
...@@ -29,13 +29,19 @@ ...@@ -29,13 +29,19 @@
from Globals import PersistentMapping from Globals import PersistentMapping
from time import gmtime,strftime # for anchors from time import gmtime,strftime # for anchors
from SyncCode import SyncCode from SyncCode import SyncCode
from AccessControl import ClassSecurityInfo
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Acquisition import Implicit, aq_base from Acquisition import Implicit, aq_base
from Products.ERP5Type.Document.Folder import Folder
from Products.ERP5Type.Base import Base
from Products.ERP5Type import Permissions
from Products.ERP5Type import PropertySheet
from zLOG import LOG from zLOG import LOG
import md5 import md5
class Conflict(SyncCode, Implicit): #class Conflict(SyncCode, Implicit):
class Conflict(SyncCode, Base):
""" """
object_path : the path of the obect object_path : the path of the obect
keyword : an identifier of the conflict keyword : an identifier of the conflict
...@@ -206,7 +212,7 @@ class Conflict(SyncCode, Implicit): ...@@ -206,7 +212,7 @@ class Conflict(SyncCode, Implicit):
""" """
return self.keyword return self.keyword
class Signature(SyncCode): class Signature(SyncCode,Folder):
""" """
status -- SENT, CONFLICT... status -- SENT, CONFLICT...
md5_object -- An MD5 value of a given document md5_object -- An MD5 value of a given document
...@@ -233,12 +239,6 @@ class Signature(SyncCode): ...@@ -233,12 +239,6 @@ class Signature(SyncCode):
self.setSubscriberXupdate(None) self.setSubscriberXupdate(None)
self.setPublisherXupdate(None) self.setPublisherXupdate(None)
#def __init__(self,object=None, status=None, xml_string=None):
# self.uid = object.uid
# self.id = object.id
# self.status = status
# self.setXML(xml_string)
def setStatus(self, status): def setStatus(self, status):
""" """
set the Status (see SyncCode for numbers) set the Status (see SyncCode for numbers)
...@@ -397,11 +397,9 @@ class Signature(SyncCode): ...@@ -397,11 +397,9 @@ class Signature(SyncCode):
Set the partial string we will have to Set the partial string we will have to
deliver in the future deliver in the future
""" """
#LOG('Subscriber.setPartialXML before',0,'partial_xml: %s' % str(self.partial_xml))
if type(xml) is type(u'a'): if type(xml) is type(u'a'):
xml = xml.encode('utf-8') xml = xml.encode('utf-8')
self.partial_xml = xml self.partial_xml = xml
#LOG('Subscriber.setPartialXML after',0,'partial_xml: %s' % str(self.partial_xml))
def getPartialXML(self): def getPartialXML(self):
""" """
...@@ -466,7 +464,19 @@ class Signature(SyncCode): ...@@ -466,7 +464,19 @@ class Signature(SyncCode):
else: else:
self.resetConflictList() self.resetConflictList()
class Subscription(SyncCode, Implicit): def addSubscription( self, id, title='', REQUEST=None ):
"""
Add a new Category and generate UID by calling the
ZSQLCatalog
"""
o = Subscription( id ,'','','','','','')
self._setObject( id, o )
if REQUEST is not None:
return self.manage_main(self, REQUEST, update_menu=1)
return o
#class Subscription(SyncCode, Implicit):
class Subscription(SyncCode, Implicit, Folder):
""" """
Subscription hold the definition of a master ODB Subscription hold the definition of a master ODB
from/to which a selection of objects will be synchronised from/to which a selection of objects will be synchronised
...@@ -502,10 +512,32 @@ class Subscription(SyncCode, Implicit): ...@@ -502,10 +512,32 @@ class Subscription(SyncCode, Implicit):
""" """
signatures = PersistentMapping() meta_type='ERP5 Subscription'
portal_type='Subscription' # may be useful in the future...
isPortalContent = 1
isRADContent = 1
icon = None
# Declarative properties
property_sheets = ( PropertySheet.Base
, PropertySheet.SimpleItem )
allowed_types = ( 'Signatures',)
# Declarative constructors
constructors = (addSubscription,)
# Declarative security
security = ClassSecurityInfo()
security.declareProtected(Permissions.ManagePortal,
'manage_editProperties',
'manage_changeProperties',
'manage_propertiesForm',
)
# Constructor # Constructor
def __init__(self, id, publication_url, subscription_url, destination_path, query, xml_mapping, gpg_key): def __init__(self, id, title, publication_url, subscription_url, destination_path, query, xml_mapping, gpg_key):
""" """
We need to create a dictionnary of We need to create a dictionnary of
signatures of documents which belong to the synchronisation signatures of documents which belong to the synchronisation
...@@ -519,16 +551,30 @@ class Subscription(SyncCode, Implicit): ...@@ -519,16 +551,30 @@ class Subscription(SyncCode, Implicit):
self.xml_mapping = xml_mapping self.xml_mapping = xml_mapping
self.anchor = None self.anchor = None
self.session_id = 0 self.session_id = 0
self.signatures = PersistentMapping() #self.signatures = PersistentMapping()
self.last_anchor = '00000000T000000Z' self.last_anchor = '00000000T000000Z'
self.next_anchor = '00000000T000000Z' self.next_anchor = '00000000T000000Z'
self.domain_type = self.SUB self.domain_type = self.SUB
self.gpg_key = gpg_key self.gpg_key = gpg_key
self.setGidGenerator(None) self.setGidGenerator(None)
self.setIdGenerator(None) self.setIdGenerator(None)
Folder.__init__(self, id)
self.title = title
#self.signatures = PersitentMapping() #self.signatures = PersitentMapping()
def getTitle(self):
"""
getter for title
"""
return getattr(self,'title',None)
def setTitle(self, value):
"""
setter for title
"""
self.title = value
# Accessors # Accessors
def getRemoteId(self, id, path=None): def getRemoteId(self, id, path=None):
""" """
...@@ -544,16 +590,15 @@ class Subscription(SyncCode, Implicit): ...@@ -544,16 +590,15 @@ class Subscription(SyncCode, Implicit):
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# XXX for debugging only, to be removed # XXX for debugging only, to be removed
dict_sign = {} dict_sign = {}
for object_id in self.signatures.keys(): for o in self.objectValues():
dict_sign[object_id] = self.signatures[object_id].getStatus() dict_sign[o.getId()] = o.getStatus()
LOG('getSignature',0,'signatures_status: %s' % str(dict_sign)) LOG('getSignature',0,'signatures_status: %s' % str(dict_sign))
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXX # XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
code = self.SLOW_SYNC code = self.SLOW_SYNC
if len(self.signatures.keys()) > 0: if len(self.objectValues()) > 0:
code = self.TWO_WAY code = self.TWO_WAY
if default is not None: if default is not None:
code = default code = default
LOG('Subscription',0,'getSynchronizationType keys: %s' % str(self.signatures.keys()))
LOG('Subscription',0,'getSynchronizationType: %s' % code) LOG('Subscription',0,'getSynchronizationType: %s' % code)
return code return code
...@@ -620,6 +665,12 @@ class Subscription(SyncCode, Implicit): ...@@ -620,6 +665,12 @@ class Subscription(SyncCode, Implicit):
""" """
return getattr(self,'gpg_key','') return getattr(self,'gpg_key','')
def setGPGKey(self, value):
"""
setter for the gnupg key name
"""
self.gpg_key = value
def setQuery(self, query): def setQuery(self, query):
""" """
set the query set the query
...@@ -739,7 +790,7 @@ class Subscription(SyncCode, Implicit): ...@@ -739,7 +790,7 @@ class Subscription(SyncCode, Implicit):
# query_list = query() # query_list = query()
# return query_list # return query_list
def generateNewId(self, object=None,gid=None): def generateNewIdWithGenerator(self, object=None,gid=None):
""" """
This tries to generate a new Id This tries to generate a new Id
""" """
...@@ -858,54 +909,50 @@ class Subscription(SyncCode, Implicit): ...@@ -858,54 +909,50 @@ class Subscription(SyncCode, Implicit):
""" """
add a Signature to the subscription add a Signature to the subscription
""" """
self.signatures[signature.getGid()] = signature self._setObject( signature.getGid(), signature )
def delSignature(self, gid): def delSignature(self, gid):
""" """
add a Signature to the subscription add a Signature to the subscription
""" """
del self.signatures[gid] #del self.signatures[gid]
self._delObject(gid)
def getSignature(self, gid): def getSignature(self, gid):
""" """
add a Signature to the subscription add a Signature to the subscription
""" """
# This is just a test XXX To be removed o = None
#dict = {} if gid in self.objectIds():
#for key in self.signatures.keys(): o = self._getOb(gid)
# dict[key]=self.signatures[key].getPartialXML() return o
#LOG('Subscription',0,'dict: %s' % str(dict))
if self.signatures.has_key(gid):
return self.signatures[gid]
return None
def getSignatureList(self): def getSignatureList(self):
""" """
add a Signature to the subscription add a Signature to the subscription
""" """
signature_list = [] return self.objectValues()
for key in self.signatures.keys():
signature_list += [self.signatures[key]]
return signature_list
def hasSignature(self, gid): def hasSignature(self, gid):
""" """
Check if there's a signature with this uid Check if there's a signature with this uid
""" """
LOG('Subscription',0,'keys: %s' % str(self.signatures.keys())) #return self.signatures.has_key(gid)
return self.signatures.has_key(gid) return gid in self.objectIds()
def resetAllSignatures(self): def resetAllSignatures(self):
""" """
Reset all signatures Reset all signatures
""" """
self.signatures = PersistentMapping() #self.signatures = PersistentMapping()
for o in self.objectValues():
self._delObject(o.id)
def getGidList(self): def getGidList(self):
""" """
Returns the list of ids from signature Returns the list of ids from signature
""" """
return self.signatures.keys() return self.objectIds()
def getConflictList(self): def getConflictList(self):
""" """
...@@ -920,17 +967,10 @@ class Subscription(SyncCode, Implicit): ...@@ -920,17 +967,10 @@ class Subscription(SyncCode, Implicit):
""" """
Set the status of every object as NOT_SYNCHRONIZED Set the status of every object as NOT_SYNCHRONIZED
""" """
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXX for o in self.objectValues():
# XXX for debugging only, to be removed
dict_sign = {}
for object_id in self.signatures.keys():
dict_sign[object_id] = self.signatures[object_id].getStatus()
LOG('startSynchronization',0,'signatures_status: %s' % str(dict_sign))
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
for object_id in self.signatures.keys():
# Change the status only if we are not in a conflict mode # Change the status only if we are not in a conflict mode
if not(self.signatures[object_id].getStatus() in (self.CONFLICT,self.PUB_CONFLICT_MERGE, if not(o.getStatus() in (self.CONFLICT,self.PUB_CONFLICT_MERGE,
self.PUB_CONFLICT_CLIENT_WIN)): self.PUB_CONFLICT_CLIENT_WIN)):
self.signatures[object_id].setStatus(self.NOT_SYNCHRONIZED) o.setStatus(self.NOT_SYNCHRONIZED)
self.signatures[object_id].setPartialXML(None) o.setPartialXML(None)
self.signatures[object_id].setTempXML(None) o.setTempXML(None)
...@@ -29,13 +29,15 @@ ERP portal_synchronizations tool. ...@@ -29,13 +29,15 @@ ERP portal_synchronizations tool.
""" """
from OFS.SimpleItem import SimpleItem from OFS.SimpleItem import SimpleItem
from OFS.Folder import Folder from Products.ERP5Type.Document.Folder import Folder
from Products.ERP5Type.Base import Base
from Products.CMFCore.utils import UniqueObject from Products.CMFCore.utils import UniqueObject
from Globals import InitializeClass, DTMLFile, PersistentMapping, Persistent from Globals import InitializeClass, DTMLFile, PersistentMapping, Persistent
from AccessControl import ClassSecurityInfo, getSecurityManager from AccessControl import ClassSecurityInfo, getSecurityManager
from Products.CMFCore import CMFCorePermissions from Products.CMFCore import CMFCorePermissions
from Products.ERP5SyncML import _dtmldir from Products.ERP5SyncML import _dtmldir
from Publication import Publication,Subscriber from Publication import Publication,Subscriber
from Products.BTreeFolder2.BTreeFolder2 import BTreeFolder2
from Subscription import Subscription,Signature from Subscription import Subscription,Signature
from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml from xml.dom.ext.reader.Sax2 import FromXmlStream, FromXml
from xml.dom.minidom import parse, parseString from xml.dom.minidom import parse, parseString
...@@ -59,11 +61,8 @@ from zLOG import LOG ...@@ -59,11 +61,8 @@ from zLOG import LOG
from Conduit.ERP5Conduit import ERP5Conduit from Conduit.ERP5Conduit import ERP5Conduit
class SynchronizationError( Exception ): class SynchronizationTool( SubscriptionSynchronization, PublicationSynchronization,
pass UniqueObject, Folder, Base):
class SynchronizationTool( UniqueObject, SimpleItem,
SubscriptionSynchronization, PublicationSynchronization ):
""" """
This tool implements the synchronization algorithm This tool implements the synchronization algorithm
""" """
...@@ -89,9 +88,10 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -89,9 +88,10 @@ class SynchronizationTool( UniqueObject, SimpleItem,
email = 1 email = 1
same_export = 1 same_export = 1
def __init__( self ): # Multiple inheritance inconsistency caused by Base must be circumvented
self.list_publications = PersistentMapping() def __init__( self, *args, **kwargs ):
self.list_subscriptions = PersistentMapping() Folder.__init__(self, self.id, **kwargs)
# #
# ZMI methods # ZMI methods
...@@ -109,7 +109,7 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -109,7 +109,7 @@ class SynchronizationTool( UniqueObject, SimpleItem,
, 'action' : 'manageConflicts' , 'action' : 'manageConflicts'
} }
) )
+ SimpleItem.manage_options + Folder.manage_options
) )
security.declareProtected( CMFCorePermissions.ManagePortal security.declareProtected( CMFCorePermissions.ManagePortal
...@@ -156,82 +156,107 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -156,82 +156,107 @@ class SynchronizationTool( UniqueObject, SimpleItem,
) )
security.declareProtected(Permissions.ModifyPortalContent, 'manage_addPublication') security.declareProtected(Permissions.ModifyPortalContent, 'manage_addPublication')
def manage_addPublication(self, id, publication_url, destination_path, def manage_addPublication(self, title, publication_url, destination_path,
query, xml_mapping, gpg_key, RESPONSE=None): query, xml_mapping, gpg_key, RESPONSE=None):
""" """
create a new publication create a new publication
""" """
pub = Publication(id, publication_url, destination_path, #if not('publications' in self.objectIds()):
# publications = Folder('publications')
# self._setObject(publications.id, publications)
new_id = self.getPublicationIdFromTitle(title)
pub = Publication(new_id, title, publication_url, destination_path,
query, xml_mapping, gpg_key) query, xml_mapping, gpg_key)
if len(self.list_publications) == 0: self._setObject( new_id, pub )
self.list_publications = PersistentMapping() #if len(self.list_publications) == 0:
self.list_publications[id] = pub # self.list_publications = PersistentMapping()
#self.list_publications[id] = pub
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_addSubscription') security.declareProtected(Permissions.ModifyPortalContent, 'manage_addSubscription')
def manage_addSubscription(self, id, publication_url, subscription_url, def manage_addSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, gpg_key, RESPONSE=None): destination_path, query, xml_mapping, gpg_key, RESPONSE=None):
""" """
XXX should be renamed as addSubscription XXX should be renamed as addSubscription
create a new subscription create a new subscription
""" """
sub = Subscription(id, publication_url, subscription_url, #if not('subscriptions' in self.objectIds()):
# subscriptions = Folder('subscriptions')
# self._setObject(subscriptions.id, subscriptions)
new_id = self.getSubscriptionIdFromTitle(title)
sub = Subscription(new_id, title, publication_url, subscription_url,
destination_path, query, xml_mapping, gpg_key) destination_path, query, xml_mapping, gpg_key)
if len(self.list_subscriptions) == 0: self._setObject( new_id, sub )
self.list_subscriptions = PersistentMapping() #if len(self.list_subscriptions) == 0:
self.list_subscriptions[id] = sub # self.list_subscriptions = PersistentMapping()
#self.list_subscriptions[id] = sub
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_editPublication') security.declareProtected(Permissions.ModifyPortalContent, 'manage_editPublication')
def manage_editPublication(self, id, publication_url, destination_path, def manage_editPublication(self, title, publication_url, destination_path,
query, xml_mapping, gpg_key, RESPONSE=None): query, xml_mapping, gpg_key, RESPONSE=None):
""" """
modify a publication modify a publication
""" """
pub = Publication(id, publication_url, destination_path, id = self.getPublicationIdFromTitle(title)
query, xml_mapping, gpg_key) pub = self._getOb(id)
self.list_publications[id] = pub pub.setTitle(title)
pub.setPublicationUrl(publication_url)
pub.setDestinationPath(destination_path)
pub.setQuery(query)
pub.setXMLMapping(xml_mapping)
pub.setGPGKey(gpg_key)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_editSubscription') security.declareProtected(Permissions.ModifyPortalContent, 'manage_editSubscription')
def manage_editSubscription(self, id, publication_url, subscription_url, def manage_editSubscription(self, title, publication_url, subscription_url,
destination_path, query, xml_mapping, gpg_key, RESPONSE=None): destination_path, query, xml_mapping, gpg_key, RESPONSE=None):
""" """
modify a subscription modify a subscription
""" """
sub = Subscription(id, publication_url, subscription_url, id = self.getSubscriptionIdFromTitle(title)
destination_path, query, xml_mapping, gpg_key) sub = self._getOb(id)
self.list_subscriptions[id] = sub sub.setTitle(title)
sub.setPublicationUrl(publication_url)
sub.setDestinationPath(destination_path)
sub.setQuery(query)
sub.setXMLMapping(xml_mapping)
sub.setGPGKey(gpg_key)
sub.setSubscriptionUrl(subscription_url)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_deletePublication') security.declareProtected(Permissions.ModifyPortalContent, 'manage_deletePublication')
def manage_deletePublication(self, id, RESPONSE=None): def manage_deletePublication(self, title, RESPONSE=None):
""" """
delete a publication delete a publication
""" """
del self.list_publications[id] id = self.getPublicationIdFromTitle(title)
self._delObject(id)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_deleteSubscription') security.declareProtected(Permissions.ModifyPortalContent, 'manage_deleteSubscription')
def manage_deleteSubscription(self, id, RESPONSE=None): def manage_deleteSubscription(self, title, RESPONSE=None):
""" """
delete a subscription delete a subscription
""" """
del self.list_subscriptions[id] id = self.getSubscriptionIdFromTitle(title)
self._delObject(id)
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
security.declareProtected(Permissions.ModifyPortalContent, 'manage_resetPublication') security.declareProtected(Permissions.ModifyPortalContent, 'manage_resetPublication')
def manage_resetPublication(self, id, RESPONSE=None): def manage_resetPublication(self, title, RESPONSE=None):
""" """
reset a publication reset a publication
""" """
self.list_publications[id].resetAllSubscribers() id = self.getPublicationIdFromTitle(title)
pub = self.getObject(id)
pub.resetAllSubscribers()
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('managePublications') RESPONSE.redirect('managePublications')
...@@ -240,8 +265,10 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -240,8 +265,10 @@ class SynchronizationTool( UniqueObject, SimpleItem,
""" """
reset a subscription reset a subscription
""" """
self.list_subscriptions[id].resetAllSignatures() id = self.getSubscriptionIdFromTitle(title)
self.list_subscriptions[id].resetAnchors() sub = self.getObject(id)
sub.resetAllSignatures()
sub.resetAnchors()
if RESPONSE is not None: if RESPONSE is not None:
RESPONSE.redirect('manageSubscriptions') RESPONSE.redirect('manageSubscriptions')
...@@ -250,23 +277,18 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -250,23 +277,18 @@ class SynchronizationTool( UniqueObject, SimpleItem,
""" """
Return a list of publications Return a list of publications
""" """
return_list = [] object_list = self.objectValues()
if type(self.list_publications) is type([]): # For compatibility with old object_list = filter(lambda x: x.id.find('pub')==0,object_list)
# SynchronizationTool, XXX To be removed return object_list
self.list_publications = PersistentMapping()
for key in self.list_publications.keys():
LOG('getPublicationList',0,'key: %s, pub:%s' % (key,repr(self.list_publications[key])))
return_list += [self.list_publications[key].__of__(self)]
return return_list
security.declareProtected(Permissions.AccessContentsInformation,'getPublication') security.declareProtected(Permissions.AccessContentsInformation,'getPublication')
def getPublication(self, id): def getPublication(self, title):
""" """
Return the publications with this id Return the publications with this id
""" """
#self.list_publications=PersistentMapping() for p in self.getPublicationList():
if self.list_publications.has_key(id): if p.getTitle() == title:
return self.list_publications[id].__of__(self) return p
return None return None
security.declareProtected(Permissions.AccessContentsInformation,'getSubscriptionList') security.declareProtected(Permissions.AccessContentsInformation,'getSubscriptionList')
...@@ -274,21 +296,17 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -274,21 +296,17 @@ class SynchronizationTool( UniqueObject, SimpleItem,
""" """
Return a list of publications Return a list of publications
""" """
return_list = [] object_list = self.objectValues()
if type(self.list_subscriptions) is type([]): # For compatibility with old object_list = filter(lambda x: x.id.find('sub')==0,object_list)
# SynchronizationTool, XXX To be removed return object_list
self.list_subscriptions = PersistentMapping()
for key in self.list_subscriptions.keys():
return_list += [self.list_subscriptions[key].__of__(self)]
return return_list
def getSubscription(self, id): def getSubscription(self, title):
""" """
Returns the subscription with this id Returns the subscription with this id
""" """
for subscription in self.getSubscriptionList(): for s in self.getSubscriptionList():
if subscription.getId()==id: if s.getTitle() == title:
return subscription return s
return None return None
...@@ -735,7 +753,7 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -735,7 +753,7 @@ class SynchronizationTool( UniqueObject, SimpleItem,
if len(message_list) == 0: if len(message_list) == 0:
for subscription in self.getSubscriptionList(): for subscription in self.getSubscriptionList():
LOG('sync, subcription:',0,subscription) LOG('sync, subcription:',0,subscription)
self.activate(activity='RAMQueue').SubSync(subscription.getId()) self.activate(activity='RAMQueue').SubSync(subscription.getTitle())
security.declarePublic('readResponse') security.declarePublic('readResponse')
def readResponse(self, text=None, sync_id=None, to_url=None, from_url=None): def readResponse(self, text=None, sync_id=None, to_url=None, from_url=None):
...@@ -758,11 +776,11 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -758,11 +776,11 @@ class SynchronizationTool( UniqueObject, SimpleItem,
# to know if we will call a publication or subscription XXX # to know if we will call a publication or subscription XXX
gpg_key = '' gpg_key = ''
for publication in self.getPublicationList(): for publication in self.getPublicationList():
if publication.getId()==sync_id: if publication.getTitle()==sync_id:
gpg_key = publication.getGPGKey() gpg_key = publication.getGPGKey()
if gpg_key == '': if gpg_key == '':
for subscription in self.getSubscriptionList(): for subscription in self.getSubscriptionList():
if subscription.getId()==sync_id: if subscription.getTitle()==sync_id:
gpg_key = subscription.getGPGKey() gpg_key = subscription.getGPGKey()
# decrypt the message if needed # decrypt the message if needed
if gpg_key not in (None,''): if gpg_key not in (None,''):
...@@ -791,14 +809,14 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -791,14 +809,14 @@ class SynchronizationTool( UniqueObject, SimpleItem,
if subnode2.nodeName == 'Target': if subnode2.nodeName == 'Target':
url = subnode2.childNodes[0].data url = subnode2.childNodes[0].data
for publication in self.getPublicationList(): for publication in self.getPublicationList():
if publication.getPublicationUrl()==url and publication.getId()==sync_id: if publication.getPublicationUrl()==url and publication.getTitle()==sync_id:
result = self.PubSync(sync_id,xml) result = self.PubSync(sync_id,xml)
# Then encrypt the message # Then encrypt the message
xml = result['xml'] xml = result['xml']
xml = self.sendResponse(xml=xml,domain=publication,send=0) xml = self.sendResponse(xml=xml,domain=publication,send=0)
return xml return xml
for subscription in self.getSubscriptionList(): for subscription in self.getSubscriptionList():
if subscription.getSubscriptionUrl()==url and subscription.getId()==sync_id: if subscription.getSubscriptionUrl()==url and subscription.getTitle()==sync_id:
result = self.activate(activity='RAMQueue').SubSync(sync_id,xml) result = self.activate(activity='RAMQueue').SubSync(sync_id,xml)
#result = self.SubSync(sync_id,xml) #result = self.SubSync(sync_id,xml)
...@@ -818,4 +836,25 @@ class SynchronizationTool( UniqueObject, SimpleItem, ...@@ -818,4 +836,25 @@ class SynchronizationTool( UniqueObject, SimpleItem,
xml = None xml = None
return xml return xml
security.declareProtected(Permissions.ModifyPortalContent, 'getPublicationIdFromTitle')
def getPublicationIdFromTitle(self, title):
"""
simply return an id from a title
"""
return 'pub_' + title
security.declareProtected(Permissions.ModifyPortalContent, 'getPublicationIdFromTitle')
def getSubscriptionIdFromTitle(self, title):
"""
simply return an id from a title
"""
return 'sub_' + title
InitializeClass( SynchronizationTool ) InitializeClass( SynchronizationTool )
...@@ -43,7 +43,7 @@ except ImportError: ...@@ -43,7 +43,7 @@ except ImportError:
import commands import commands
from zLOG import LOG from zLOG import LOG
class XMLSyncUtilsMixin(SyncCode, ActiveObject): class XMLSyncUtilsMixin(SyncCode):
def SyncMLHeader(self, session_id, msg_id, target, source): def SyncMLHeader(self, session_id, msg_id, target, source):
""" """
...@@ -748,7 +748,7 @@ class XMLSyncUtilsMixin(SyncCode, ActiveObject): ...@@ -748,7 +748,7 @@ class XMLSyncUtilsMixin(SyncCode, ActiveObject):
if next_action.nodeName == 'Add': if next_action.nodeName == 'Add':
# Then store the xml of this new subobject # Then store the xml of this new subobject
if object is None: if object is None:
object_id = domain.generateNewId(object=destination_path) object_id = domain.generateNewIdWithGenerator(object=destination_path)
conflict_list += conduit.addNode(xml=data_subnode, object=destination_path, conflict_list += conduit.addNode(xml=data_subnode, object=destination_path,
object_id=object_id) object_id=object_id)
object = domain.getObjectFromGid(object_gid) object = domain.getObjectFromGid(object_gid)
......
...@@ -40,18 +40,30 @@ document_classes = generateInitFiles(this_module, globals()) ...@@ -40,18 +40,30 @@ document_classes = generateInitFiles(this_module, globals())
# Update ERP5 Globals # Update ERP5 Globals
from Products.ERP5Type.Utils import initializeProduct, updateGlobals from Products.ERP5Type.Utils import initializeProduct, updateGlobals
import Interface, PropertySheet, Permissions, Constraint
updateGlobals( this_module, globals(),
property_sheet_module = PropertySheet,
interface_module = Interface,
permissions_module = Permissions,
constraint_module = Constraint)
# Define object classes and tools # Define object classes and tools
import SynchronizationTool import SynchronizationTool
object_classes = () object_classes = (Subscription.Subscription, Publication.Publication,)
portal_tools = (SynchronizationTool.SynchronizationTool,) portal_tools = (SynchronizationTool.SynchronizationTool,)
content_classes = () content_classes = ()
content_constructors = () content_constructors = ()
# Finish installation # Finish installation
def initialize( context ): def initialize( context ):
import Document
initializeProduct(context, this_module, globals(), initializeProduct(context, this_module, globals(),
document_module = Document,
document_classes = document_classes,
object_classes = object_classes, object_classes = object_classes,
portal_tools = portal_tools, portal_tools = portal_tools,
content_constructors = content_constructors, content_constructors = content_constructors,
content_classes = content_classes) content_classes = content_classes)
...@@ -40,11 +40,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -40,11 +40,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Id Title
</div> </div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id" value="<dtml-var getId>" size="40"/> <input type="text" name="title" value="<dtml-var getTitle>" size="40"/>
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -107,12 +107,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -107,12 +107,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<form action="manage_resetPublication" method="POST"> <form action="manage_resetPublication" method="POST">
<td align="left" valign="top"> <td align="left" valign="top">
<input type="submit" value=" Reset "> <input type="submit" value=" Reset ">
<input type="hidden" name="id" value="<dtml-var getId>" > <input type="hidden" name="title" value="<dtml-var getTitle>" >
</form> </form>
<form action="manage_deletePublication" method="POST"> <form action="manage_deletePublication" method="POST">
<td align="left" valign="top"> <td align="left" valign="top">
<input type="submit" value=" Delete "> <input type="submit" value=" Delete ">
<input type="hidden" name="id" value="<dtml-var getId>" > <input type="hidden" name="title" value="<dtml-var getTitle>" >
</form> </form>
</td> </td>
</tr> </tr>
......
...@@ -40,11 +40,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -40,11 +40,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Id Title
</div> </div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id" value="<dtml-var getId>" size="40"/> <input type="text" name="title" value="<dtml-var getTitle>" size="40"/>
</td> </td>
</tr> </tr>
<tr> <tr>
...@@ -117,17 +117,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -117,17 +117,17 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<form action="SubSync" method="POST"> <form action="SubSync" method="POST">
<td align="left" valign="top"> <td align="left" valign="top">
<input type="submit" value=" Sync "> <input type="submit" value=" Sync ">
<input type="hidden" name="id" value="<dtml-var getId>" > <input type="hidden" name="title" value="<dtml-var getTitle>" >
</form> </form>
<form action="manage_resetSubscription" method="POST"> <form action="manage_resetSubscription" method="POST">
<td align="left" valign="top"> <td align="left" valign="top">
<input type="submit" value=" Reset "> <input type="submit" value=" Reset ">
<input type="hidden" name="id" value="<dtml-var getId>" > <input type="hidden" name="title" value="<dtml-var getTitle>" >
</form> </form>
<form action="manage_deleteSubscription" method="POST"> <form action="manage_deleteSubscription" method="POST">
<td align="left" valign="top"> <td align="left" valign="top">
<input type="submit" value=" Delete "> <input type="submit" value=" Delete ">
<input type="hidden" name="id" value="<dtml-var getId>" > <input type="hidden" name="title" value="<dtml-var getTitle>" >
</form> </form>
</td> </td>
</tr> </tr>
......
...@@ -36,11 +36,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -36,11 +36,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Id Title
</div> </div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id" size="40" /> <input type="text" name="title" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
......
...@@ -36,11 +36,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ...@@ -36,11 +36,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
<tr> <tr>
<td align="left" valign="top"> <td align="left" valign="top">
<div class="form-label"> <div class="form-label">
Id Title
</div> </div>
</td> </td>
<td align="left" valign="top"> <td align="left" valign="top">
<input type="text" name="id" size="40" /> <input type="text" name="title" size="40" />
</td> </td>
</tr> </tr>
<tr> <tr>
......
...@@ -318,10 +318,10 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -318,10 +318,10 @@ class TestERP5SyncML(ERP5TypeTestCase):
file.write('') file.write('')
file.close() file.close()
nb_message = 1 nb_message = 1
result = portal_sync.SubSync(subscription.getId()) result = portal_sync.SubSync(subscription.getTitle())
while result['has_response']==1: while result['has_response']==1:
portal_sync.PubSync(publication.getId()) portal_sync.PubSync(publication.getTitle())
result = portal_sync.SubSync(subscription.getId()) result = portal_sync.SubSync(subscription.getTitle())
nb_message += 1 + result['has_response'] nb_message += 1 + result['has_response']
return nb_message return nb_message
...@@ -349,16 +349,16 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -349,16 +349,16 @@ class TestERP5SyncML(ERP5TypeTestCase):
file.write('') file.write('')
file.close() file.close()
nb_message = 1 nb_message = 1
result = portal_sync.SubSync(subscription.getId()) result = portal_sync.SubSync(subscription.getTitle())
while result['has_response']==1: while result['has_response']==1:
# We do thing three times, so that we will test # We do thing three times, so that we will test
# if we manage well duplicate messages # if we manage well duplicate messages
portal_sync.PubSync(publication.getId()) portal_sync.PubSync(publication.getTitle())
portal_sync.PubSync(publication.getId()) portal_sync.PubSync(publication.getTitle())
portal_sync.PubSync(publication.getId()) portal_sync.PubSync(publication.getTitle())
result = portal_sync.SubSync(subscription.getId()) result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription.getId()) result = portal_sync.SubSync(subscription.getTitle())
result = portal_sync.SubSync(subscription.getId()) result = portal_sync.SubSync(subscription.getTitle())
nb_message += 1 + result['has_response'] nb_message += 1 + result['has_response']
return nb_message return nb_message
...@@ -372,13 +372,22 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -372,13 +372,22 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.login() self.login()
self.setupPublicationAndSubscription(quiet=1,run=1) self.setupPublicationAndSubscription(quiet=1,run=1)
nb_person = self.populatePersonServer(quiet=1,run=1) nb_person = self.populatePersonServer(quiet=1,run=1)
portal_sync = self.getSynchronizationTool()
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.SLOW_SYNC)
# Synchronize the first client # Synchronize the first client
nb_message1 = self.synchronize(self.sub_id1) nb_message1 = self.synchronize(self.sub_id1)
for sub in portal_sync.getSubscriptionList():
if sub.getTitle() == self.sub_id1:
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
else:
self.assertEquals(sub.getSynchronizationType(),SyncCode.SLOW_SYNC)
self.failUnless(nb_message1==self.nb_message_first_synchronization) self.failUnless(nb_message1==self.nb_message_first_synchronization)
# Synchronize the second client # Synchronize the second client
nb_message2 = self.synchronize(self.sub_id2) nb_message2 = self.synchronize(self.sub_id2)
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
self.failUnless(nb_message2==self.nb_message_first_synchronization) self.failUnless(nb_message2==self.nb_message_first_synchronization)
portal_sync = self.getSynchronizationTool()
subscription1 = portal_sync.getSubscription(self.sub_id1) subscription1 = portal_sync.getSubscription(self.sub_id1)
subscription2 = portal_sync.getSubscription(self.sub_id2) subscription2 = portal_sync.getSubscription(self.sub_id2)
self.failUnless(len(subscription1.getObjectList())==nb_person) self.failUnless(len(subscription1.getObjectList())==nb_person)
...@@ -1153,6 +1162,43 @@ class TestERP5SyncML(ERP5TypeTestCase): ...@@ -1153,6 +1162,43 @@ class TestERP5SyncML(ERP5TypeTestCase):
self.failUnless(person1_c.getLastName()==self.last_name1) self.failUnless(person1_c.getLastName()==self.last_name1)
SyncCode.MAX_LINES = previous_max_lines SyncCode.MAX_LINES = previous_max_lines
def testGetSynchronizationType(self, quiet=0, run=run_all_test):
# We will try to update some simple data, first
# we change on the server side, the on the client side
if not run: return
if not quiet:
ZopeTestCase._print('\nTest Get Synchronization Type ')
LOG('Testing... ',0,'testGetSynchronizationType')
self.testFirstSynchronization(quiet=1,run=1)
# First we do only modification on server
# Check for each subsription that the synchronization type
# is TWO WAY
portal_sync = self.getSynchronizationTool()
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
person_server = self.getPersonServer()
person1_s = person_server._getOb(self.id1)
kw = {'first_name':self.first_name3,'last_name':self.last_name3}
person1_s.edit(**kw)
self.synchronize(self.sub_id1)
# Then we do only modification on a client
person_client1 = self.getPersonClient1()
person1_c = person_client1._getOb(self.id1)
kw = {'first_name':self.first_name1,'last_name':self.last_name1}
person1_c.edit(**kw)
self.synchronize(self.sub_id1)
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
# Then we do only modification on both the client and the server
# and of course, on the same object
kw = {'first_name':self.first_name3}
person1_s.edit(**kw)
kw = {'description':self.description3}
person1_c.edit(**kw)
self.synchronize(self.sub_id1)
for sub in portal_sync.getSubscriptionList():
self.assertEquals(sub.getSynchronizationType(),SyncCode.TWO_WAY)
# We may add a test in order to check if the slow_sync mode works fine, ie # We may add a test in order to check if the slow_sync mode works fine, ie
# if we do have both object on the client and server side, we must make sure # if we do have both object on the client and server side, we must make sure
# that the server first sends is own data # that the server first sends is own data
......
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