diff --git a/product/ERP5SyncML/Conduit/ERP5Conduit.py b/product/ERP5SyncML/Conduit/ERP5Conduit.py index c61da7fa888e50e7be13242e732caacf0187c6c0..dbc4f2cdb795c34e7bdc7e729064727a1f207ab1 100755 --- a/product/ERP5SyncML/Conduit/ERP5Conduit.py +++ b/product/ERP5SyncML/Conduit/ERP5Conduit.py @@ -150,7 +150,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): if portal_type == 'Workspace': proxy_type = 'folder' proxy = px_tool.createEmptyProxy(proxy_type, - object,portal_type,object_id,docid) + object,portal_type,object_id,docid=docid) proxy.isIndexable = 0 # So it will not be reindexed, this prevent errors # Calculate rpath utool = getToolByName(object, 'portal_url') @@ -184,6 +184,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): conflict_list += self.addNode(xml=sub_xml,object=sub_object, previous_xml=sub_previous_xml, force=force) elif xml.nodeName == self.history_tag or self.isHistoryAdd(xml)>0: + #return conflict_list # XXX to be removed soon # We want to add a workflow action wf_tool = getToolByName(object,'portal_workflow') wf_id = self.getAttribute(xml,'id') @@ -199,9 +200,11 @@ class ERP5Conduit(XMLSyncUtilsMixin): LOG('addNode, status:',0,status) wf_tool.setStatusOf(wf_id,object,status) elif xml.nodeName in self.local_role_list: + #return conflict_list # XXX to be removed soon # We want to add a local role #user = self.getParameter(xml,'user') roles = self.convertXmlValue(xml.childNodes[0].data,data_type='tokens') + roles = list(roles) # Needed for CPS, or we have a CPS error user = roles[0] roles = roles[1:] object.manage_setLocalRoles(user,roles) @@ -217,7 +220,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): LOG('ERP5Conduit',0,'deleteNode') LOG('ERP5Conduit',0,'deleteNode, object.id: %s' % object.getId()) conflict_list = [] - xml = self.convertToXml(xml) + if xml is not None: + xml = self.convertToXml(xml) if object_id is None: LOG('ERP5Conduit',0,'deleteNode, SubObjectDepth: %i' % self.getSubObjectDepth(xml)) if xml.nodeName == self.xml_object_tag: @@ -238,6 +242,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): try: object._delObject(object_id) except (AttributeError, KeyError): + LOG('ERP5Conduit',0,'deleteNode, Unable to delete: %s' % str(object_id)) pass return conflict_list @@ -319,10 +324,16 @@ class ERP5Conduit(XMLSyncUtilsMixin): if 1: # This is a conflict isConflict = 1 - conflict_list += [Conflict(object_path=object.getPhysicalPath(), - keyword=keyword, - local_value=current_data, - remote_value=data)] + string_io = StringIO() + PrettyPrint(xml,stream=string_io) + conflict = Conflict(object_path=object.getPhysicalPath()) + conflict.setXupdate(string_io.getvalue()) + conflict_list += [conflict] + #conflict_list += [Conflict(object_path=object.getPhysicalPath(), + # keyword=keyword, + # xupdate=string_io)] + #local_value=current_data, # not needed any more + #remote_value=data)] # not needed any more # We will now apply the argument with the method edit if args != {} and (isConflict==0 or force): LOG('updateNode',0,'object._edit, args: %s' % str(args)) diff --git a/product/ERP5SyncML/Subscription.py b/product/ERP5SyncML/Subscription.py index 6634b9ad72c29295b24eb8b3c2abe7fcebfb1331..a271c038bdae72a9ef3b1c3f7a57a6eca3a2a35f 100755 --- a/product/ERP5SyncML/Subscription.py +++ b/product/ERP5SyncML/Subscription.py @@ -41,13 +41,14 @@ class Conflict(SyncCode): remote_value : the value sent by the remote box """ - def __init__(self, object_path=None, keyword=None, local_value=None,\ + def __init__(self, object_path=None, keyword=None, xupdate=None, local_value=None,\ remote_value=None, domain=None, domain_id=None): self.object_path=object_path self.keyword = keyword self.setLocalValue(local_value) self.setRemoteValue(remote_value) self.domain = domain + self.resetXupdate() self.domain_id = domain_id def getObjectPath(self): @@ -62,6 +63,37 @@ class Conflict(SyncCode): """ return self.local_value + def getXupdateList(self): + """ + get the xupdate wich gave an error + """ + xupdate_list = [] + if len(self.xupdate)>0: + for xupdate in self.xupdate: + xupdate_list+= [xupdate] + return xupdate_list + + def resetXupdate(self): + """ + Reset the xupdate list + """ + self.xupdate = PersistentMapping() + + def setXupdate(self, xupdate): + """ + set the xupdate + """ + if xupdate == None: + self.resetXupdate() + else: + self.xupdate = self.getXupdateList() + [xupdate] + + def setXupdateList(self, xupdate): + """ + set the xupdate + """ + self.xupdate = xupdate + def setLocalValue(self, value): """ get the domain @@ -318,10 +350,24 @@ class Signature(SyncCode): """ Return the actual action for a partial synchronization """ + LOG('setConflictList, list',0,conflict_list) if conflict_list is None: self.resetConflictList() else: - self.conflict_list = conflict_list + new_conflict_list = [] + # If two conflicts are on the same objects, then + # we join them, so we have a conflict with many xupdate + for conflict in conflict_list: + found = None + for n_conflict in new_conflict_list: + if n_conflict.getObjectPath() == conflict.getObjectPath(): + found = n_conflict + LOG('setConflictList, found',0,found) + if found == None: + new_conflict_list += [conflict] + else: + n_conflict.setXupdate(conflict.getXupdateList()) + self.conflict_list = new_conflict_list class Subscription(SyncCode): """ diff --git a/product/ERP5SyncML/SynchronizationTool.py b/product/ERP5SyncML/SynchronizationTool.py index 8e09c20bcef87e9298710ba3c3b633cfb9c2aecb..6544a76794ac047e438c7d3e57672883f1862315 100755 --- a/product/ERP5SyncML/SynchronizationTool.py +++ b/product/ERP5SyncML/SynchronizationTool.py @@ -245,7 +245,13 @@ class SynchronizationTool( UniqueObject, SimpleItem, return_list += [self.list_subscriptions[key]] return return_list - def getConflictList(self): + def getDomainList(self): + """ + Returns the list of subscriptions and publications + """ + return self.getSubscriptionList() + self.getPublicationList() + + def getConflictList(self, path=None): """ Retrieve the list of all conflicts Here the list is as follow : @@ -256,23 +262,67 @@ class SynchronizationTool( UniqueObject, SimpleItem, for publication in self.getPublicationList(): pub_conflict_list = publication.getConflictList() for conflict in pub_conflict_list: - conflict.setDomain('Publication') + #conflict.setDomain('Publication') + conflict.setDomain(publication) conflict.setDomainId(publication.getId()) conflict_list += [conflict] for subscription in self.getSubscriptionList(): sub_conflict_list = subscription.getConflictList() for conflict in sub_conflict_list: - conflict.setDomain('Subscription') + #conflict.setDomain('Subscription') + conflict.setDomain(subscription) conflict.setDomainId(subscription.getId()) conflict_list += [conflict] + if path is not None: # Retrieve only conflicts for a given path + new_list = [] + for conflict in conflict_list: + if conflict.getObjectPath() == path: + new_list += [conflict] + return new_list return conflict_list - def getSynchronizationState(self, context): - """ - context -- the context on which we are looking for state + def getSynchronizationState(self, path): """ + context : the context on which we are looking for state + This functions have to retrieve the synchronization state, + it will first look in the conflict list, if nothing is found, + then we have to check on a publication/subscription. + This method returns a mapping between subscription and states + """ + conflict_list = self.getConflictList() + state_list= [] + LOG('getSynchronizationState',0,'path: %s' % str(path)) + for conflict in conflict_list: + if conflict.getObjectPath() == path: + LOG('getSynchronizationState',0,'found a conflict: %s' % str(conflict)) + state_list += [[conflict.getDomain(),self.CONFLICT]] + for domain in self.getDomainList(): + destination = domain.getDestinationPath() + LOG('getSynchronizationState',0,'destination: %s' % str(destination)) + j_path = '/'.join(path) + LOG('getSynchronizationState',0,'j_path: %s' % str(j_path)) + if j_path.find(destination)==0: + o_id = j_path[len(destination)+1:].split('/')[0] + LOG('getSynchronizationState',0,'o_id: %s' % o_id) + subscriber_list = [] + if domain.domain_type==self.PUB: + subscriber_list = domain.getSubscriberList() + else: + subscriber_list = [domain] + for subscriber in subscriber_list: + signature = subscriber.getSignature(o_id) + if signature is not None: + state = signature.getStatus() + found = None + # Make sure there is not already a conflict giving the state + for state_item in state_list: + if state_item[0]==subscriber: + found = 1 + if found is None: + state_list += [[subscriber,state]] + return state_list def manageLocalValue(self, domain, domain_id, object_path, RESPONSE=None): """