Commit 6f2372aa authored by Arnaud Fontaine's avatar Arnaud Fontaine

ZODB Components: Migrate ERP5SyncML Product from filesystem.

To avoid too generic names for Products.ERP5SyncML.{Engine,Transport}, prefix
the ZODB Components references with SyncML{Engine,Transport}.
parent c8ad77fb
...@@ -65,7 +65,7 @@ def findMessageListFromPythonInProduct(function_name_list): ...@@ -65,7 +65,7 @@ def findMessageListFromPythonInProduct(function_name_list):
erp5_product_list = ('CMFActivity', 'CMFCategory', erp5_product_list = ('CMFActivity', 'CMFCategory',
'ERP5', 'ERP5Banking', 'ERP5Catalog', 'ERP5', 'ERP5Banking', 'ERP5Catalog',
'ERP5Form', 'ERP5OOo', 'ERP5Security', 'ERP5Form', 'ERP5OOo', 'ERP5Security',
'ERP5SyncML', 'ERP5Type', 'ERP5Wizard', 'ERP5Workflow', 'ERP5Type', 'ERP5Wizard', 'ERP5Workflow',
'HBTreeFolder2', 'MailTemplates', 'TimerService', 'HBTreeFolder2', 'MailTemplates', 'TimerService',
'ZMySQLDA', 'ZSQLCatalog', 'ZMySQLDA', 'ZSQLCatalog',
) )
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLConflict</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Document.SyncMLConflict</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.SyncMLConflict</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,10 +27,10 @@ ...@@ -27,10 +27,10 @@
# #
############################################################################## ##############################################################################
from Products.ERP5SyncML.Document.SyncMLSubscription import SyncMLSubscription from erp5.component.document.SyncMLSubscription import SyncMLSubscription
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5SyncML.SyncMLConstant import ACTIVITY_PRIORITY from erp5.component.module.SyncMLConstant import ACTIVITY_PRIORITY
from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod from Products.ERP5Type.UnrestrictedMethod import UnrestrictedMethod
class SyncMLPublication(SyncMLSubscription): class SyncMLPublication(SyncMLSubscription):
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLPublication</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Document.SyncMLPublication</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.SyncMLPublication</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -34,11 +34,11 @@ from AccessControl import ClassSecurityInfo ...@@ -34,11 +34,11 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type import PropertySheet from Products.ERP5Type import PropertySheet
from Products.ERP5SyncML.Utils import PdataHelper from erp5.component.module.SyncMLUtils import PdataHelper
from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter from Products.ERP5Type.Accessor.Constant import PropertyGetter as ConstantGetter
_MARKER = [] _MARKER = object()
class SyncMLSignature(XMLObject): class SyncMLSignature(XMLObject):
""" """
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLSignature</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Document.SyncMLSignature</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.SyncMLSignature</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -41,18 +41,18 @@ from MySQLdb import ProgrammingError ...@@ -41,18 +41,18 @@ from MySQLdb import ProgrammingError
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5Type import Permissions, PropertySheet
from Products.ERP5Type.Utils import deprecated from Products.ERP5Type.Utils import deprecated
from Products.ERP5SyncML.XMLSyncUtils import getConduitByName, \ from erp5.component.module.XMLSyncUtils import getConduitByName, \
buildAnchorFromDate buildAnchorFromDate
from Products.ERP5SyncML.SyncMLConstant import MAX_OBJECTS, ACTIVITY_PRIORITY,\ from erp5.component.module.SyncMLConstant import MAX_OBJECTS, ACTIVITY_PRIORITY,\
NULL_ANCHOR NULL_ANCHOR
from Products.ERP5SyncML.SyncMLMessage import SyncMLResponse from erp5.component.module.SyncMLMessage import SyncMLResponse
from Products.ERP5SyncML.Transport.HTTP import HTTPTransport from erp5.component.module.SyncMLTransportHTTP import HTTPTransport
from Products.ERP5SyncML.Transport.File import FileTransport from erp5.component.module.SyncMLTransportFile import FileTransport
from Products.ERP5SyncML.Transport.Mail import MailTransport from erp5.component.module.SyncMLTransportMail import MailTransport
from Products.ERP5SyncML.Transport.ERP5 import ERP5Transport from erp5.component.module.SyncMLTransportERP5 import ERP5Transport
from Products.ERP5SyncML.SyncMLConstant import MAX_LEN, ADD_ACTION, \ from erp5.component.module.SyncMLConstant import MAX_LEN, ADD_ACTION, \
REPLACE_ACTION REPLACE_ACTION
from Products.ERP5SyncML.XMLSyncUtils import cutXML from erp5.component.module.XMLSyncUtils import cutXML
transport_scheme_dict = { transport_scheme_dict = {
"http" : HTTPTransport(), "http" : HTTPTransport(),
...@@ -68,7 +68,7 @@ MAX_OBJECT_PER_MESSAGE = 300 ...@@ -68,7 +68,7 @@ MAX_OBJECT_PER_MESSAGE = 300
RETRO_COMPATIBLE = True RETRO_COMPATIBLE = True
_MARKER = [] _MARKER = object()
class SyncMLSubscription(XMLObject): class SyncMLSubscription(XMLObject):
""" """
""" """
...@@ -128,8 +128,8 @@ class SyncMLSubscription(XMLObject): ...@@ -128,8 +128,8 @@ class SyncMLSubscription(XMLObject):
if not RETRO_COMPATIBLE: if not RETRO_COMPATIBLE:
raise raise
else: else:
syncml_logger.warning("Script %s does not accept paramaters limit=%s kw=%s" % syncml_logger.warning("Script %s does not accept paramaters limit=%s kw=%s",
(self.getListMethodId(), limit, search_kw,)) self.getListMethodId(), limit, search_kw)
r_list = self.getDocumentList() # It is assumed that r_list = self.getDocumentList() # It is assumed that
# the result is sorted # the result is sorted
result_count = len(r_list) result_count = len(r_list)
...@@ -137,22 +137,22 @@ class SyncMLSubscription(XMLObject): ...@@ -137,22 +137,22 @@ class SyncMLSubscription(XMLObject):
r = [str(x.path) for x in r_list] r = [str(x.path) for x in r_list]
if not limit: if not limit:
# We do not split in activity so call the callback right now # We do not split in activity so call the callback right now
syncml_logger.info("getAndIndex : got %d result and no limit, calling callback..." % syncml_logger.info("getAndIndex : got %d result and no limit, calling callback...",
(result_count,)) result_count)
callback_method = getattr(self, callback) callback_method = getattr(self, callback)
callback_method(path_list=r[:], callback_method(path_list=r[:],
activate_kw=activate_kw, activate_kw=activate_kw,
**method_kw) **method_kw)
else: else:
syncml_logger.info("getAndIndex : got %d, %r result, limit = %r, packet %r" % syncml_logger.info("getAndIndex : got %d, %r result, limit = %r, packet %r",
(result_count, r, limit, packet_size)) result_count, r, limit, packet_size)
generated_other_activity = False generated_other_activity = False
if result_count == limit: if result_count == limit:
# Recursive call to prevent too many activity generation # Recursive call to prevent too many activity generation
next_kw = dict(activate_kw, priority=1+activate_kw.get('priority', 1)) next_kw = dict(activate_kw, priority=1+activate_kw.get('priority', 1))
kw["min_id"] = r_list[-1].getId() kw["min_id"] = r_list[-1].getId()
syncml_logger.info("--> calling getAndIndex in activity, min = %s" % syncml_logger.info("--> calling getAndIndex in activity, min = %s",
(kw["min_id"],)) kw["min_id"])
self.activate(**next_kw).getAndIndex( self.activate(**next_kw).getAndIndex(
callback, method_kw, activate_kw, **kw) callback, method_kw, activate_kw, **kw)
generated_other_activity = True generated_other_activity = True
...@@ -161,23 +161,23 @@ class SyncMLSubscription(XMLObject): ...@@ -161,23 +161,23 @@ class SyncMLSubscription(XMLObject):
callback_method = getattr(activate(**activate_kw), callback) callback_method = getattr(activate(**activate_kw), callback)
if generated_other_activity: if generated_other_activity:
for i in xrange(0, result_count, packet_size): for i in xrange(0, result_count, packet_size):
syncml_logger.info("-- getAndIndex : recursive call, generating for %s" syncml_logger.info("-- getAndIndex : recursive call, generating for %s",
% (r[i:i+packet_size],)) r[i:i+packet_size])
callback_method(path_list=r[i:i+packet_size], callback_method(path_list=r[i:i+packet_size],
activate_kw=activate_kw, activate_kw=activate_kw,
**method_kw) **method_kw)
else: else:
if result_count > packet_size and limit: if result_count > packet_size and limit:
for i in xrange(0, result_count-packet_size, packet_size): for i in xrange(0, result_count-packet_size, packet_size):
syncml_logger.info("-- getAndIndex : i %s, call, generating for %s : %s" % syncml_logger.info("-- getAndIndex : i %s, call, generating for %s : %s",
(i, r[i:i+packet_size], activate_kw)) i, r[i:i+packet_size], activate_kw)
callback_method(path_list=r[i:i+packet_size], callback_method(path_list=r[i:i+packet_size],
**method_kw) **method_kw)
final_min = i + packet_size final_min = i + packet_size
else: else:
final_min = 0 final_min = 0
syncml_logger.info("---- getAndIndex : final call for %s %s : %s" \ syncml_logger.info("---- getAndIndex : final call for %s %s : %s",
%(final_min, r[final_min:], activate_kw)) final_min, r[final_min:], activate_kw)
callback_method(path_list=r[final_min:], callback_method(path_list=r[final_min:],
activate_kw=activate_kw, activate_kw=activate_kw,
**method_kw) **method_kw)
...@@ -205,7 +205,7 @@ class SyncMLSubscription(XMLObject): ...@@ -205,7 +205,7 @@ class SyncMLSubscription(XMLObject):
Return the path of the subscription that will be used in sql table Return the path of the subscription that will be used in sql table
_ char must be escaped because of the LIKE behaviour _ char must be escaped because of the LIKE behaviour
""" """
return "%s/%%" % (self.getSourceValue().getPath().replace("_","\_"),) return "%s/%%" % (self.getSourceValue().getPath().replace("_","\_"),) # pylint: disable=anomalous-backslash-in-string
security.declarePrivate('sendSyncCommand') security.declarePrivate('sendSyncCommand')
def sendSyncCommand(self, min_gid, max_gid, message_id, activate_kw): def sendSyncCommand(self, min_gid, max_gid, message_id, activate_kw):
...@@ -244,9 +244,9 @@ class SyncMLSubscription(XMLObject): ...@@ -244,9 +244,9 @@ class SyncMLSubscription(XMLObject):
# Send the message in activity to prevent recomputing data in case of # Send the message in activity to prevent recomputing data in case of
# transport failure # transport failure
if syncml_response: if syncml_response:
syncml_logger("---- %s sending %s notifications of sync" syncml_logger("---- %s sending %s notifications of sync",
% (self.getTitle(), self.getTitle(),
syncml_response.sync_confirmation_counter)) syncml_response.sync_confirmation_counter)
self.activate(activity="SQLQueue", self.activate(activity="SQLQueue",
# group_method_id=None, # group_method_id=None,
# group_method_cost=.05, # group_method_cost=.05,
...@@ -274,8 +274,8 @@ class SyncMLSubscription(XMLObject): ...@@ -274,8 +274,8 @@ class SyncMLSubscription(XMLObject):
search_kw = dict(kw) search_kw = dict(kw)
packet_size = search_kw.pop('packet_size', 30) packet_size = search_kw.pop('packet_size', 30)
limit = packet_size * search_kw.pop('activity_count', 100) limit = packet_size * search_kw.pop('activity_count', 100)
syncml_logger.debug("--> calling getAndActivate packet size = %s, limit = %s" % syncml_logger.debug("--> calling getAndActivate packet size = %s, limit = %s",
(packet_size, limit)) packet_size, limit)
# We must know if we have a lower limit or not to propagate # We must know if we have a lower limit or not to propagate
if not kw.has_key("strict_min_gid"): if not kw.has_key("strict_min_gid"):
first_call = True first_call = True
...@@ -292,13 +292,13 @@ class SyncMLSubscription(XMLObject): ...@@ -292,13 +292,13 @@ class SyncMLSubscription(XMLObject):
result_count = len(r) result_count = len(r)
generated_other_activity = False generated_other_activity = False
if result_count: if result_count:
syncml_logger.info("getAndActivate : got %d result" % (result_count,)) syncml_logger.info("getAndActivate : got %d result", result_count)
if result_count == limit: if result_count == limit:
# Recursive call to prevent too many activity generation # Recursive call to prevent too many activity generation
next_kw = dict(activate_kw, priority=1+activate_kw.get('priority', 1)) next_kw = dict(activate_kw, priority=1+activate_kw.get('priority', 1))
kw["strict_min_gid"] = r[-1] kw["strict_min_gid"] = r[-1]
syncml_logger.info("--> calling getAndActivate in activity, min = %s" % syncml_logger.info("--> calling getAndActivate in activity, min = %s",
(kw.get("strict_min_gid", None),)) kw.get("strict_min_gid", None))
self.activate(**next_kw).getAndActivate( self.activate(**next_kw).getAndActivate(
callback, activate_kw, **kw) callback, activate_kw, **kw)
generated_other_activity = True generated_other_activity = True
...@@ -321,8 +321,8 @@ class SyncMLSubscription(XMLObject): ...@@ -321,8 +321,8 @@ class SyncMLSubscription(XMLObject):
except IndexError: except IndexError:
# Last packet # Last packet
max_gid = r[-1] max_gid = r[-1]
syncml_logger.info("-- getAndActivate : recursive call i = %s, min = %s, max = %s" \ syncml_logger.info("-- getAndActivate : recursive call i = %s, min = %s, max = %s",
% (i, min_gid, max_gid,)) i, min_gid, max_gid)
callback_method(min_gid=min_gid, callback_method(min_gid=min_gid,
max_gid=max_gid, max_gid=max_gid,
message_id=message_id_list.pop(), message_id=message_id_list.pop(),
...@@ -336,8 +336,8 @@ class SyncMLSubscription(XMLObject): ...@@ -336,8 +336,8 @@ class SyncMLSubscription(XMLObject):
first_call = False first_call = False
else: else:
min_gid = r[i] min_gid = r[i]
syncml_logger.info("-- getAndActivate : call min = %s, max = %s" \ syncml_logger.info("-- getAndActivate : call min = %s, max = %s",
% (min_gid, r[i+packet_size-1])) min_gid, r[i+packet_size-1])
callback_method(min_gid=min_gid, callback_method(min_gid=min_gid,
max_gid=r[i+packet_size-1], max_gid=r[i+packet_size-1],
message_id=message_id_list.pop(), message_id=message_id_list.pop(),
...@@ -351,8 +351,8 @@ class SyncMLSubscription(XMLObject): ...@@ -351,8 +351,8 @@ class SyncMLSubscription(XMLObject):
min_gid = None min_gid = None
else: else:
min_gid = r[final_min] min_gid = r[final_min]
syncml_logger.info("-- getAndActivate : final call min = %s, max = None" \ syncml_logger.info("-- getAndActivate : final call min = %s, max = None",
% (min_gid,)) min_gid)
callback_method(min_gid=min_gid, callback_method(min_gid=min_gid,
max_gid=None, # No limit when last call max_gid=None, # No limit when last call
message_id=message_id_list.pop(), message_id=message_id_list.pop(),
...@@ -456,8 +456,8 @@ class SyncMLSubscription(XMLObject): ...@@ -456,8 +456,8 @@ class SyncMLSubscription(XMLObject):
portal_type='SyncML Signature', portal_type='SyncML Signature',
id=gid, id=gid,
) )
syncml_logger.info("Created a signature for %s - document : %s" syncml_logger.info("Created a signature for %s - document : %s",
% (signature.getPath(), document)) signature.getPath(), document)
if document is not None: if document is not None:
signature.setReference(document.getPath()) signature.setReference(document.getPath())
...@@ -484,7 +484,7 @@ class SyncMLSubscription(XMLObject): ...@@ -484,7 +484,7 @@ class SyncMLSubscription(XMLObject):
signature.appendPartialData(incoming_data) signature.appendPartialData(incoming_data)
incoming_data = signature.getPartialData() incoming_data = signature.getPartialData()
signature.setPartialData(None) signature.setPartialData(None)
__traceback_info__ = (gid, document, incoming_data, action['command']) __traceback_info__ = (gid, document, incoming_data, action['command']) # pylint: disable=unused-variable
# Browse possible actions # Browse possible actions
if action["command"] == 'Add': if action["command"] == 'Add':
status_code = "item_added" # Default status code for addition status_code = "item_added" # Default status code for addition
...@@ -518,7 +518,7 @@ class SyncMLSubscription(XMLObject): ...@@ -518,7 +518,7 @@ class SyncMLSubscription(XMLObject):
if data_diff and len(data_diff): if data_diff and len(data_diff):
# XXX Here maybe a conflict must be raised as document was never # XXX Here maybe a conflict must be raised as document was never
# synchronized and we try to add one which is different # synchronized and we try to add one which is different
syncml_logger.critical("trying to add data, but already existing object exists, diff is\n%s" % (data_diff)) syncml_logger.critical("trying to add data, but already existing object exists, diff is\n%s", data_diff)
conflict_list.extend(conduit.updateNode( conflict_list.extend(conduit.updateNode(
xml=data_diff, xml=data_diff,
...@@ -577,8 +577,8 @@ class SyncMLSubscription(XMLObject): ...@@ -577,8 +577,8 @@ class SyncMLSubscription(XMLObject):
elif action['command'] == 'Delete': elif action['command'] == 'Delete':
status_code="success" status_code="success"
document = self.getDocumentFromGid(signature.getId()) document = self.getDocumentFromGid(signature.getId())
syncml_logger.info("Deleting signature %s & doc %s" %(signature.getPath(), syncml_logger.info("Deleting signature %s & doc %s", signature.getPath(),
document.getPath())) document.getPath())
path_list.remove(signature.getPath()) path_list.remove(signature.getPath())
if document is not None: if document is not None:
# XXX Can't we get conflict ? # XXX Can't we get conflict ?
...@@ -589,8 +589,8 @@ class SyncMLSubscription(XMLObject): ...@@ -589,8 +589,8 @@ class SyncMLSubscription(XMLObject):
# Delete signature # Delete signature
self._delObject(gid) self._delObject(gid)
else: else:
syncml_logger.error("Document with gid %s is already deleted" syncml_logger.error("Document with gid %s is already deleted",
% (gid,)) gid)
self.z_delete_data_from_path(path="%s" %(signature.getPath(),)) self.z_delete_data_from_path(path="%s" %(signature.getPath(),))
else: else:
...@@ -610,8 +610,8 @@ class SyncMLSubscription(XMLObject): ...@@ -610,8 +610,8 @@ class SyncMLSubscription(XMLObject):
else: else:
signature.setData(str(xml_document)) signature.setData(str(xml_document))
signature.synchronize() signature.synchronize()
syncml_logger.info("change state of signature to %s with %s" syncml_logger.info("change state of signature to %s with %s",
% (signature.getValidationState(), signature.getData())) signature.getValidationState(), signature.getData())
if signature: if signature:
# Generate status about the object synchronized # Generate status about the object synchronized
...@@ -625,8 +625,8 @@ class SyncMLSubscription(XMLObject): ...@@ -625,8 +625,8 @@ class SyncMLSubscription(XMLObject):
message_ref=request_message_id) message_ref=request_message_id)
else: # We want to retrieve more data else: # We want to retrieve more data
syncml_logger.info("we need to retrieve more data for %s" syncml_logger.info("we need to retrieve more data for %s",
% (signature.getRelativeUrl(),)) signature.getRelativeUrl())
signature.appendPartialData(incoming_data) signature.appendPartialData(incoming_data)
# XXX Must check if size is present into the xml # XXX Must check if size is present into the xml
# if not, client might ask it to server with a 411 alert # if not, client might ask it to server with a 411 alert
...@@ -665,8 +665,8 @@ class SyncMLSubscription(XMLObject): ...@@ -665,8 +665,8 @@ class SyncMLSubscription(XMLObject):
'priority' :ACTIVITY_PRIORITY + 1, 'priority' :ACTIVITY_PRIORITY + 1,
'tag' : "%s_delete" %(self.getRelativeUrl(),) 'tag' : "%s_delete" %(self.getRelativeUrl(),)
} }
syncml_logger.info("Sending final message for modificationson on %s" syncml_logger.info("Sending final message for modificationson on %s",
% (self.getRelativeUrl(),)) self.getRelativeUrl())
self.activate(**final_activate_kw).sendMessage(xml=str(syncml_response)) self.activate(**final_activate_kw).sendMessage(xml=str(syncml_response))
...@@ -685,10 +685,10 @@ class SyncMLSubscription(XMLObject): ...@@ -685,10 +685,10 @@ class SyncMLSubscription(XMLObject):
signature_path=self.getSearchablePath(), signature_path=self.getSearchablePath(),
source_path=self.getSearchableSourcePath()) source_path=self.getSearchableSourcePath())
syncml_logger.info("\t---> delete signature are %r" % (len(deleted_signature_set))) syncml_logger.info("\t---> delete signature are %r", len(deleted_signature_set))
for r in deleted_signature_set: for r in deleted_signature_set:
syncml_response.addDeleteCommand(gid=r.gid) syncml_response.addDeleteCommand(gid=r.gid)
syncml_logger.info("\t\t---> %r" % (r.gid)) syncml_logger.info("\t\t---> %r", r.gid)
syncml_response.addFinal() syncml_response.addFinal()
# Now send the message # Now send the message
...@@ -698,12 +698,12 @@ class SyncMLSubscription(XMLObject): ...@@ -698,12 +698,12 @@ class SyncMLSubscription(XMLObject):
'priority' :ACTIVITY_PRIORITY + 1, 'priority' :ACTIVITY_PRIORITY + 1,
'tag' : "%s_delete" %(self.getRelativeUrl(),) 'tag' : "%s_delete" %(self.getRelativeUrl(),)
} }
syncml_logger.info("Sending final message for modificationson on %s" syncml_logger.info("Sending final message for modificationson on %s",
% (self.getRelativeUrl(),)) self.getRelativeUrl())
self.activate(**final_activate_kw).sendMessage(xml=str(syncml_response)) self.activate(**final_activate_kw).sendMessage(xml=str(syncml_response))
def getSearchablePath(self): def getSearchablePath(self):
return "%s%%" %(self.getPath().replace('_', '\_'),) return "%s%%" %(self.getPath().replace('_', '\_'),) # pylint: disable=anomalous-backslash-in-string
def _generateSyncCommand(self, action, signature, data_diff ,document_data, gid, def _generateSyncCommand(self, action, signature, data_diff ,document_data, gid,
...@@ -715,7 +715,7 @@ class SyncMLSubscription(XMLObject): ...@@ -715,7 +715,7 @@ class SyncMLSubscription(XMLObject):
if signature: if signature:
if len(data_diff) > MAX_LEN and not self.getIsActivityEnabled(): if len(data_diff) > MAX_LEN and not self.getIsActivityEnabled():
# XXX-Aurel : I do not think splitting is working when running in activity # XXX-Aurel : I do not think splitting is working when running in activity
syncml_logger.info("data for %s too big, splitting..." %(signature.getPath(),)) syncml_logger.info("data for %s too big, splitting...", signature.getPath())
more_data = True more_data = True
data_diff, rest_string = cutXML(data_diff, MAX_LEN) data_diff, rest_string = cutXML(data_diff, MAX_LEN)
# Store the remaining data to send it later # Store the remaining data to send it later
...@@ -727,7 +727,7 @@ class SyncMLSubscription(XMLObject): ...@@ -727,7 +727,7 @@ class SyncMLSubscription(XMLObject):
signature.setTemporaryData(document_data) signature.setTemporaryData(document_data)
# Generate the message # Generate the message
syncml_logger.info("adding sync command %s for %s" %(action, gid)) syncml_logger.info("adding sync command %s for %s", action, gid)
syncml_response.addSyncCommand( syncml_response.addSyncCommand(
sync_command=action, sync_command=action,
gid=gid, gid=gid,
...@@ -747,7 +747,7 @@ class SyncMLSubscription(XMLObject): ...@@ -747,7 +747,7 @@ class SyncMLSubscription(XMLObject):
min_gid = the lower limit for browsing data min_gid = the lower limit for browsing data
max_gid = the upper limit for browsing data max_gid = the upper limit for browsing data
""" """
syncml_logger.info("getSyncMLData, min %s - max %r" % (min_gid, max_gid,)) syncml_logger.info("getSyncMLData, min %s - max %r", min_gid, max_gid)
conduit = self.getConduit() conduit = self.getConduit()
portal = self.getPortalObject() portal = self.getPortalObject()
...@@ -762,7 +762,7 @@ class SyncMLSubscription(XMLObject): ...@@ -762,7 +762,7 @@ class SyncMLSubscription(XMLObject):
max_gid=max_gid, max_gid=max_gid,
path=self.getSearchableSourcePath()) path=self.getSearchableSourcePath())
syncml_logger.info("getSyncMLData, object list is %s" % ([x.path for x in object_list])) syncml_logger.info("getSyncMLData, object list is %s", [x.path for x in object_list])
alert_code = self.getSyncmlAlertCode() alert_code = self.getSyncmlAlertCode()
sync_all = alert_code in ("refresh_from_client_only", "slow_sync") sync_all = alert_code in ("refresh_from_client_only", "slow_sync")
...@@ -782,8 +782,8 @@ class SyncMLSubscription(XMLObject): ...@@ -782,8 +782,8 @@ class SyncMLSubscription(XMLObject):
document_data = result.data document_data = result.data
signature = self.getSignatureFromGid(gid) signature = self.getSignatureFromGid(gid)
if signature: if signature:
syncml_logger.info("signature is %s = %s" %(signature.getRelativeUrl(), syncml_logger.info("signature is %s = %s", signature.getRelativeUrl(),
signature.getValidationState())) signature.getValidationState())
if not document_data: if not document_data:
raise ValueError("No data for %s / %s" %(gid, document_path)) raise ValueError("No data for %s / %s" %(gid, document_path))
...@@ -799,8 +799,8 @@ class SyncMLSubscription(XMLObject): ...@@ -799,8 +799,8 @@ class SyncMLSubscription(XMLObject):
id=gid, id=gid,
reference=document_path, reference=document_path,
temporary_data=document_data) temporary_data=document_data)
syncml_logger.info("Created a signature %s for gid = %s, path %s" syncml_logger.info("Created a signature %s for gid = %s, path %s",
% (signature.getPath(), gid, document_path)) signature.getPath(), gid, document_path)
more_data = self._generateSyncCommand( more_data = self._generateSyncCommand(
action=ADD_ACTION, action=ADD_ACTION,
signature=signature, signature=signature,
...@@ -820,7 +820,7 @@ class SyncMLSubscription(XMLObject): ...@@ -820,7 +820,7 @@ class SyncMLSubscription(XMLObject):
# We need to convert XML to a CDATA type to prevent collision # We need to convert XML to a CDATA type to prevent collision
# with syncml's XML # with syncml's XML
document_data = etree.CDATA(xml_string.decode('utf-8')) document_data = etree.CDATA(xml_string.decode('utf-8'))
syncml_logger.info("adding partial sync command for %s" %(gid,)) syncml_logger.info("adding partial sync command for %s", gid)
syncml_response.addSyncCommand( syncml_response.addSyncCommand(
sync_command=signature.getPartialAction(), sync_command=signature.getPartialAction(),
gid=gid, gid=gid,
...@@ -829,8 +829,8 @@ class SyncMLSubscription(XMLObject): ...@@ -829,8 +829,8 @@ class SyncMLSubscription(XMLObject):
media_type=conduit.getContentType()) media_type=conduit.getContentType())
if not more_data: if not more_data:
syncml_logger.info("signature %s is syncing from partial" syncml_logger.info("signature %s is syncing from partial",
% (signature.getRelativeUrl(),)) signature.getRelativeUrl())
elif signature.getValidationState() in ('no_conflict', elif signature.getValidationState() in ('no_conflict',
'conflict_resolved_with_merge'): 'conflict_resolved_with_merge'):
...@@ -848,8 +848,8 @@ class SyncMLSubscription(XMLObject): ...@@ -848,8 +848,8 @@ class SyncMLSubscription(XMLObject):
sync_code='conflict_resolved_with_merge', sync_code='conflict_resolved_with_merge',
command='Replace') command='Replace')
syncml_logger.info("\tMD5 is %s for %s" %((signature.checkMD5(document_data)), syncml_logger.info("\tMD5 is %s for %s", signature.checkMD5(document_data),
signature.getReference())) signature.getReference())
if not signature.checkMD5(document_data): if not signature.checkMD5(document_data):
# MD5 checksum tell there is a modification of the object # MD5 checksum tell there is a modification of the object
# XXX this diff generation must managed by the conduit # XXX this diff generation must managed by the conduit
...@@ -868,12 +868,12 @@ class SyncMLSubscription(XMLObject): ...@@ -868,12 +868,12 @@ class SyncMLSubscription(XMLObject):
# MD5 Checksum can detect changes like <lang/> != <lang></lang> # MD5 Checksum can detect changes like <lang/> != <lang></lang>
# but Diff generator will return no diff for it # but Diff generator will return no diff for it
# in this case, no need to send diff # in this case, no need to send diff
syncml_logger.info("\tFake diff, signature %s is synchronized" syncml_logger.info("\tFake diff, signature %s is synchronized",
% (signature.getRelativeUrl(),)) signature.getRelativeUrl())
continue continue
# Reindex modified document # Reindex modified document
syncml_logger.info("\tGot a diff for %s : %s" %(gid, data_diff)) syncml_logger.info("\tGot a diff for %s : %s", gid, data_diff)
more_data = self._generateSyncCommand( more_data = self._generateSyncCommand(
action=REPLACE_ACTION, action=REPLACE_ACTION,
signature=signature, signature=signature,
...@@ -903,15 +903,15 @@ class SyncMLSubscription(XMLObject): ...@@ -903,15 +903,15 @@ class SyncMLSubscription(XMLObject):
sync_code='conflict_resolved_with_client_command_winning', sync_code='conflict_resolved_with_client_command_winning',
command='Replace') command='Replace')
signature.synchronize() signature.synchronize()
syncml_logger.debug("signature %s is synchronized" syncml_logger.debug("signature %s is synchronized",
% (signature.getRelativeUrl(),)) signature.getRelativeUrl())
if more_data: if more_data:
syncml_logger.info("Splitting document") syncml_logger.info("Splitting document")
break break
syncml_logger.info("_getSyncMLData end with more_data %s" syncml_logger.info("_getSyncMLData end with more_data %s",
% (more_data,)) more_data)
return not more_data return not more_data
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
...@@ -961,7 +961,7 @@ class SyncMLSubscription(XMLObject): ...@@ -961,7 +961,7 @@ class SyncMLSubscription(XMLObject):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getGidFromObject') 'getGidFromObject')
def getGidFromObject(self, object, encoded=True): def getGidFromObject(self, object, encoded=True): # pylint: disable=redefined-builtin
""" """
Returns the object gid Returns the object gid
""" """
...@@ -1094,7 +1094,7 @@ class SyncMLSubscription(XMLObject): ...@@ -1094,7 +1094,7 @@ class SyncMLSubscription(XMLObject):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getSignatureFromObjectId') 'getSignatureFromObjectId')
def getSignatureFromObjectId(self, id): def getSignatureFromObjectId(self, id): # pylint: disable=redefined-builtin
""" """
return the signature corresponding to the id return the signature corresponding to the id
### Use a reverse dictionary will be usefull ### Use a reverse dictionary will be usefull
...@@ -1106,7 +1106,7 @@ class SyncMLSubscription(XMLObject): ...@@ -1106,7 +1106,7 @@ class SyncMLSubscription(XMLObject):
if document is not None: if document is not None:
if id == document.getId(): if id == document.getId():
return signature return signature
else: # XXX-Aurel : maybe none is expected else: # XXX-Aurel : maybe none is expected # pylint: disable=useless-else-on-loop
raise KeyError, id raise KeyError, id
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
...@@ -1203,7 +1203,7 @@ class SyncMLSubscription(XMLObject): ...@@ -1203,7 +1203,7 @@ class SyncMLSubscription(XMLObject):
) )
else: else:
r = [x.getPath() for x in self.getDocumentList()] r = [x.getPath() for x in self.getDocumentList()]
syncml_logger.info("indexing data from %s : %r" %(self.getPath(), r)) syncml_logger.info("indexing data from %s : %r", self.getPath(), r)
portal.SQLCatalog_indexSyncMLDocumentList( portal.SQLCatalog_indexSyncMLDocumentList(
path_list=r[:], path_list=r[:],
subscription_path=self.getRelativeUrl()) subscription_path=self.getRelativeUrl())
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLSubscription</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Document.SyncMLSubscription</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.SyncMLSubscription</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -67,7 +67,7 @@ class IConduit(Interface): ...@@ -67,7 +67,7 @@ class IConduit(Interface):
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
""" """
def constructContent(object, object_id, portal_type): def constructContent(object, object_id, portal_type): # pylint: disable=redefined-builtin
""" """
This allows to specify how to construct a new content. This allows to specify how to construct a new content.
This is really usefull if you want to write your This is really usefull if you want to write your
...@@ -82,7 +82,7 @@ class IConduit(Interface): ...@@ -82,7 +82,7 @@ class IConduit(Interface):
return newObject, reset_local_roles boolean, reset_workflow boolean return newObject, reset_local_roles boolean, reset_workflow boolean
""" """
def addNode(xml=None, object=None, previous_xml=None, def addNode(xml=None, object=None, previous_xml=None, # pylint: disable=redefined-builtin
object_id=None, sub_object=None, force=0, simulate=0, **kw): object_id=None, sub_object=None, force=0, simulate=0, **kw):
""" """
A node is added A node is added
...@@ -100,13 +100,13 @@ class IConduit(Interface): ...@@ -100,13 +100,13 @@ class IConduit(Interface):
[object.getPath(),keyword,local_and_actual_value,subscriber_value] [object.getPath(),keyword,local_and_actual_value,subscriber_value]
""" """
def deleteNode(xml=None, object=None, object_id=None, force=None, def deleteNode(xml=None, object=None, object_id=None, force=None, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
""" """
A node is deleted A node is deleted
""" """
def updateNode(xml=None, object=None, previous_xml=None, force=0, def updateNode(xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
""" """
A node is updated with some xupdate A node is updated with some xupdate
...@@ -117,7 +117,7 @@ class IConduit(Interface): ...@@ -117,7 +117,7 @@ class IConduit(Interface):
""" """
def getGidFromObject(object, configurable_gid_dictionary=None): def getGidFromObject(object, configurable_gid_dictionary=None): # pylint: disable=redefined-builtin
""" """
return the Gid composed with the object information return the Gid composed with the object information
- object is the document on which for we are building the gid. - object is the document on which for we are building the gid.
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Interface Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>IConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.interfaces.conduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>interface.erp5.IConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Interface Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -31,15 +31,15 @@ from AccessControl import ClassSecurityInfo, getSecurityManager ...@@ -31,15 +31,15 @@ from AccessControl import ClassSecurityInfo, getSecurityManager
from Products.PluggableAuthService.interfaces.plugins import \ from Products.PluggableAuthService.interfaces.plugins import \
IAuthenticationPlugin IAuthenticationPlugin
from Products.ERP5SyncML.XMLSyncUtils import resolveSyncmlStatusCode, decode from erp5.component.module.XMLSyncUtils import resolveSyncmlStatusCode, decode
from Products.ERP5SyncML.SyncMLMessage import SyncMLResponse from erp5.component.module.SyncMLMessage import SyncMLResponse
from Products.ERP5SyncML.SyncMLConstant import NULL_ANCHOR, ACTIVITY_PRIORITY, \ from erp5.component.module.SyncMLConstant import NULL_ANCHOR, ACTIVITY_PRIORITY, \
SynchronizationError SynchronizationError
syncml_logger = getLogger('ERP5SyncML') syncml_logger = getLogger('ERP5SyncML')
class EngineMixin(object): class SyncMLEngineMixin(object):
""" """
Mixin class that holds generci methods used by engines Mixin class that holds generci methods used by engines
""" """
...@@ -75,9 +75,11 @@ class EngineMixin(object): ...@@ -75,9 +75,11 @@ class EngineMixin(object):
status['authentication_type'])) status['authentication_type']))
# XXX Not working To Review ! # XXX Not working To Review !
raise NotImplementedError("Adding credentials") raise NotImplementedError("Adding credentials")
"""
syncml_response = domain.generateBaseResponse() syncml_response = domain.generateBaseResponse()
syncml_response.addCredentialMessage(domain) syncml_response.addCredentialMessage(domain)
return syncml_response return syncml_response
"""
elif status['status_code'] == \ elif status['status_code'] == \
resolveSyncmlStatusCode('invalid_credentials'): resolveSyncmlStatusCode('invalid_credentials'):
syncml_logger.error("\tClient authentication refused") syncml_logger.error("\tClient authentication refused")
...@@ -92,8 +94,8 @@ class EngineMixin(object): ...@@ -92,8 +94,8 @@ class EngineMixin(object):
# XXX Must check status for asked synchrozation # XXX Must check status for asked synchrozation
# and must be done for command, not for # and must be done for command, not for
# For now do nothing = say it is always OK # For now do nothing = say it is always OK
syncml_logger.info("\tChecking database, will generate alert %s" syncml_logger.info("\tChecking database, will generate alert %s",
% (generate_alert)) generate_alert)
elif status["command"] in ('Add', 'Replace'): elif status["command"] in ('Add', 'Replace'):
sync_status_counter += 1 sync_status_counter += 1
object_gid = status['source'] or status['target'] object_gid = status['source'] or status['target']
...@@ -110,27 +112,27 @@ class EngineMixin(object): ...@@ -110,27 +112,27 @@ class EngineMixin(object):
% (domain.getPath(), object_gid)) % (domain.getPath(), object_gid))
if status['status_code'] == resolveSyncmlStatusCode('conflict'): if status['status_code'] == resolveSyncmlStatusCode('conflict'):
signature.changeToConflict() signature.changeToConflict()
syncml_logger.error("\tObject in conflict %s" % syncml_logger.error("\tObject in conflict %s",
(status['source'] or status['target'])) status['source'] or status['target'])
elif status['status_code'] == resolveSyncmlStatusCode( elif status['status_code'] == resolveSyncmlStatusCode(
'conflict_resolved_with_merge'): 'conflict_resolved_with_merge'):
# We will have to apply the update, and we should not care # We will have to apply the update, and we should not care
# about conflicts, so we have to force the update # about conflicts, so we have to force the update
signature.noConflict() signature.noConflict()
signature.setForce(True) signature.setForce(True)
syncml_logger.error("\tObject merged %s" % syncml_logger.error("\tObject merged %s",
(status['source'] or status['target'])) status['source'] or status['target'])
elif status['status_code'] in (resolveSyncmlStatusCode('success'), elif status['status_code'] in (resolveSyncmlStatusCode('success'),
resolveSyncmlStatusCode('item_added'), resolveSyncmlStatusCode('item_added'),
resolveSyncmlStatusCode( resolveSyncmlStatusCode(
'conflict_resolved_with_client_command_winning')): 'conflict_resolved_with_client_command_winning')):
syncml_logger.error("\tObject synchronized %s" % syncml_logger.error("\tObject synchronized %s",
(status['source'] or status['target'],)) status['source'] or status['target'])
if signature.getValidationState() != "no_conflict": if signature.getValidationState() != "no_conflict":
signature.noConflict() signature.noConflict()
signature.synchronize() signature.synchronize()
elif status['status_code'] == resolveSyncmlStatusCode('chunk_accepted'): elif status['status_code'] == resolveSyncmlStatusCode('chunk_accepted'):
syncml_logger.info("Chunk was accepted for %s" % (object_gid,)) syncml_logger.info("Chunk was accepted for %s", object_gid)
else: else:
raise ValueError("Unknown status code : %r" % (status['status_code'],)) raise ValueError("Unknown status code : %r" % (status['status_code'],))
# Index signature now to fill the data column # Index signature now to fill the data column
...@@ -147,8 +149,8 @@ class EngineMixin(object): ...@@ -147,8 +149,8 @@ class EngineMixin(object):
raise ValueError("Found no signature to delete for gid %s" %(object_gid,)) raise ValueError("Found no signature to delete for gid %s" %(object_gid,))
else: else:
raise ValueError("Unknown status code : %r" % (status['status_code'],)) raise ValueError("Unknown status code : %r" % (status['status_code'],))
syncml_logger.error("\tObject deleted %s" % syncml_logger.error("\tObject deleted %s",
(status['source'] or status['target'])) status['source'] or status['target'])
else: else:
raise ValueError("Unknown status command : %r" % (status['command'],)) raise ValueError("Unknown status command : %r" % (status['command'],))
...@@ -174,8 +176,8 @@ class EngineMixin(object): ...@@ -174,8 +176,8 @@ class EngineMixin(object):
done here but can be a way of improvement to decrease number of messages done here but can be a way of improvement to decrease number of messages
exchanged. exchanged.
""" """
syncml_logger.info('--- Starting synchronization on client side : %s ---' syncml_logger.info('--- Starting synchronization on client side : %s ---',
% (subscription.getPath(),)) subscription.getPath())
if not subscription.getSynchronizationState() == "initializing": if not subscription.getSynchronizationState() == "initializing":
# This can be called many time in sync init when credentials failed # This can be called many time in sync init when credentials failed
subscription.initialize() # Worflow action subscription.initialize() # Worflow action
...@@ -309,8 +311,8 @@ class EngineMixin(object): ...@@ -309,8 +311,8 @@ class EngineMixin(object):
% syncml_request.alert['data']) % syncml_request.alert['data'])
syncml_logger.info('--- Starting synchronization on server side : %s in mode %s ---' syncml_logger.info('--- Starting synchronization on server side : %s in mode %s ---',
% (publication.getPath(), alert_dict["data"])) publication.getPath(), alert_dict["data"])
# at the begining of the synchronization the subscriber is not authenticated # at the begining of the synchronization the subscriber is not authenticated
if subscriber.getAuthenticationState() == 'logged_in': if subscriber.getAuthenticationState() == 'logged_in':
subscriber.logout() subscriber.logout()
...@@ -339,13 +341,13 @@ class EngineMixin(object): ...@@ -339,13 +341,13 @@ class EngineMixin(object):
login, password = decoded.split(':') login, password = decoded.split(':')
# TODO: make it work for users existing anywhere # TODO: make it work for users existing anywhere
user_folder = publication.getPortalObject().acl_users user_folder = publication.getPortalObject().acl_users
for plugin_name, plugin in user_folder._getOb('plugins')\ for _, plugin in user_folder._getOb('plugins')\
.listPlugins(IAuthenticationPlugin): .listPlugins(IAuthenticationPlugin):
if plugin.authenticateCredentials( if plugin.authenticateCredentials(
{'login': login, 'password': password}) is not None: {'login': login, 'password': password}) is not None:
subscriber.login() subscriber.login()
syncml_logger.info("\tServer accepted authentication for user %s" syncml_logger.info("\tServer accepted authentication for user %s",
% (login,)) login)
authentication_code = 'authentication_accepted' authentication_code = 'authentication_accepted'
subscriber._loginUser(login) subscriber._loginUser(login)
subscriber._edit(authenticated_user=login) subscriber._edit(authenticated_user=login)
...@@ -356,21 +358,21 @@ class EngineMixin(object): ...@@ -356,21 +358,21 @@ class EngineMixin(object):
# authentication_code = 'missing_credentials' # authentication_code = 'missing_credentials'
# else: # else:
authentication_code = 'invalid_credentials' authentication_code = 'invalid_credentials'
syncml_logger.error("\tServer rejected authentication for %s" % (login)) syncml_logger.error("\tServer rejected authentication for %s", login)
else: else:
# if header_kw["message_id"] == 1: # if header_kw["message_id"] == 1:
# authentication_code = 'missing_credentials' # authentication_code = 'missing_credentials'
# else: # else:
authentication_code = 'invalid_credentials' authentication_code = 'invalid_credentials'
syncml_logger.warning( syncml_logger.warning(
"\tCredentials does not look like auth-basis, decoded value is '%s,'" "\tCredentials does not look like auth-basis, decoded value is '%s,'",
% (decoded)) decoded)
else: else:
# To complete, must send a challenge message # To complete, must send a challenge message
syncml_logger.warning( syncml_logger.warning(
"\tAuthentication type does not math, from client '%s', from server '%s'" %( "\tAuthentication type does not math, from client '%s', from server '%s'",
syncml_request.credentials['type'], syncml_request.credentials['type'],
publication.getAuthenticationType())) publication.getAuthenticationType())
authentication_code = 'missing_credentials' authentication_code = 'missing_credentials'
...@@ -397,9 +399,9 @@ class EngineMixin(object): ...@@ -397,9 +399,9 @@ class EngineMixin(object):
elif subscriber.getNextAnchor() != alert_dict['last_anchor']: elif subscriber.getNextAnchor() != alert_dict['last_anchor']:
# Anchor does not match, must start a slow sync # Anchor does not match, must start a slow sync
syncml_logger.warning("\tAnchor does not match on server, \ syncml_logger.warning("\tAnchor does not match on server, \
received is %s, stored %s. Will start a slow sync" received is %s, stored %s. Will start a slow sync",
%(alert_dict['last_anchor'], alert_dict['last_anchor'],
subscriber.getNextAnchor())) subscriber.getNextAnchor())
sync_type_validation_code = "command_failed" # Error 500 sync_type_validation_code = "command_failed" # Error 500
sync_type = 'slow_sync' sync_type = 'slow_sync'
else: else:
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Mixin Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLEngineMixin</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Engine.EngineMixin</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>mixin.erp5.SyncMLEngineMixin</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Mixin Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -42,7 +42,7 @@ class BaseConduit(object): ...@@ -42,7 +42,7 @@ class BaseConduit(object):
def generateDiff(self, new_data, former_data): def generateDiff(self, new_data, former_data):
return None return None
def getXMLFromObjectWithId(self, object, xml_mapping, context_document=None): def getXMLFromObjectWithId(self, object, xml_mapping, context_document=None): # pylint: disable=redefined-builtin
""" """
return the xml with Id of Object return the xml with Id of Object
""" """
...@@ -60,7 +60,7 @@ class BaseConduit(object): ...@@ -60,7 +60,7 @@ class BaseConduit(object):
return data return data
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
return the Gid composed with the object informations return the Gid composed with the object informations
""" """
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>BaseConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Conduit.BaseConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.BaseConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,15 +27,15 @@ ...@@ -27,15 +27,15 @@
# #
############################################################################## ##############################################################################
from Products.ERP5SyncML.XMLSyncUtils import XMLSyncUtilsMixin from erp5.component.module.XMLSyncUtils import XMLSyncUtilsMixin
from Products.ERP5SyncML.XMLSyncUtils import getXupdateObject from erp5.component.module.XMLSyncUtils import getXupdateObject
from Products.ERP5Type.Utils import deprecated from Products.ERP5Type.Utils import deprecated
from Products.ERP5Type.XMLExportImport import MARSHALLER_NAMESPACE_URI from Products.ERP5Type.XMLExportImport import MARSHALLER_NAMESPACE_URI
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from Products.ERP5Type.Base import WorkflowMethod from Products.ERP5Type.Base import WorkflowMethod
from DateTime.DateTime import DateTime from DateTime.DateTime import DateTime
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions, interfaces from Products.ERP5Type import Permissions
from Products.ERP5Type.Globals import PersistentMapping from Products.ERP5Type.Globals import PersistentMapping
from xml.sax.saxutils import unescape from xml.sax.saxutils import unescape
...@@ -54,8 +54,9 @@ syncml_logger = logging.getLogger('ERP5SyncML') ...@@ -54,8 +54,9 @@ syncml_logger = logging.getLogger('ERP5SyncML')
from hashlib import sha1 from hashlib import sha1
from Products.ERP5SyncML.SyncMLConstant import XUPDATE_ELEMENT,\ from erp5.component.module.SyncMLConstant import XUPDATE_ELEMENT,\
XUPDATE_INSERT_OR_ADD_LIST, XUPDATE_DEL, XUPDATE_UPDATE, XUPDATE_INSERT_LIST XUPDATE_INSERT_OR_ADD_LIST, XUPDATE_DEL, XUPDATE_UPDATE, XUPDATE_INSERT_LIST
from erp5.component.interface.IConduit import IConduit
# Constant # Constant
HISTORY_TAG = 'workflow_action' HISTORY_TAG = 'workflow_action'
XML_OBJECT_TAG = 'object' XML_OBJECT_TAG = 'object'
...@@ -80,11 +81,11 @@ INT_TYPE = 'int' ...@@ -80,11 +81,11 @@ INT_TYPE = 'int'
DATA_TYPE_LIST = ('data', 'object',) DATA_TYPE_LIST = ('data', 'object',)
BOOLEAN_TYPE = 'boolean' BOOLEAN_TYPE = 'boolean'
HISTORY_EXP = re.compile("/%s\[@id='.*'\]" % HISTORY_TAG) HISTORY_EXP = re.compile(r"/%s\[@id='.*'\]" % HISTORY_TAG)
BAD_HISTORY_EXP = re.compile("/%s\[@id='.*'\]/" % HISTORY_TAG) BAD_HISTORY_EXP = re.compile(r"/%s\[@id='.*'\]/" % HISTORY_TAG)
EXTRACT_ID_FROM_XPATH = re.compile( EXTRACT_ID_FROM_XPATH = re.compile(
"(?P<object_block>(?P<property>[^/]+)\[@"\ r"(?P<object_block>(?P<property>[^/]+)\[@"\
"(?P<id_of_id>id|gid)='(?P<object_id>[^']+)'\])") r"(?P<id_of_id>id|gid)='(?P<object_id>[^']+)'\])")
WORKFLOW_ACTION_NOT_ADDABLE = 0 WORKFLOW_ACTION_NOT_ADDABLE = 0
WORKFLOW_ACTION_ADDABLE = 1 WORKFLOW_ACTION_ADDABLE = 1
...@@ -128,7 +129,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -128,7 +129,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
# Declarative interfaces # Declarative interfaces
implements( interfaces.IConduit, ) implements( IConduit, )
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
...@@ -146,7 +147,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -146,7 +147,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
#self.args = {} #self.args = {}
security.declareProtected(Permissions.ModifyPortalContent, 'addNode') security.declareProtected(Permissions.ModifyPortalContent, 'addNode')
def addNode(self, xml=None, object=None, sub_object=None, reset=None, def addNode(self, xml=None, object=None, sub_object=None, reset=None, # pylint: disable=redefined-builtin
simulate=None, **kw): simulate=None, **kw):
""" """
A node is added A node is added
...@@ -203,7 +204,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -203,7 +204,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return {'conflict_list':conflict_list, 'object': sub_object} return {'conflict_list':conflict_list, 'object': sub_object}
security.declareProtected(Permissions.ModifyPortalContent, 'deleteNode') security.declareProtected(Permissions.ModifyPortalContent, 'deleteNode')
def deleteNode(self, xml=None, object=None, object_id=None, **kw): def deleteNode(self, xml=None, object=None, object_id=None, **kw): # pylint: disable=redefined-builtin
""" """
This method manage the deletion of a node as well as the deletion This method manage the deletion of a node as well as the deletion
of one property of one property
...@@ -257,7 +258,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -257,7 +258,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return [] return []
security.declareProtected(Permissions.ModifyPortalContent, 'deleteObject') security.declareProtected(Permissions.ModifyPortalContent, 'deleteObject')
def deleteObject(self, object, object_id, **kw): def deleteObject(self, object, object_id, **kw): # pylint: disable=redefined-builtin
try: try:
object._delObject(object_id) object._delObject(object_id)
except (AttributeError, KeyError): except (AttributeError, KeyError):
...@@ -265,7 +266,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -265,7 +266,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
pass pass
security.declareProtected(Permissions.ModifyPortalContent, 'updateNode') security.declareProtected(Permissions.ModifyPortalContent, 'updateNode')
def updateNode(self, xml=None, object=None, previous_xml=None, force=False, def updateNode(self, xml=None, object=None, previous_xml=None, force=False, # pylint: disable=redefined-builtin
simulate=False, reset=False, xpath_expression=None, **kw): simulate=False, reset=False, xpath_expression=None, **kw):
""" """
A node is updated with some xupdate A node is updated with some xupdate
...@@ -278,8 +279,8 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -278,8 +279,8 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if xml is None: if xml is None:
return [] return []
xml = self.convertToXml(xml) xml = self.convertToXml(xml)
syncml_logger.debug("updateNode with xml %s" syncml_logger.debug("updateNode with xml %s",
% (etree.tostring(xml, pretty_print=True))) etree.tostring(xml, pretty_print=True))
if xml.tag == '{%s}modifications' % xml.nsmap.get('xupdate'): if xml.tag == '{%s}modifications' % xml.nsmap.get('xupdate'):
conflict_list += self.applyXupdate(object=object, conflict_list += self.applyXupdate(object=object,
xupdate=xml, xupdate=xml,
...@@ -371,21 +372,21 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -371,21 +372,21 @@ class ERP5Conduit(XMLSyncUtilsMixin):
if data_type not in DATA_TYPE_LIST: if data_type not in DATA_TYPE_LIST:
conflict.edit(local_value=current_data, conflict.edit(local_value=current_data,
remote_value=data) remote_value=data)
syncml_logger.info("Generated a conflict for %s" % (keyword,)) syncml_logger.info("Generated a conflict for %s", keyword)
conflict_list += [conflict] conflict_list += [conflict]
else: else:
syncml_logger.info("UpdateNode : no previous xml founds or force") syncml_logger.info("UpdateNode : no previous xml founds or force")
# We will now apply the argument with the method edit # We will now apply the argument with the method edit
if args and (not isConflict or force) and (not simulate or reset): if args and (not isConflict or force) and (not simulate or reset):
syncml_logger.info("calling updateContent : %s" % (args)) syncml_logger.info("calling updateContent : %s", args)
self._updateContent(object=context, **args) self._updateContent(object=context, **args)
# It is sometimes required to do something after an edit # It is sometimes required to do something after an edit
if getattr(context, 'manage_afterEdit', None) is not None: if getattr(context, 'manage_afterEdit', None) is not None:
context.manage_afterEdit() context.manage_afterEdit()
else: else:
syncml_logger.warning("did not call updateContent on %s" % (context)) syncml_logger.warning("did not call updateContent on %s", context)
else: else:
syncml_logger.info("UpdateNode : not editable property %s" % (keyword)) syncml_logger.info("UpdateNode : not editable property %s", keyword)
# Specific cases of update # Specific cases of update
if keyword == 'object': if keyword == 'object':
...@@ -411,7 +412,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -411,7 +412,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
force=force, simulate=simulate, force=force, simulate=simulate,
reset=reset, **kw)['conflict_list'] reset=reset, **kw)['conflict_list']
else: else:
syncml_logger.warning("UpdateNode : not a property %s" % (etree.tostring(xml, pretty_print=True),)) syncml_logger.warning("UpdateNode : not a property %s", etree.tostring(xml, pretty_print=True))
return conflict_list return conflict_list
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
...@@ -575,7 +576,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -575,7 +576,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getXMLFromObjectWithId') 'getXMLFromObjectWithId')
def getXMLFromObjectWithId(self, object, xml_mapping, context_document=None): def getXMLFromObjectWithId(self, object, xml_mapping, context_document=None): # pylint: disable=redefined-builtin
""" """
return the xml with Id of Object return the xml with Id of Object
""" """
...@@ -593,7 +594,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -593,7 +594,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getXMLFromObjectWithGid') 'getXMLFromObjectWithGid')
def getXMLFromObjectWithGid(self, object, gid, xml_mapping, as_string=True, context_document=None): def getXMLFromObjectWithGid(self, object, gid, xml_mapping, as_string=True, context_document=None): # pylint: disable=redefined-builtin
""" """
return the xml with Gid of Object return the xml with Gid of Object
""" """
...@@ -603,7 +604,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -603,7 +604,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getXMLFromObjectWithRid') 'getXMLFromObjectWithRid')
def getXMLFromObjectWithRid(self, object, rid, xml_mapping, as_string=True, context_document=None): def getXMLFromObjectWithRid(self, object, rid, xml_mapping, as_string=True, context_document=None): # pylint: disable=redefined-builtin
""" """
return the xml with Rid of Object return the xml with Rid of Object
""" """
...@@ -643,7 +644,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -643,7 +644,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return xml.get('type') return xml.get('type')
security.declareProtected(Permissions.ModifyPortalContent, 'newObject') security.declareProtected(Permissions.ModifyPortalContent, 'newObject')
def newObject(self, object=None, xml=None, simulate=False, def newObject(self, object=None, xml=None, simulate=False, # pylint: disable=redefined-builtin
reset_local_roles=True, reset_workflow=True): reset_local_roles=True, reset_workflow=True):
""" """
modify the object with datas from modify the object with datas from
...@@ -681,7 +682,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -681,7 +682,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'afterNewObject') 'afterNewObject')
def afterNewObject(self, object): def afterNewObject(self, object): # pylint: disable=redefined-builtin
"""Overloadable method """Overloadable method
""" """
pass pass
...@@ -730,15 +731,15 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -730,15 +731,15 @@ class ERP5Conduit(XMLSyncUtilsMixin):
select_id = select_id[:select_id.find("'",1)+1] select_id = select_id[:select_id.find("'",1)+1]
else: else:
s_place = len(attribute) s_place = len(attribute)
property = attribute[:s_place].strip('/') property_ = attribute[:s_place].strip('/')
result += property result += property_
if select_id is not None: if select_id is not None:
result += ' id=%s' % select_id result += ' id=%s' % select_id
result += '>' result += '>'
xml_string = self.nodeToString(xml) xml_string = self.nodeToString(xml)
maxi = xml_string.find('>')+1 maxi = xml_string.find('>')+1
result += xml_string[maxi:xml_string.find('</%s>' % xml.xpath('name()'))] result += xml_string[maxi:xml_string.find('</%s>' % xml.xpath('name()'))]
result += '</%s>' % (property) result += '</%s>' % (property_)
#LOG('getElementFromXupdate, result:',0,repr(result)) #LOG('getElementFromXupdate, result:',0,repr(result))
return self.convertToXml(result) return self.convertToXml(result)
return xml return xml
...@@ -800,7 +801,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -800,7 +801,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
security.declareProtected(Permissions.ModifyPortalContent, 'applyXupdate') security.declareProtected(Permissions.ModifyPortalContent, 'applyXupdate')
def applyXupdate(self, object=None, xupdate=None, previous_xml=None, **kw): def applyXupdate(self, object=None, xupdate=None, previous_xml=None, **kw): # pylint: disable=redefined-builtin
""" """
Parse the xupdate and then it will call the conduit Parse the xupdate and then it will call the conduit
""" """
...@@ -918,7 +919,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -918,7 +919,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return addable return addable
security.declareProtected(Permissions.ModifyPortalContent, 'constructContent') security.declareProtected(Permissions.ModifyPortalContent, 'constructContent')
def constructContent(self, object, object_id, portal_type): def constructContent(self, object, object_id, portal_type): # pylint: disable=redefined-builtin
""" """
This allows to specify how to construct a new content. This allows to specify how to construct a new content.
This is really usefull if you want to write your This is really usefull if you want to write your
...@@ -930,7 +931,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -930,7 +931,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return subobject, True, True return subobject, True, True
security.declareProtected(Permissions.ModifyPortalContent, 'addWorkflowNode') security.declareProtected(Permissions.ModifyPortalContent, 'addWorkflowNode')
def addWorkflowNode(self, object, xml, simulate): def addWorkflowNode(self, object, xml, simulate): # pylint: disable=redefined-builtin
""" """
This allows to specify how to handle the workflow information. This allows to specify how to handle the workflow information.
This is really usefull if you want to write your own Conduit. This is really usefull if you want to write your own Conduit.
...@@ -963,7 +964,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -963,7 +964,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
return conflict_list return conflict_list
security.declareProtected(Permissions.ModifyPortalContent, 'addLocalRoleNode') security.declareProtected(Permissions.ModifyPortalContent, 'addLocalRoleNode')
def addLocalRoleNode(self, object, xml): def addLocalRoleNode(self, object, xml): # pylint: disable=redefined-builtin
""" """
This allows to specify how to handle the local role information. This allows to specify how to handle the local role information.
This is really usefull if you want to write your own Conduit. This is really usefull if you want to write your own Conduit.
...@@ -981,7 +982,7 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -981,7 +982,7 @@ class ERP5Conduit(XMLSyncUtilsMixin):
object.manage_setLocalGroupRoles(user, roles) object.manage_setLocalGroupRoles(user, roles)
security.declareProtected(Permissions.ModifyPortalContent, 'addLocalPermissionNode') security.declareProtected(Permissions.ModifyPortalContent, 'addLocalPermissionNode')
def addLocalPermissionNode(self, object, xml): def addLocalPermissionNode(self, object, xml): # pylint: disable=redefined-builtin
""" """
This allows to specify how to handle the local permision informations. This allows to specify how to handle the local permision informations.
This is really usefull if you want to write your own Conduit. This is really usefull if you want to write your own Conduit.
...@@ -1008,16 +1009,16 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1008,16 +1009,16 @@ class ERP5Conduit(XMLSyncUtilsMixin):
# example document_conversion_interaction_workflow defined for _setData()) # example document_conversion_interaction_workflow defined for _setData())
# making the source and destination XML representation different. # making the source and destination XML representation different.
@WorkflowMethod.disable @WorkflowMethod.disable
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the default editDocument method. This method This is the default editDocument method. This method
can easily be overwritten. can easily be overwritten.
""" """
syncml_logger.debug("editing document %s with %s" % (object, kw)) syncml_logger.debug("editing document %s with %s", object, kw)
object._edit(**kw) object._edit(**kw)
security.declareProtected(Permissions.ModifyPortalContent, 'getProperty') security.declareProtected(Permissions.ModifyPortalContent, 'getProperty')
def getProperty(self, object, kw): def getProperty(self, object, kw): # pylint: disable=redefined-builtin
""" """
This is the default getProperty method. This method This is the default getProperty method. This method
can easily be overwritten. can easily be overwritten.
...@@ -1030,13 +1031,13 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1030,13 +1031,13 @@ class ERP5Conduit(XMLSyncUtilsMixin):
""" """
return etree.tostring(node, encoding='utf-8', pretty_print=True) return etree.tostring(node, encoding='utf-8', pretty_print=True)
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
return the Gid composed with the object informations return the Gid composed with the object informations
""" """
return object.getId() return object.getId()
def _createContent(self, xml=None, object=None, object_id=None, def _createContent(self, xml=None, object=None, object_id=None, # pylint: disable=redefined-builtin
sub_object=None, reset_local_roles=False, sub_object=None, reset_local_roles=False,
reset_workflow=False, simulate=False, **kw): reset_workflow=False, simulate=False, **kw):
""" """
...@@ -1066,13 +1067,13 @@ class ERP5Conduit(XMLSyncUtilsMixin): ...@@ -1066,13 +1067,13 @@ class ERP5Conduit(XMLSyncUtilsMixin):
reset_workflow=reset_workflow) reset_workflow=reset_workflow)
return sub_object return sub_object
def _updateContent(self, object=None, **args): def _updateContent(self, object=None, **args): # pylint: disable=redefined-builtin
""" """
This is the method for update the object This is the method for update the object
""" """
return self.editDocument(object=object, **args) return self.editDocument(object=object, **args)
def _deleteContent(self, object=None, object_id=None, **kw): def _deleteContent(self, object=None, object_id=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the method for delete the object This is the method for delete the object
""" """
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5Conduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Conduit.ERP5Conduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5Conduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -29,7 +29,7 @@ ...@@ -29,7 +29,7 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.ERP5Conduit import ERP5Conduit
class ERP5ConduitTitleGid(ERP5Conduit): class ERP5ConduitTitleGid(ERP5Conduit):
...@@ -42,7 +42,7 @@ class ERP5ConduitTitleGid(ERP5Conduit): ...@@ -42,7 +42,7 @@ class ERP5ConduitTitleGid(ERP5Conduit):
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
return the Gid composed of FirstName and LastName generate with the object return the Gid composed of FirstName and LastName generate with the object
""" """
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5ConduitTitleGid</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Conduit.ERP5ConduitTitleGid</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5ConduitTitleGid</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.ERP5Conduit import ERP5Conduit
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
...@@ -49,7 +49,7 @@ class ERP5DocumentConduit(ERP5Conduit): ...@@ -49,7 +49,7 @@ class ERP5DocumentConduit(ERP5Conduit):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareProtected(Permissions.AccessContentsInformation, 'getGidFromObject') security.declareProtected(Permissions.AccessContentsInformation, 'getGidFromObject')
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
return the Gid generate with the reference, object, language of the object return the Gid generate with the reference, object, language of the object
""" """
...@@ -70,7 +70,6 @@ class ERP5DocumentConduit(ERP5Conduit): ...@@ -70,7 +70,6 @@ class ERP5DocumentConduit(ERP5Conduit):
else: else:
return WORKFLOW_ACTION_ADDABLE return WORKFLOW_ACTION_ADDABLE
addable = WORKFLOW_ACTION_ADDABLE addable = WORKFLOW_ACTION_ADDABLE
time = status.get('time')
for action in action_list: for action in action_list:
this_one = WORKFLOW_ACTION_ADDABLE this_one = WORKFLOW_ACTION_ADDABLE
# if time <= action.get('time'): # if time <= action.get('time'):
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5DocumentConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Conduit.ERP5DocumentConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5DocumentConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -34,7 +34,7 @@ from cStringIO import StringIO ...@@ -34,7 +34,7 @@ from cStringIO import StringIO
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from zLOG import LOG from zLOG import LOG
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.ERP5Conduit import ERP5Conduit
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
...@@ -53,12 +53,11 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -53,12 +53,11 @@ class ERP5ShopOrderConduit(ERP5Conduit):
random.seed() random.seed()
security.declareProtected(Permissions.ModifyPortalContent, 'constructContent') security.declareProtected(Permissions.ModifyPortalContent, 'constructContent')
def constructContent(self, object, object_id, docid, portal_type): def constructContent(self, object, object_id, docid, portal_type): # pylint: disable=redefined-builtin,arguments-differ
""" """
This is a redefinition of the original ERP5Conduit.constructContent function to This is a redefinition of the original ERP5Conduit.constructContent function to
allow the creation of a ERP5 Sale Order instead of a Storever Shop Order. allow the creation of a ERP5 Sale Order instead of a Storever Shop Order.
""" """
portal_types = getToolByName(object, 'portal_types')
subobject = None subobject = None
new_object_id = object_id new_object_id = object_id
if portal_type == 'Shop Order': if portal_type == 'Shop Order':
...@@ -283,7 +282,7 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -283,7 +282,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
security.declarePrivate('updateObjProperty') security.declarePrivate('updateObjProperty')
def updateObjProperty(self, object, property, kw, key): def updateObjProperty(self, object, property, kw, key): # pylint: disable=redefined-builtin
""" """
This function update the property of an object with a given value stored in a dictionnary. This function help the Conduit to make decision about the synchronization of values. This function update the property of an object with a given value stored in a dictionnary. This function help the Conduit to make decision about the synchronization of values.
...@@ -296,10 +295,10 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -296,10 +295,10 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if kw.has_key(key): if kw.has_key(key):
new_value = kw[key] new_value = kw[key]
if new_value != None: if new_value != None:
if type(new_value) is type('s'): if isinstance(new_value, str):
new_value = new_value.title() new_value = new_value.title()
current_value = eval('object.get' + property + '()') current_value = getattr(object, 'get' + property)()
LOG("I have to run this >>>>>>>> ", 0, 'object.get' + property + '()') LOG("I have to run this >>>>>>>> ", 0, 'object.get' + property + '()')
LOG("current_value >>>>>>>> ", 0, repr(current_value)) LOG("current_value >>>>>>>> ", 0, repr(current_value))
...@@ -320,7 +319,7 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -320,7 +319,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
security.declareProtected(Permissions.ModifyPortalContent, 'editDocument') security.declareProtected(Permissions.ModifyPortalContent, 'editDocument')
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This function use the properties of the object to convert a Storever ShopOrder to an ERP5 SaleOrder. This function use the properties of the object to convert a Storever ShopOrder to an ERP5 SaleOrder.
""" """
...@@ -478,7 +477,6 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -478,7 +477,6 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# We only need to be aware of data fusion between the previous and the current representation # We only need to be aware of data fusion between the previous and the current representation
# So we don't need to do something because the information fusion process take place below # So we don't need to do something because the information fusion process take place below
LOG("The structure is the same. don't do anything >>>>>>>>",0,'') LOG("The structure is the same. don't do anything >>>>>>>>",0,'')
pass
LOG("Person object >>>>>>>>",0,repr(person_object)) LOG("Person object >>>>>>>>",0,repr(person_object))
LOG("Organisation object >>>>>>>>",0,repr(org_object)) LOG("Organisation object >>>>>>>>",0,repr(org_object))
...@@ -628,9 +626,9 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -628,9 +626,9 @@ class ERP5ShopOrderConduit(ERP5Conduit):
erp5_ship_id_word_list = self.str2id(service_id).split("_") erp5_ship_id_word_list = self.str2id(service_id).split("_")
stor_ship_id_word_list = self.str2id(stor_ship_title).split("_") stor_ship_id_word_list = self.str2id(stor_ship_title).split("_")
erp5_ship_title_word_list = self.str2id(erp5_ship_title).split("_") erp5_ship_title_word_list = self.str2id(erp5_ship_title).split("_")
erp5_ship_id_word_list.sort(key=lambda x: str(x)) erp5_ship_id_word_list.sort(key=str)
stor_ship_id_word_list.sort(key=lambda x: str(x)) stor_ship_id_word_list.sort(key=str)
erp5_ship_title_word_list.sort(key=lambda x: str(x)) erp5_ship_title_word_list.sort(key=str)
if stor_ship_id_word_list in (erp5_ship_id_word_list, erp5_ship_title_word_list): if stor_ship_id_word_list in (erp5_ship_id_word_list, erp5_ship_title_word_list):
shipment_id = service_id shipment_id = service_id
LOG("Service found with method 3 ! >>>>>>>>", 0, repr(shipment_id)) LOG("Service found with method 3 ! >>>>>>>>", 0, repr(shipment_id))
...@@ -676,8 +674,6 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -676,8 +674,6 @@ class ERP5ShopOrderConduit(ERP5Conduit):
# The object is an OrderLine # The object is an OrderLine
else: else:
# Find the product folder # Find the product folder
product_path = erp5_site_path + '/product'
product_folder = erp5_site.restrictedTraverse(product_path)
# Find the parent order object # Find the parent order object
parent_order_object = object.aq_parent parent_order_object = object.aq_parent
...@@ -787,7 +783,7 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -787,7 +783,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
LOG('editDocument, cat_base',0,cat_base) LOG('editDocument, cat_base',0,cat_base)
base_cat_object = portal_cat.resolveCategory(cat_base) base_cat_object = portal_cat.resolveCategory(cat_base)
cat_list = base_cat_object.getCategoryChildIdItemList() cat_list = base_cat_object.getCategoryChildIdItemList()
for (category, category_bis) in cat_list: for (category, _) in cat_list:
if self.str2id(option) == category: if self.str2id(option) == category:
customer_product_variation_list[category] = cat_base + '/' + category customer_product_variation_list[category] = cat_base + '/' + category
if cat_base not in customer_product_base_variation_list: if cat_base not in customer_product_base_variation_list:
...@@ -799,7 +795,7 @@ class ERP5ShopOrderConduit(ERP5Conduit): ...@@ -799,7 +795,7 @@ class ERP5ShopOrderConduit(ERP5Conduit):
if option_is_variant == None: if option_is_variant == None:
customer_product_option_list[option] = priced_list[option] customer_product_option_list[option] = priced_list[option]
if len(customer_product_option_list) + len(customer_product_variation_list) != len(priced_list): if len(customer_product_option_list) + len(customer_product_variation_list) != len(priced_list):
LOG('>>>>>>> Wrong repartition of the customer priced list', 200) LOG('>>>>>>> Wrong repartition of the customer priced list', 200, '')
LOG('>>>>>> Customer product option priced list: ', 0, repr(customer_product_option_list)) LOG('>>>>>> Customer product option priced list: ', 0, repr(customer_product_option_list))
LOG('>>>>>> Customer product variation priced list: ', 0, repr(customer_product_variation_list)) LOG('>>>>>> Customer product variation priced list: ', 0, repr(customer_product_variation_list))
LOG('>>>>>> Customer product base variation list: ', 0, repr(customer_product_base_variation_list)) LOG('>>>>>> Customer product base variation list: ', 0, repr(customer_product_base_variation_list))
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5ShopOrderConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Conduit.ERP5ShopOrderConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5ShopOrderConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -29,9 +29,9 @@ ...@@ -29,9 +29,9 @@
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5SyncML.Conduit.VCardConduit import VCardConduit from erp5.component.module.VCardConduit import VCardConduit
# pylint: disable=abstract-method
class SharedVCardConduit(VCardConduit): class SharedVCardConduit(VCardConduit):
""" """
A conduit is in charge to read data from a particular structure, A conduit is in charge to read data from a particular structure,
...@@ -45,7 +45,7 @@ class SharedVCardConduit(VCardConduit): ...@@ -45,7 +45,7 @@ class SharedVCardConduit(VCardConduit):
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
return the Gid composed of FirstName_LastName generate with the object return the Gid composed of FirstName_LastName generate with the object
""" """
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SharedVCardConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Conduit.SharedVCardConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SharedVCardConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -50,4 +50,4 @@ REPLACE_ACTION = 'Replace' ...@@ -50,4 +50,4 @@ REPLACE_ACTION = 'Replace'
ACTIVITY_PRIORITY = 5 ACTIVITY_PRIORITY = 5
class SynchronizationError(Exception): class SynchronizationError(Exception):
pass pass
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLConstant</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.SyncMLConstant</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLConstant</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,31 +27,31 @@ ...@@ -27,31 +27,31 @@
from logging import getLogger from logging import getLogger
from Products.ERP5SyncML.Engine.EngineMixin import EngineMixin from erp5.component.mixin.SyncMLEngineMixin import SyncMLEngineMixin
from Products.ERP5SyncML.SyncMLConstant import ACTIVITY_PRIORITY from erp5.component.module.SyncMLConstant import ACTIVITY_PRIORITY
from Products.ERP5.ERP5Site import getSite from Products.ERP5.ERP5Site import getSite
syncml_logger = getLogger('ERP5SyncML') syncml_logger = getLogger('ERP5SyncML')
class SyncMLAsynchronousEngine(EngineMixin): class SyncMLAsynchronousEngine(SyncMLEngineMixin):
""" Implement synchronization engine using activities """ """ Implement synchronization engine using activities """
def processClientSynchronization(self, syncml_request, subscription): def processClientSynchronization(self, syncml_request, subscription):
""" Global method that process the package 3, 4 & 5 of SyncML DS Protocol """ """ Global method that process the package 3, 4 & 5 of SyncML DS Protocol """
syncml_logger.info("xxx Client processing data from server (%s) xxx" syncml_logger.info("xxx Client processing data from server (%s) xxx",
% (subscription.getSynchronizationState())) subscription.getSynchronizationState())
syncml_logger.info("\tstatus %s, sync %s, final %s" syncml_logger.info("\tstatus %s, sync %s, final %s",
% (len(syncml_request.status_list), len(syncml_request.status_list),
len(syncml_request.sync_command_list), len(syncml_request.sync_command_list),
syncml_request.isFinal)) syncml_request.isFinal)
# We must log in with user defined # We must log in with user defined
subscription._loginUser() subscription._loginUser()
if syncml_request.alert_list: if syncml_request.alert_list:
syncml_logger.warning("Got an alert from server not processed : %s" syncml_logger.warning("Got an alert from server not processed : %s",
% (syncml_request.alert_list,)) syncml_request.alert_list)
# Must check what server tell about database synchronization # Must check what server tell about database synchronization
# and update the mode if required # and update the mode if required
...@@ -98,8 +98,8 @@ class SyncMLAsynchronousEngine(EngineMixin): ...@@ -98,8 +98,8 @@ class SyncMLAsynchronousEngine(EngineMixin):
self.runApplySyncCommand(subscription=subscription, self.runApplySyncCommand(subscription=subscription,
syncml_request=syncml_request, syncml_request=syncml_request,
tag=tag) tag=tag)
syncml_logger.info("-> Client apply command in %d activities" syncml_logger.info("-> Client apply command in %d activities",
% (len(syncml_request.sync_command_list))) len(syncml_request.sync_command_list))
if syncml_request.isFinal: if syncml_request.isFinal:
if not syncml_response: if not syncml_response:
syncml_response = subscription.generateBaseResponse() syncml_response = subscription.generateBaseResponse()
...@@ -153,10 +153,10 @@ class SyncMLAsynchronousEngine(EngineMixin): ...@@ -153,10 +153,10 @@ class SyncMLAsynchronousEngine(EngineMixin):
# syncml_response = subscriber.getLastSentMessage("") # XXX # syncml_response = subscriber.getLastSentMessage("") # XXX
else: else:
syncml_logger.info("xxx Server processing data from client xxx") syncml_logger.info("xxx Server processing data from client xxx")
syncml_logger.info("\tstatus %s, sync %s, final %s" syncml_logger.info("\tstatus %s, sync %s, final %s",
% (len(syncml_request.status_list), len(syncml_request.status_list),
len(syncml_request.sync_command_list), len(syncml_request.sync_command_list),
syncml_request.isFinal)) syncml_request.isFinal)
# we log the user authenticated to do the synchronization with him # we log the user authenticated to do the synchronization with him
if subscriber.getAuthenticationState() == 'logged_in': if subscriber.getAuthenticationState() == 'logged_in':
subscriber._loginUser() subscriber._loginUser()
...@@ -200,8 +200,8 @@ class SyncMLAsynchronousEngine(EngineMixin): ...@@ -200,8 +200,8 @@ class SyncMLAsynchronousEngine(EngineMixin):
# First server process sync commands : Pkg 3 of the sync process # First server process sync commands : Pkg 3 of the sync process
self.runApplySyncCommand(subscription=subscriber, self.runApplySyncCommand(subscription=subscriber,
syncml_request=syncml_request, tag=tag) syncml_request=syncml_request, tag=tag)
syncml_logger.info("-> Server apply command in %d activities" syncml_logger.info("-> Server apply command in %d activities",
% (len(syncml_request.sync_command_list))) len(syncml_request.sync_command_list))
if syncml_request.isFinal: if syncml_request.isFinal:
# Server then sends its modifications # Server then sends its modifications
subscriber.sendModifications() subscriber.sendModifications()
...@@ -226,7 +226,7 @@ class SyncMLAsynchronousEngine(EngineMixin): ...@@ -226,7 +226,7 @@ class SyncMLAsynchronousEngine(EngineMixin):
activity_created = self.runGetAndActivate(subscription=subscriber, activity_created = self.runGetAndActivate(subscription=subscriber,
after_method_id=after_method_id, after_method_id=after_method_id,
tag=tag) tag=tag)
syncml_logger.info("X--> Server is sending modifications in activities %s" %(activity_created)) syncml_logger.info("X--> Server is sending modifications in activities %s", activity_created)
if not activity_created: if not activity_created:
# Server has no modification to send to client, return final message # Server has no modification to send to client, return final message
syncml_logger.info("X-> Server sending final message") syncml_logger.info("X-> Server sending final message")
...@@ -281,7 +281,7 @@ class SyncMLAsynchronousEngine(EngineMixin): ...@@ -281,7 +281,7 @@ class SyncMLAsynchronousEngine(EngineMixin):
id_count=len(syncml_request.sync_command_list)) id_count=len(syncml_request.sync_command_list))
response_id_list.reverse() response_id_list.reverse()
else: else:
response_id_list = [None for x in response_id_list = [None for _ in
xrange(len(syncml_request.sync_command_list))] xrange(len(syncml_request.sync_command_list))]
split = getSite().portal_preferences.getPreferredSyncActionPerActivityCount() split = getSite().portal_preferences.getPreferredSyncActionPerActivityCount()
if not split: # We do not use activities if not split: # We do not use activities
...@@ -306,7 +306,7 @@ class SyncMLAsynchronousEngine(EngineMixin): ...@@ -306,7 +306,7 @@ class SyncMLAsynchronousEngine(EngineMixin):
"group_method_cost" : 1./float(split), "group_method_cost" : 1./float(split),
} }
for action in syncml_request.sync_command_list: for action in syncml_request.sync_command_list:
syncml_logger.info("---> launch action in activity %s" %(action,)) syncml_logger.info("---> launch action in activity %s", action)
activate(**activate_kw).applySyncCommand( activate(**activate_kw).applySyncCommand(
response_message_id=response_id_list.pop(), response_message_id=response_id_list.pop(),
activate_kw=activate_kw, activate_kw=activate_kw,
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLEngineAsynchronous</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Engine.AsynchronousEngine</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLEngineAsynchronous</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,12 +27,12 @@ ...@@ -27,12 +27,12 @@
from logging import getLogger from logging import getLogger
from Products.ERP5SyncML.Engine.EngineMixin import EngineMixin from erp5.component.mixin.SyncMLEngineMixin import SyncMLEngineMixin
from Products.ERP5SyncML.SyncMLConstant import SynchronizationError from erp5.component.module.SyncMLConstant import SynchronizationError
syncml_logger = getLogger('ERP5SyncML') syncml_logger = getLogger('ERP5SyncML')
class SyncMLSynchronousEngine(EngineMixin): class SyncMLSynchronousEngine(SyncMLEngineMixin):
""" """
Implement a synchronous engine wait for IO Implement a synchronous engine wait for IO
""" """
...@@ -41,16 +41,16 @@ class SyncMLSynchronousEngine(EngineMixin): ...@@ -41,16 +41,16 @@ class SyncMLSynchronousEngine(EngineMixin):
""" Global method that process the package 3 of SyncML DS Protocol """ """ Global method that process the package 3 of SyncML DS Protocol """
syncml_logger.info("xxx Client processing data from server xxx") syncml_logger.info("xxx Client processing data from server xxx")
syncml_logger.info("\tstatus %s, sync %s, final %s" syncml_logger.info("\tstatus %s, sync %s, final %s",
% (len(syncml_request.status_list), len(syncml_request.status_list),
len(syncml_request.sync_command_list), len(syncml_request.sync_command_list),
syncml_request.isFinal)) syncml_request.isFinal)
# Process sync logged in # Process sync logged in
subscription._loginUser() subscription._loginUser()
if syncml_request.alert_list: if syncml_request.alert_list:
syncml_logger.warning("Got an alert from server not processed : %s" syncml_logger.warning("Got an alert from server not processed : %s",
% (syncml_request.alert_list,)) syncml_request.alert_list)
# Must check what server tell about database synchronization # Must check what server tell about database synchronization
# and update the mode if required # and update the mode if required
...@@ -61,8 +61,8 @@ class SyncMLSynchronousEngine(EngineMixin): ...@@ -61,8 +61,8 @@ class SyncMLSynchronousEngine(EngineMixin):
self._readStatusList(syncml_request, subscription, syncml_response) self._readStatusList(syncml_request, subscription, syncml_response)
except SynchronizationError: except SynchronizationError:
# Looks like we process an already received message # Looks like we process an already received message
syncml_logger.error("%s does no process packet due to error" syncml_logger.error("%s does no process packet due to error",
% (subscription.getRelativeUrl())) subscription.getRelativeUrl())
return return
if syncml_request.isFinal and \ if syncml_request.isFinal and \
...@@ -88,7 +88,7 @@ class SyncMLSynchronousEngine(EngineMixin): ...@@ -88,7 +88,7 @@ class SyncMLSynchronousEngine(EngineMixin):
# Delete message will contain final tag # Delete message will contain final tag
subscription.getDeletedSyncMLData(syncml_response=syncml_response) subscription.getDeletedSyncMLData(syncml_response=syncml_response)
syncml_logger.info("-> Client sendind modification, finished %s" % (finished,)) syncml_logger.info("-> Client sendind modification, finished %s", finished)
if finished: if finished:
# Will then start processing sync commands from server # Will then start processing sync commands from server
subscription.processSyncRequest() subscription.processSyncRequest()
...@@ -101,8 +101,8 @@ class SyncMLSynchronousEngine(EngineMixin): ...@@ -101,8 +101,8 @@ class SyncMLSynchronousEngine(EngineMixin):
syncml_request=syncml_request, syncml_request=syncml_request,
syncml_response=syncml_response, syncml_response=syncml_response,
simulate=False) simulate=False)
syncml_logger.info("-> Client sending %s notification of object synchronized" syncml_logger.info("-> Client sending %s notification of object synchronized",
% (syncml_response.sync_confirmation_counter)) syncml_response.sync_confirmation_counter)
if syncml_request.isFinal: if syncml_request.isFinal:
# Notify that all modifications were applied # Notify that all modifications were applied
syncml_response.addFinal() syncml_response.addFinal()
...@@ -137,10 +137,10 @@ class SyncMLSynchronousEngine(EngineMixin): ...@@ -137,10 +137,10 @@ class SyncMLSynchronousEngine(EngineMixin):
syncml_response = subscriber.getLastSentMessage("") # XXX syncml_response = subscriber.getLastSentMessage("") # XXX
else: else:
syncml_logger.info("xxx Server processing data from client xxx") syncml_logger.info("xxx Server processing data from client xxx")
syncml_logger.info("\tstatus %s, sync %s, final %s" syncml_logger.info("\tstatus %s, sync %s, final %s",
% (len(syncml_request.status_list), len(syncml_request.status_list),
len(syncml_request.sync_command_list), len(syncml_request.sync_command_list),
syncml_request.isFinal)) syncml_request.isFinal)
# we log the user authenticated to do the synchronization with him # we log the user authenticated to do the synchronization with him
if subscriber.getAuthenticationState() == 'logged_in': if subscriber.getAuthenticationState() == 'logged_in':
subscriber._loginUser() subscriber._loginUser()
...@@ -187,8 +187,8 @@ class SyncMLSynchronousEngine(EngineMixin): ...@@ -187,8 +187,8 @@ class SyncMLSynchronousEngine(EngineMixin):
syncml_response=syncml_response, syncml_response=syncml_response,
simulate=True) simulate=True)
syncml_logger.info("-> Server sending %s notification of sync" syncml_logger.info("-> Server sending %s notification of sync",
% (syncml_response.sync_confirmation_counter)) syncml_response.sync_confirmation_counter)
if syncml_request.isFinal: if syncml_request.isFinal:
# Server will now send its modifications # Server will now send its modifications
subscriber.sendModifications() subscriber.sendModifications()
...@@ -211,7 +211,7 @@ class SyncMLSynchronousEngine(EngineMixin): ...@@ -211,7 +211,7 @@ class SyncMLSynchronousEngine(EngineMixin):
# Delete message will contain final tag # Delete message will contain final tag
subscriber.getDeletedSyncMLData(syncml_response=syncml_response) subscriber.getDeletedSyncMLData(syncml_response=syncml_response)
syncml_logger.info("-> Server sendind data, finished %s" % (finished,)) syncml_logger.info("-> Server sendind data, finished %s", finished)
if finished: if finished:
subscriber.waitNotifications() subscriber.waitNotifications()
# Do not go into finished here as we must wait for # Do not go into finished here as we must wait for
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLEngineSynchronous</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Engine.SynchronousEngine</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLEngineSynchronous</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -29,9 +29,9 @@ from lxml.builder import ElementMaker ...@@ -29,9 +29,9 @@ from lxml.builder import ElementMaker
from lxml.etree import Element from lxml.etree import Element
from lxml import etree from lxml import etree
from Products.ERP5SyncML.XMLSyncUtils import resolveSyncmlStatusCode, \ from erp5.component.module.XMLSyncUtils import resolveSyncmlStatusCode, \
encode, resolveSyncmlAlertCode encode, resolveSyncmlAlertCode
from Products.ERP5SyncML.SyncMLConstant import SYNCML_NAMESPACE, NSMAP from erp5.component.module.SyncMLConstant import SYNCML_NAMESPACE, NSMAP
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
E = ElementMaker(namespace=SYNCML_NAMESPACE, nsmap=NSMAP) E = ElementMaker(namespace=SYNCML_NAMESPACE, nsmap=NSMAP)
...@@ -224,6 +224,7 @@ class SyncMLResponse(object): ...@@ -224,6 +224,7 @@ class SyncMLResponse(object):
receiving a challenge message receiving a challenge message
""" """
raise NotImplementedError("To review") raise NotImplementedError("To review")
"""
# create element 'SyncML' with a default namespace # create element 'SyncML' with a default namespace
xml = E.SyncML() xml = E.SyncML()
# syncml header # syncml header
...@@ -257,6 +258,7 @@ class SyncMLResponse(object): ...@@ -257,6 +258,7 @@ class SyncMLResponse(object):
xml_string = etree.tostring(xml, encoding='utf-8', xml_declaration=True, xml_string = etree.tostring(xml, encoding='utf-8', xml_declaration=True,
pretty_print=True) pretty_print=True)
self.data_append(xml_string) self.data_append(xml_string)
"""
def addPutMessage(self,subscription, markup='Put', def addPutMessage(self,subscription, markup='Put',
cmd_ref=None, message_id=None): cmd_ref=None, message_id=None):
...@@ -277,6 +279,7 @@ class SyncMLResponse(object): ...@@ -277,6 +279,7 @@ class SyncMLResponse(object):
Both must be able to handle and process these informations Both must be able to handle and process these informations
""" """
return return
"""
# XXX-Aurel : must be reviewed according to specification # XXX-Aurel : must be reviewed according to specification
# This part can be skipped for now # This part can be skipped for now
conduit = subscription.getConduit() conduit = subscription.getConduit()
...@@ -330,6 +333,7 @@ class SyncMLResponse(object): ...@@ -330,6 +333,7 @@ class SyncMLResponse(object):
E.SyncType('6') E.SyncType('6')
)) ))
self.data_append(xml) self.data_append(xml)
"""
def addSyncCommand(self, sync_command, gid, data, media_type, more_data): def addSyncCommand(self, sync_command, gid, data, media_type, more_data):
...@@ -583,8 +587,8 @@ class SyncMLRequest(object): ...@@ -583,8 +587,8 @@ class SyncMLRequest(object):
data = sync_command.xpath('string(.//syncml:Item/syncml:Data)', data = sync_command.xpath('string(.//syncml:Item/syncml:Data)',
namespaces=self.data.nsmap) namespaces=self.data.nsmap)
if isinstance(data, etree.CDATA): if isinstance(data, etree.CDATA):
parser = etree.XMLParser(strip_cdata=False) parser_ = etree.XMLParser(strip_cdata=False)
cdata = etree.XML(data, parser) cdata = etree.XML(data, parser_)
data = cdata.text data = cdata.text
# XXX this is unicode and can be a problem for activity # XXX this is unicode and can be a problem for activity
sync_command_kw["raw_data"] = data sync_command_kw["raw_data"] = data
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLMessage</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.SyncMLMessage</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLMessage</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLTransportERP5</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Transport.ERP5</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLTransportERP5</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -25,10 +25,7 @@ ...@@ -25,10 +25,7 @@
# #
############################################################################## ##############################################################################
from erp5.component.module.SyncMLTransportHTTP import ConnectionError
from HTTP import ConnectionError
class FileTransport: class FileTransport:
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLTransportFile</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Transport.File</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLTransportFile</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -63,7 +63,7 @@ class HTTPTransport: ...@@ -63,7 +63,7 @@ class HTTPTransport:
def send(self, to_url, data, sync_id, content_type): def send(self, to_url, data, sync_id, content_type):
syncml_logger.debug("HTTP.send : %s" %(to_url,)) syncml_logger.debug("HTTP.send : %s", to_url)
data = { data = {
'text' : data, 'text' : data,
'sync_id': sync_id 'sync_id': sync_id
...@@ -72,5 +72,5 @@ class HTTPTransport: ...@@ -72,5 +72,5 @@ class HTTPTransport:
headers=self.getHeaders(content_type, data), headers=self.getHeaders(content_type, data),
timeout=60, timeout=60,
proxies=self.getProxyMapping()) proxies=self.getProxyMapping())
syncml_logger.debug("Status code : %s - %s" %(r.status_code, r.headers)) syncml_logger.debug("Status code : %s - %s", r.status_code, r.headers)
r.raise_for_status() r.raise_for_status()
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLTransportHTTP</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Transport.HTTP</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLTransportHTTP</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -25,11 +25,9 @@ ...@@ -25,11 +25,9 @@
# #
############################################################################## ##############################################################################
from erp5.component.module.SyncMLTransportHTTP import ConnectionError
from HTTP import ConnectionError
from Products.ERP5.ERP5Site import getSite from Products.ERP5.ERP5Site import getSite
class MailTransport: class MailTransport:
def send(self, from_url, to_url, xml, sync_id, content_type): def send(self, from_url, to_url, xml, sync_id, content_type):
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLTransportMail</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Transport.Mail</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLTransportMail</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -68,20 +68,20 @@ class PdataHelper(persistent.Persistent): ...@@ -68,20 +68,20 @@ class PdataHelper(persistent.Persistent):
n = self._max_len n = self._max_len
if isinstance(value, (str, unicode)): if isinstance(value, (str, unicode)):
if isinstance(value, unicode): if isinstance(value, unicode):
value = value.encode('utf-8') value = value.encode('utf-8')
size=len(value) size=len(value)
if size < n: if size < n:
return Pdata(value), size return Pdata(value), size
# Big string: cut it into smaller chunks # Big string: cut it into smaller chunks
value = StringIO(value) value = StringIO(value)
if isinstance(value, FileUpload) and not value: if isinstance(value, FileUpload) and not value:
raise ValueError, 'File not specified' raise ValueError, 'File not specified'
if isinstance(value, Pdata): if isinstance(value, Pdata):
size = self._read_size_from_pdata(value) size = self._read_size_from_pdata(value)
return value, size return value, size
# Clear md5sum to force refreshing # Clear md5sum to force refreshing
self.md5sum = None self.md5sum = None
...@@ -93,66 +93,66 @@ class PdataHelper(persistent.Persistent): ...@@ -93,66 +93,66 @@ class PdataHelper(persistent.Persistent):
size=end=value.tell() size=end=value.tell()
if size <= 2*n: if size <= 2*n:
seek(0) seek(0)
return Pdata(read(size)), size return Pdata(read(size)), size
# Make sure we have an _p_jar, even if we are a new object, by # Make sure we have an _p_jar, even if we are a new object, by
# doing a sub-transaction commit. # doing a sub-transaction commit.
transaction.savepoint(optimistic=True) transaction.savepoint(optimistic=True)
if persistent_object._p_jar is None: if persistent_object._p_jar is None:
# Ugh # Ugh
seek(0) seek(0)
return Pdata(read(size)), size return Pdata(read(size)), size
# Now we're going to build a linked list from back # Now we're going to build a linked list from back
# to front to minimize the number of database updates # to front to minimize the number of database updates
# and to allow us to get things out of memory as soon as # and to allow us to get things out of memory as soon as
# possible. # possible.
next = None next_ = None
while end > 0: while end > 0:
pos = end-n pos = end-n
if pos < n: if pos < n:
pos = 0 # we always want at least n bytes pos = 0 # we always want at least n bytes
seek(pos) seek(pos)
# Create the object and assign it a next pointer # Create the object and assign it a next pointer
# in the same transaction, so that there is only # in the same transaction, so that there is only
# a single database update for it. # a single database update for it.
data = Pdata(read(end-pos)) data = Pdata(read(end-pos))
persistent_object._p_jar.add(data) persistent_object._p_jar.add(data)
data.next = next data.next = next_
# Save the object so that we can release its memory. # Save the object so that we can release its memory.
transaction.savepoint(optimistic=True) transaction.savepoint(optimistic=True)
data._p_deactivate() data._p_deactivate()
# The object should be assigned an oid and be a ghost. # The object should be assigned an oid and be a ghost.
assert data._p_oid is not None assert data._p_oid is not None
assert data._p_state == -1 assert data._p_state == -1
next = data next_ = data
end = pos end = pos
return next, size return next_, size
def _digest_md5_hash_from_pdata(self, pdata): def _digest_md5_hash_from_pdata(self, pdata):
"""Compute hash part by part """Compute hash part by part
""" """
md5_hash = md5() md5_hash = md5()
next = pdata next_ = pdata
while next is not None: while next_ is not None:
md5_hash.update(next.data) md5_hash.update(next_.data)
next = next.next next_ = next_.next
return md5_hash.hexdigest() return md5_hash.hexdigest()
def _read_size_from_pdata(self, pdata): def _read_size_from_pdata(self, pdata):
"""Compute size part by part """Compute size part by part
""" """
size = 0 size = 0
next = pdata next_ = pdata
while next is not None: while next_ is not None:
size += len(next.data) size += len(next_.data)
next = next.next next_ = next_.next
return size return size
def __len__(self): def __len__(self):
...@@ -186,9 +186,9 @@ class PdataHelper(persistent.Persistent): ...@@ -186,9 +186,9 @@ class PdataHelper(persistent.Persistent):
of a Pdata chains of a Pdata chains
""" """
pdata = self._data pdata = self._data
next = pdata.next next_ = pdata.next
while next is not None: while next_ is not None:
pdata = next pdata = next_
next = pdata.next next_ = pdata.next
return pdata return pdata
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SyncMLUtils</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Utils</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.SyncMLUtils</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.ERP5Conduit import ERP5Conduit
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
import difflib import difflib
...@@ -48,7 +48,7 @@ class VCardConduit(ERP5Conduit): ...@@ -48,7 +48,7 @@ class VCardConduit(ERP5Conduit):
security.declareProtected(Permissions.ModifyPortalContent, 'addNode') security.declareProtected(Permissions.ModifyPortalContent, 'addNode')
def addNode(self, xml=None, object=None, previous_xml=None, def addNode(self, xml=None, object=None, previous_xml=None, # pylint: disable=redefined-builtin
object_id=None, sub_object=None, force=0, simulate=0, **kw): object_id=None, sub_object=None, force=0, simulate=0, **kw):
""" """
add a new person corresponding to the vcard add a new person corresponding to the vcard
...@@ -61,8 +61,7 @@ class VCardConduit(ERP5Conduit): ...@@ -61,8 +61,7 @@ class VCardConduit(ERP5Conduit):
portal_type = 'Person' #the VCard can just use Person portal_type = 'Person' #the VCard can just use Person
if sub_object is None: if sub_object is None:
new_object, reset_local_roles, reset_workflow =\ new_object, _, _ = ERP5Conduit.constructContent(self, object, object_id, portal_type)
ERP5Conduit.constructContent(self, object, object_id, portal_type)
else: #if the object exist, it juste must be update else: #if the object exist, it juste must be update
new_object = sub_object new_object = sub_object
#LOG('addNode', 0, 'new_object:%s, sub_object:%s' % (new_object, sub_object)) #LOG('addNode', 0, 'new_object:%s, sub_object:%s' % (new_object, sub_object))
...@@ -75,7 +74,7 @@ class VCardConduit(ERP5Conduit): ...@@ -75,7 +74,7 @@ class VCardConduit(ERP5Conduit):
return {'conflict_list':[], 'object': new_object} return {'conflict_list':[], 'object': new_object}
security.declareProtected(Permissions.ModifyPortalContent, 'deleteNode') security.declareProtected(Permissions.ModifyPortalContent, 'deleteNode')
def deleteNode(self, xml=None, object=None, object_id=None, force=None, def deleteNode(self, xml=None, object=None, object_id=None, force=None, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
""" """
A node is deleted A node is deleted
...@@ -88,7 +87,7 @@ class VCardConduit(ERP5Conduit): ...@@ -88,7 +87,7 @@ class VCardConduit(ERP5Conduit):
return [] return []
security.declareProtected(Permissions.ModifyPortalContent, 'updateNode') security.declareProtected(Permissions.ModifyPortalContent, 'updateNode')
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, def updateNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
""" """
A node is updated A node is updated
...@@ -165,12 +164,12 @@ class VCardConduit(ERP5Conduit): ...@@ -165,12 +164,12 @@ class VCardConduit(ERP5Conduit):
vcard_list = vcard.split('\n') vcard_list = vcard.split('\n')
for vcard_line in vcard_list: for vcard_line in vcard_list:
if ':' in vcard_line: if ':' in vcard_line:
property, property_value = vcard_line.split(':') property_, property_value = vcard_line.split(':')
property_value_list = property_value.split(';') property_value_list = property_value.split(';')
property_parameters_list = [] property_parameters_list = []
property_name = '' property_name = ''
if ';' in property: if ';' in property_:
property_list = property.split(';') property_list = property_.split(';')
property_name = property_list[0] #the property name is the 1st element property_name = property_list[0] #the property name is the 1st element
if len(property_list) > 1 and property_list[1] != '': if len(property_list) > 1 and property_list[1] != '':
property_parameters_list = property_list[1:len(property_list)] property_parameters_list = property_list[1:len(property_list)]
...@@ -192,7 +191,7 @@ class VCardConduit(ERP5Conduit): ...@@ -192,7 +191,7 @@ class VCardConduit(ERP5Conduit):
property_value_list) property_value_list)
else: else:
property_name=property property_name=property_
if isinstance(property_name, unicode): if isinstance(property_name, unicode):
property_name = property_name.encode('utf-8') property_name = property_name.encode('utf-8')
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>VCardConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Conduit.VCardConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.VCardConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -37,7 +37,7 @@ from zLOG import LOG, INFO ...@@ -37,7 +37,7 @@ from zLOG import LOG, INFO
from ERP5Diff import ERP5Diff from ERP5Diff import ERP5Diff
from DateTime import DateTime from DateTime import DateTime
from SyncMLConstant import SYNCML_NAMESPACE, NSMAP, MAX_LEN from erp5.component.module.SyncMLConstant import SYNCML_NAMESPACE, NSMAP, MAX_LEN
from Products.ERP5.ERP5Site import getSite from Products.ERP5.ERP5Site import getSite
E = ElementMaker(namespace=SYNCML_NAMESPACE, nsmap=NSMAP) E = ElementMaker(namespace=SYNCML_NAMESPACE, nsmap=NSMAP)
...@@ -51,7 +51,7 @@ def buildAnchorFromDate(date): ...@@ -51,7 +51,7 @@ def buildAnchorFromDate(date):
return date return date
def encode(format, string_to_encode): def encode(format, string_to_encode): # pylint: disable=redefined-builtin
""" """
return the string_to_encode encoded with format format return the string_to_encode encoded with format format
""" """
...@@ -65,7 +65,7 @@ def encode(format, string_to_encode): ...@@ -65,7 +65,7 @@ def encode(format, string_to_encode):
raise ValueError, "Sorry, the server ask for the format %s but \ raise ValueError, "Sorry, the server ask for the format %s but \
it's unknow or not implemented" % format it's unknow or not implemented" % format
def decode(format, string_to_decode): def decode(format, string_to_decode): # pylint: disable=redefined-builtin
""" """
return the string_to_decode decoded with format format return the string_to_decode decoded with format format
""" """
...@@ -80,7 +80,7 @@ def decode(format, string_to_decode): ...@@ -80,7 +80,7 @@ def decode(format, string_to_decode):
raise ValueError, "Sorry, the format %s is unknow or \ raise ValueError, "Sorry, the format %s is unknow or \
not implemented" % format not implemented" % format
def isDecodeEncodeTheSame(string_encoded, string_decoded, format): def isDecodeEncodeTheSame(string_encoded, string_decoded, format): # pylint: disable=redefined-builtin
""" """
return True if the string_encoded is equal to string_decoded encoded return True if the string_encoded is equal to string_decoded encoded
in format in format
...@@ -121,7 +121,7 @@ def getConduitByName(conduit_name): ...@@ -121,7 +121,7 @@ def getConduitByName(conduit_name):
Get Conduit Object by given name. Get Conduit Object by given name.
The Conduit can be located in Any Products according to naming Convention 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. 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> By default Conduit must be defined as ZODB Components (erp5.component.module.<Conduit Module>)
Conduit can also be defined as Extension to have it editable through the web, in this Conduit can also be defined as Extension to have it editable through the web, in this
case its definition must be Extensions.<Conduit Module> case its definition must be Extensions.<Conduit Module>
""" """
...@@ -136,9 +136,7 @@ def getConduitByName(conduit_name): ...@@ -136,9 +136,7 @@ def getConduitByName(conduit_name):
conduit_module = __import__("erp5.component."+conduit_name, globals(), locals(), ['']) conduit_module = __import__("erp5.component."+conduit_name, globals(), locals(), [''])
conduit_name = conduit_name.split('.')[-1] conduit_name = conduit_name.split('.')[-1]
else: else:
from Products.ERP5SyncML import Conduit conduit_module = __import__('erp5.component.module.'+conduit_name, globals(), locals(), [''])
conduit_module = __import__('.'.join([Conduit.__name__, conduit_name]),
globals(), locals(), [''])
conduit_instance = getattr(conduit_module, conduit_name)() conduit_instance = getattr(conduit_module, conduit_name)()
return conduit_instance return conduit_instance
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>XMLSyncUtils</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.XMLSyncUtils</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.XMLSyncUtils</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5SyncML.XMLSyncUtils import XMLSyncUtilsMixin from erp5.component.module.XMLSyncUtils import XMLSyncUtilsMixin
from xml.dom.ext.reader.Sax2 import FromXml from xml.dom.ext.reader.Sax2 import FromXml
class XupdateUtils(XMLSyncUtilsMixin): class XupdateUtils(XMLSyncUtilsMixin):
...@@ -35,7 +35,7 @@ class XupdateUtils(XMLSyncUtilsMixin): ...@@ -35,7 +35,7 @@ class XupdateUtils(XMLSyncUtilsMixin):
this is the place where we should parse xupdate data. this is the place where we should parse xupdate data.
""" """
def applyXupdate(self, object=None, xupdate=None, conduit=None, force=0, **kw): def applyXupdate(self, object=None, xupdate=None, conduit=None, force=0, **kw): # pylint: disable=redefined-builtin
""" """
Parse the xupdate and then it will call the conduit Parse the xupdate and then it will call the conduit
""" """
...@@ -44,7 +44,6 @@ class XupdateUtils(XMLSyncUtilsMixin): ...@@ -44,7 +44,6 @@ class XupdateUtils(XMLSyncUtilsMixin):
xupdate = FromXml(xupdate) xupdate = FromXml(xupdate)
for subnode in xupdate: for subnode in xupdate:
selection_name = ''
if subnode.xpath('name()') in self.XUPDATE_INSERT_OR_ADD: if subnode.xpath('name()') in self.XUPDATE_INSERT_OR_ADD:
conflict_list.extend(conduit.addNode(xml=subnode, object=object, \ conflict_list.extend(conduit.addNode(xml=subnode, object=object, \
force=force, **kw)) force=force, **kw))
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>XupdateUtils</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.XupdateUtils</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.XupdateUtils</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -99,5 +99,4 @@ class TestERP5SyncMLMixin(ERP5TypeTestCase): ...@@ -99,5 +99,4 @@ class TestERP5SyncMLMixin(ERP5TypeTestCase):
portal_type="SyncML Subscription") portal_type="SyncML Subscription")
for subscription in subscription_list: for subscription in subscription_list:
if self.portal.portal_workflow.isTransitionPossible(subscription, 'validate'): if self.portal.portal_workflow.isTransitionPossible(subscription, 'validate'):
subscription.validate() subscription.validate()
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testERP5SyncMLMixin</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.tests.testERP5SyncMLMixin</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.testERP5SyncMLMixin</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -36,11 +36,12 @@ from AccessControl.SecurityManagement import newSecurityManager ...@@ -36,11 +36,12 @@ from AccessControl.SecurityManagement import newSecurityManager
from Products.ERP5Type.tests.runUnitTest import tests_home from Products.ERP5Type.tests.runUnitTest import tests_home
from Products.ERP5Type.tests.utils import FileUpload from Products.ERP5Type.tests.utils import FileUpload
from Products.ERP5SyncML.Tool import SynchronizationTool from erp5.component.tool import SynchronizationTool
from Products.ERP5SyncML.tests.testERP5SyncML import TestERP5SyncMLMixin from erp5.component.test.testERP5SyncML import TestERP5SyncMLMixin
from Products.ERP5SyncML.Document import SyncMLSubscription from erp5.component.document import SyncMLSubscription
test_files = os.path.join(os.path.dirname(__file__), 'test_document') import Products.ERP5.tests
test_files = os.path.join(os.path.dirname(Products.ERP5.tests.__file__), 'test_data')
FILENAME_REGULAR_EXPRESSION = "(?P<reference>[A-Z]{3,10})-\ FILENAME_REGULAR_EXPRESSION = "(?P<reference>[A-Z]{3,10})-\
(?P<language>[a-z]{2})-(?P<version>[0-9]{3})" (?P<language>[a-z]{2})-(?P<version>[0-9]{3})"
REFERENCE_REGULAR_EXPRESSION = "(?P<reference>[A-Z]{3,10})(-\ REFERENCE_REGULAR_EXPRESSION = "(?P<reference>[A-Z]{3,10})(-\
...@@ -138,12 +139,12 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin): ...@@ -138,12 +139,12 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin):
def clearFiles(self): def clearFiles(self):
# reset files, because we do sync by files # reset files, because we do sync by files
for filename in self.subscription_url.values(): for filename in self.subscription_url.values():
file = open(filename[len('file:/'):], 'w') file_ = open(filename[len('file:/'):], 'w')
file.write('') file_.write('')
file.close() file_.close()
file = open(self.publication_url[len('file:/'):], 'w') file_ = open(self.publication_url[len('file:/'):], 'w')
file.write('') file_.write('')
file.close() file_.close()
def setSystemPreferences(self): def setSystemPreferences(self):
...@@ -253,16 +254,16 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin): ...@@ -253,16 +254,16 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin):
self.createDocumentModules() self.createDocumentModules()
document_server = self.getDocumentServer() document_server = self.getDocumentServer()
#plain text document #plain text document
for id in self.ids[:self.id_max_text]: for id_ in self.ids[:self.id_max_text]:
reference = "Test-Text-%s" % (id,) reference = "Test-Text-%s" % (id_,)
self.createDocument(id=id, file_name=self.filename_text, reference=reference) self.createDocument(id=id_, file_name=self.filename_text, reference=reference)
self.commit() self.commit()
nb_document = len(document_server.objectValues()) nb_document = len(document_server.objectValues())
self.assertEqual(nb_document, len(self.ids[:self.id_max_text])) self.assertEqual(nb_document, len(self.ids[:self.id_max_text]))
#binary document #binary document
for id in self.ids[self.id_max_text:]: for id_ in self.ids[self.id_max_text:]:
reference = "Test-Odt-%s" % (id, ) reference = "Test-Odt-%s" % (id_, )
self.createDocument(id=id, file_name=self.filename_odt, reference=reference) self.createDocument(id=id_, file_name=self.filename_odt, reference=reference)
self.tic() self.tic()
nb_document = len(document_server.objectValues()) nb_document = len(document_server.objectValues())
self.assertEqual(nb_document, len(self.ids)) self.assertEqual(nb_document, len(self.ids))
...@@ -279,22 +280,22 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin): ...@@ -279,22 +280,22 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin):
kw = {'reference': self.reference1, 'Version': self.version1, kw = {'reference': self.reference1, 'Version': self.version1,
'Language': self.language1, 'Description': self.description1} 'Language': self.language1, 'Description': self.description1}
document_text.edit(**kw) document_text.edit(**kw)
file = makeFileUpload(self.filename_text) file_ = makeFileUpload(self.filename_text)
document_text.edit(file=file) document_text.edit(file=file_)
self.tic() self.tic()
document_pdf = document_server.newContent(id=self.id2, document_pdf = document_server.newContent(id=self.id2,
portal_type='PDF') portal_type='PDF')
kw = {'reference': self.reference2, 'Version': self.version2, kw = {'reference': self.reference2, 'Version': self.version2,
'Language': self.language2, 'Description': self.description2} 'Language': self.language2, 'Description': self.description2}
document_pdf.edit(**kw) document_pdf.edit(**kw)
file = makeFileUpload(self.filename_pdf) file_ = makeFileUpload(self.filename_pdf)
document_pdf.edit(file=file) document_pdf.edit(file=file_)
self.tic() self.tic()
nb_document = len(document_server) nb_document = len(document_server)
self.assertEqual(nb_document, 2) self.assertEqual(nb_document, 2)
return nb_document return nb_document
def createDocument(self, id, file_name=None, portal_type='Text', def createDocument(self, id, file_name=None, portal_type='Text', # pylint: disable=redefined-builtin
reference='P-SYNCML.Text', version='001', language='en'): reference='P-SYNCML.Text', version='001', language='en'):
""" """
Create a text document Create a text document
...@@ -304,8 +305,8 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin): ...@@ -304,8 +305,8 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin):
kw = {'reference': reference, 'version': version, 'language': language} kw = {'reference': reference, 'version': version, 'language': language}
doc_text.edit(**kw) doc_text.edit(**kw)
if file_name is not None: if file_name is not None:
file = makeFileUpload(file_name) file_ = makeFileUpload(file_name)
doc_text.edit(file=file) doc_text.edit(file=file_)
return doc_text return doc_text
def checkSynchronizationStateIsSynchronized(self): def checkSynchronizationStateIsSynchronized(self):
...@@ -330,39 +331,39 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin): ...@@ -330,39 +331,39 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin):
for m in sub.contentValues(): for m in sub.contentValues():
self.assertEqual(m.getPartialData(), None) self.assertEqual(m.getPartialData(), None)
def checkFirstSynchronization(self, nb_document=0): def checkFirstSynchronization(self, nb_document=0): # pylint: disable=arguments-differ
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
subscription1 = portal_sync[self.sub_id1] subscription1 = portal_sync[self.sub_id1]
self.assertEqual(len(subscription1), nb_document) self.assertEqual(len(subscription1), nb_document)
document_server = self.getDocumentServer() # We also check we don't document_server = self.getDocumentServer() # We also check we don't
# modify initial ob # modify initial ob
doc1_s = document_server._getOb(self.id1) doc1_s = document_server._getOb(self.id1)
self.assertEqual(doc1_s.getId(), self.id1) self.assertEqual(doc1_s.getId(), self.id1)
self.assertEqual(doc1_s.getReference(), self.reference1) self.assertEqual(doc1_s.getReference(), self.reference1)
self.assertEqual(doc1_s.getVersion(), self.version1) self.assertEqual(doc1_s.getVersion(), self.version1)
self.assertEqual(doc1_s.getLanguage(), self.language1) self.assertEqual(doc1_s.getLanguage(), self.language1)
self.assertEqual(doc1_s.getFilename(), self.filename_text) self.assertEqual(doc1_s.getFilename(), self.filename_text)
self.assertEqual(self.size_filename_text, doc1_s.get_size()) self.assertEqual(self.size_filename_text, doc1_s.get_size())
doc2_s = document_server._getOb(self.id2) doc2_s = document_server._getOb(self.id2)
self.assertEqual(doc2_s.getReference(), self.reference2) self.assertEqual(doc2_s.getReference(), self.reference2)
self.assertEqual(doc2_s.getVersion(), self.version2) self.assertEqual(doc2_s.getVersion(), self.version2)
self.assertEqual(doc2_s.getLanguage(), self.language2) self.assertEqual(doc2_s.getLanguage(), self.language2)
self.assertEqual(doc2_s.getFilename(), self.filename_pdf) self.assertEqual(doc2_s.getFilename(), self.filename_pdf)
self.assertEqual(self.size_filename_pdf, doc2_s.get_size()) self.assertEqual(self.size_filename_pdf, doc2_s.get_size())
document_client1 = self.getDocumentClient1() document_client1 = self.getDocumentClient1()
document_c = document_client1._getOb(self.id1) document_c = document_client1._getOb(self.id1)
self.assertEqual(document_c.getId(), self.id1) self.assertEqual(document_c.getId(), self.id1)
self.assertEqual(document_c.getReference(), self.reference1) self.assertEqual(document_c.getReference(), self.reference1)
self.assertEqual(document_c.getVersion(), self.version1) self.assertEqual(document_c.getVersion(), self.version1)
self.assertEqual(document_c.getLanguage(), self.language1) self.assertEqual(document_c.getLanguage(), self.language1)
self.assertEqual(document_c.getFilename(), self.filename_text) self.assertEqual(document_c.getFilename(), self.filename_text)
self.assertEqual(self.size_filename_text, document_c.get_size()) self.assertEqual(self.size_filename_text, document_c.get_size())
self.assertXMLViewIsEqual(self.sub_id1, doc1_s, document_c) self.assertXMLViewIsEqual(self.sub_id1, doc1_s, document_c)
self.assertXMLViewIsEqual(self.sub_id1, doc2_s, self.assertXMLViewIsEqual(self.sub_id1, doc2_s,
document_client1._getOb(self.id2)) document_client1._getOb(self.id2))
def checkDocument(self, id, document, filename=None, def checkDocument(self, id, document, filename=None, # pylint: disable=redefined-builtin
size_filename=None, reference='P-SYNCML.Text', size_filename=None, reference='P-SYNCML.Text',
portal_type='Text', version='001', language='en', portal_type='Text', version='001', language='en',
description=''): description=''):
...@@ -384,9 +385,9 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin): ...@@ -384,9 +385,9 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin):
def checkXMLsSynchronized(self): def checkXMLsSynchronized(self):
document_server = self.getDocumentServer() document_server = self.getDocumentServer()
document_client1 = self.getDocumentClient1() document_client1 = self.getDocumentClient1()
for id in self.ids: for id_ in self.ids:
doc_s = document_server._getOb(str(id)) doc_s = document_server._getOb(str(id_))
doc_c = document_client1._getOb(str(id)) doc_c = document_client1._getOb(str(id_))
self.assertXMLViewIsEqual(self.sub_id1, doc_s, doc_c) self.assertXMLViewIsEqual(self.sub_id1, doc_s, doc_c)
...@@ -395,17 +396,17 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin): ...@@ -395,17 +396,17 @@ class TestERP5DocumentSyncMLMixin(TestERP5SyncMLMixin):
subscription1 = portal_sync[self.sub_id1] subscription1 = portal_sync[self.sub_id1]
self.assertEqual(len(subscription1.getDocumentList()), nb_document) self.assertEqual(len(subscription1.getDocumentList()), nb_document)
document_server = self.getDocumentServer() document_server = self.getDocumentServer()
id = str(self.ids[0]) id_ = str(self.ids[0])
doc_text_s = document_server._getOb(id) doc_text_s = document_server._getOb(id_)
reference = 'Test-Text-%s' % id reference = 'Test-Text-%s' % id_
self.checkDocument(id=id, document=doc_text_s, self.checkDocument(id=id_, document=doc_text_s,
reference=reference, reference=reference,
filename=self.filename_text, filename=self.filename_text,
size_filename=self.size_filename_text) size_filename=self.size_filename_text)
id = str(self.ids[self.id_max_text]) id_ = str(self.ids[self.id_max_text])
doc_odt_s = document_server._getOb(id) doc_odt_s = document_server._getOb(id_)
reference = 'Test-Odt-%s' % id reference = 'Test-Odt-%s' % id_
self.checkDocument(id=id, document=doc_odt_s, self.checkDocument(id=id_, document=doc_odt_s,
reference=reference, reference=reference,
filename=self.filename_odt, filename=self.filename_odt,
size_filename=self.size_filename_odt) size_filename=self.size_filename_odt)
...@@ -479,8 +480,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin): ...@@ -479,8 +480,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin):
# Then we do only modification on a client (the gid) of client => add a object # Then we do only modification on a client (the gid) of client => add a object
kw = {'reference':self.reference1,'version':self.version3} kw = {'reference':self.reference1,'version':self.version3}
document_c.edit(**kw) document_c.edit(**kw)
file = makeFileUpload(self.filename_odt) file_ = makeFileUpload(self.filename_odt)
document_c.edit(file=file) document_c.edit(file=file_)
self.tic() self.tic()
self.synchronize(self.sub_id1) self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized() self.checkSynchronizationStateIsSynchronized()
...@@ -590,15 +591,15 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin): ...@@ -590,15 +591,15 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin):
doc_s = document_server._getOb(id_text) doc_s = document_server._getOb(id_text)
kw = {'description':self.description1} kw = {'description':self.description1}
doc_s.edit(**kw) doc_s.edit(**kw)
file = makeFileUpload(self.filename_odt) file_ = makeFileUpload(self.filename_odt)
doc_s.edit(file=file) doc_s.edit(file=file_)
# Side client modification gid of a odt document # Side client modification gid of a odt document
id_odt = str(self.ids[self.id_max_text+1]) id_odt = str(self.ids[self.id_max_text+1])
doc_c = document_client1._getOb(id_odt) doc_c = document_client1._getOb(id_odt)
kw = {'description':self.description3} kw = {'description':self.description3}
doc_c.edit(**kw) doc_c.edit(**kw)
file = makeFileUpload(self.filename_text) file_ = makeFileUpload(self.filename_text)
doc_c.edit(file=file) doc_c.edit(file=file_)
self.tic() self.tic()
self.synchronize(self.sub_id1) self.synchronize(self.sub_id1)
self.checkSynchronizationStateIsSynchronized() self.checkSynchronizationStateIsSynchronized()
...@@ -691,8 +692,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin): ...@@ -691,8 +692,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin):
document_s = document_server._getOb(self.id1) document_s = document_server._getOb(self.id1)
kw = {'description': self.description2, 'short_title': self.short_title2 } kw = {'description': self.description2, 'short_title': self.short_title2 }
document_s.edit(**kw) document_s.edit(**kw)
file = makeFileUpload(self.filename_ppt) file_ = makeFileUpload(self.filename_ppt)
document_s.edit(file=file) document_s.edit(file=file_)
self.tic() self.tic()
# Modify on client side # Modify on client side
...@@ -700,8 +701,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin): ...@@ -700,8 +701,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin):
document_c1 = document_client1._getOb(self.id1) document_c1 = document_client1._getOb(self.id1)
kw = {'description': self.description3, 'short_title': self.short_title3 } kw = {'description': self.description3, 'short_title': self.short_title3 }
document_c1.edit(**kw) document_c1.edit(**kw)
file = makeFileUpload(self.filename_odt) file_ = makeFileUpload(self.filename_odt)
document_c1.edit(file=file) document_c1.edit(file=file_)
self.tic() self.tic()
self.synchronize(self.sub_id1) self.synchronize(self.sub_id1)
...@@ -821,8 +822,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin): ...@@ -821,8 +822,8 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin):
self.assertXMLViewIsEqual(self.sub_id_from_server, document_s, document_c, force=1) self.assertXMLViewIsEqual(self.sub_id_from_server, document_s, document_c, force=1)
# Then we change things on both sides and we look if there # Then we change things on both sides and we look if there
# is synchronization from only one way # is synchronization from only one way
file = makeFileUpload(self.filename_odt) file_ = makeFileUpload(self.filename_odt)
document_c.edit(file=file) document_c.edit(file=file_)
kw = {'short_title' : self.short_title2} kw = {'short_title' : self.short_title2}
document_s.edit(**kw) document_s.edit(**kw)
...@@ -854,6 +855,6 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin): ...@@ -854,6 +855,6 @@ class TestERP5DocumentSyncML(TestERP5DocumentSyncMLMixin):
ignore_processing_status_workflow=True) ignore_processing_status_workflow=True)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestERP5DocumentSyncML)) suite.addTest(unittest.makeSuite(TestERP5DocumentSyncML))
return suite return suite
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Test Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testERP5DocumentSyncML</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.tests.testERP5DocumentSyncML</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testERP5DocumentSyncML</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Test Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -35,14 +35,13 @@ from unittest import expectedFailure ...@@ -35,14 +35,13 @@ from unittest import expectedFailure
from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import newSecurityManager
from ERP5Diff import ERP5Diff from ERP5Diff import ERP5Diff
from Products.ERP5Type.tests.runUnitTest import tests_home from erp5.component.module.ERP5Conduit import ERP5Conduit
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.XMLSyncUtils import encode, decode,\
from Products.ERP5SyncML.XMLSyncUtils import encode, decode,\
isDecodeEncodeTheSame isDecodeEncodeTheSame
from Products.ERP5SyncML.XMLSyncUtils import getConduitByName from erp5.component.module.XMLSyncUtils import getConduitByName
from Products.ERP5SyncML.SyncMLConstant import MAX_LEN from erp5.component.module.SyncMLConstant import MAX_LEN
from Products.ERP5SyncML.Document import SyncMLSubscription from erp5.component.document import SyncMLSubscription
from Products.ERP5SyncML.tests.testERP5SyncMLMixin import TestERP5SyncMLMixin \ from erp5.component.module.testERP5SyncMLMixin import TestERP5SyncMLMixin \
as TestMixin as TestMixin
class TestERP5SyncMLMixin(TestMixin): class TestERP5SyncMLMixin(TestMixin):
...@@ -83,12 +82,6 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -83,12 +82,6 @@ class TestERP5SyncMLMixin(TestMixin):
nb_synchronization = 3 nb_synchronization = 3
nb_message_first_synchronization = 6 nb_message_first_synchronization = 6
nb_message_first_sync_max_lines = 16 nb_message_first_sync_max_lines = 16
_subscription_url1 = tests_home + '/sync_client1'
_subscription_url2 = tests_home + '/sync_client2'
_publication_url = tests_home + '/sync_server'
subscription_url1 = 'file:/' + _subscription_url1
subscription_url2 = 'file:/' + _subscription_url2
publication_url = 'file:/' + _publication_url
activity_enabled = False activity_enabled = False
...@@ -104,6 +97,14 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -104,6 +97,14 @@ class TestERP5SyncMLMixin(TestMixin):
# allow anything inside Person (we'll cleanup on teardown) # allow anything inside Person (we'll cleanup on teardown)
self.getTypesTool().getTypeInfo('Person').filter_content_types = 0 self.getTypesTool().getTypeInfo('Person').filter_content_types = 0
from Products.ERP5Type.tests.runUnitTest import tests_home
self._subscription_url1 = tests_home + '/sync_client1'
self._subscription_url2 = tests_home + '/sync_client2'
self._publication_url = tests_home + '/sync_server'
self.subscription_url1 = 'file:/' + self._subscription_url1
self.subscription_url2 = 'file:/' + self._subscription_url2
self.publication_url = 'file:/' + self._publication_url
def beforeTearDown(self): def beforeTearDown(self):
"""Clean up.""" """Clean up."""
self.getTypesTool().getTypeInfo('Person').filter_content_types = 1 self.getTypesTool().getTypeInfo('Person').filter_content_types = 1
...@@ -132,7 +133,7 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -132,7 +133,7 @@ class TestERP5SyncMLMixin(TestMixin):
def getPersonClient2(self): def getPersonClient2(self):
return getattr(self.getPortalObject(), 'person_client2', None) return getattr(self.getPortalObject(), 'person_client2', None)
def login(self): def login(self, *args, **kw):
uf = self.getPortal().acl_users uf = self.getPortal().acl_users
uf._doAddUser('fab', 'myPassword', ['Manager'], []) uf._doAddUser('fab', 'myPassword', ['Manager'], [])
uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], []) uf._doAddUser('ERP5TypeTestCase', '', ['Manager'], [])
...@@ -180,9 +181,9 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -180,9 +181,9 @@ class TestERP5SyncMLMixin(TestMixin):
self.initPersonModule() self.initPersonModule()
person_client = self.getPersonClient1() person_client = self.getPersonClient1()
number_of_object = 60 number_of_object = 60
for id in range(1, number_of_object+1): for id_ in range(1, number_of_object+1):
person_client.newContent(portal_type='Person', person_client.newContent(portal_type='Person',
id=id, id=id_,
first_name=self.first_name1, first_name=self.first_name1,
last_name=self.last_name1, last_name=self.last_name1,
description=self.description1) description=self.description1)
...@@ -193,17 +194,17 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -193,17 +194,17 @@ class TestERP5SyncMLMixin(TestMixin):
def clearFiles(self): def clearFiles(self):
# reset files, because we do sync by files # reset files, because we do sync by files
file = open(self._subscription_url1, 'w') file_ = open(self._subscription_url1, 'w')
file.write('') file_.write('')
file.close() file_.close()
file = open(self._subscription_url2, 'w') file_ = open(self._subscription_url2, 'w')
file.write('') file_.write('')
file.close() file_.close()
file = open(self._publication_url, 'w') file_ = open(self._publication_url, 'w')
file.write('') file_.write('')
file.close() file_.close()
def synchronize(self, id): def synchronize(self, id): # pylint: disable=redefined-builtin
""" """
This just define how we synchronize, we have This just define how we synchronize, we have
to define it here because it is specific to the unit testing to define it here because it is specific to the unit testing
...@@ -233,7 +234,7 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -233,7 +234,7 @@ class TestERP5SyncMLMixin(TestMixin):
self.tic() self.tic()
return nb_message return nb_message
def synchronizeWithBrokenMessage(self, id): def synchronizeWithBrokenMessage(self, id): # pylint: disable=redefined-builtin
""" """
This just define how we synchronize, we have This just define how we synchronize, we have
to define it here because it is specific to the unit testing to define it here because it is specific to the unit testing
...@@ -254,7 +255,7 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -254,7 +255,7 @@ class TestERP5SyncMLMixin(TestMixin):
# only first call will return an answer # only first call will return an answer
result = portal_sync.processServerSynchronization(publication.getPath()) result = portal_sync.processServerSynchronization(publication.getPath())
self.tic() self.tic()
for x in xrange(2): for _ in xrange(2):
portal_sync.processServerSynchronization(publication.getPath()) portal_sync.processServerSynchronization(publication.getPath())
self.tic() self.tic()
nb_message += 1 nb_message += 1
...@@ -262,7 +263,7 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -262,7 +263,7 @@ class TestERP5SyncMLMixin(TestMixin):
break break
result = portal_sync.processClientSynchronization(subscription.getPath()) result = portal_sync.processClientSynchronization(subscription.getPath())
self.tic() self.tic()
for x in xrange(2): for _ in xrange(2):
portal_sync.processClientSynchronization(subscription.getPath()) portal_sync.processClientSynchronization(subscription.getPath())
self.tic() self.tic()
nb_message += 1 nb_message += 1
...@@ -365,7 +366,7 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -365,7 +366,7 @@ class TestERP5SyncMLMixin(TestMixin):
self.assertEqual(person_client.getFirstName(), first_name) self.assertEqual(person_client.getFirstName(), first_name)
self.assertEqual(person_client.getLastName(), last_name) self.assertEqual(person_client.getLastName(), last_name)
def checkFirstSynchronization(self, id=None, nb_person=0): def checkFirstSynchronization(self, id=None, nb_person=0): # pylint: disable=redefined-builtin
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
subscription1 = portal_sync[self.sub_id1] subscription1 = portal_sync[self.sub_id1]
...@@ -451,7 +452,7 @@ class TestERP5SyncMLMixin(TestMixin): ...@@ -451,7 +452,7 @@ class TestERP5SyncMLMixin(TestMixin):
def deletePublicationAndSubscriptionList(self): def deletePublicationAndSubscriptionList(self):
portal_sync = self.getSynchronizationTool() portal_sync = self.getSynchronizationTool()
id_list = [id for id in portal_sync.objectIds()] id_list = [id_ for id_ in portal_sync.objectIds()]
portal_sync.manage_delObjects(id_list) portal_sync.manage_delObjects(id_list)
class TestERP5SyncML(TestERP5SyncMLMixin): class TestERP5SyncML(TestERP5SyncMLMixin):
...@@ -1153,13 +1154,13 @@ return [context[%r]] ...@@ -1153,13 +1154,13 @@ return [context[%r]]
for conflict in conflict_list : for conflict in conflict_list :
subscriber = conflict.getSubscriber() subscriber = conflict.getSubscriber()
property = conflict.getPropertyId() property_id = conflict.getPropertyId()
resolve = 0 resolve = 0
if property == 'language': if property_id == 'language':
if subscriber.getUrlString() == self.subscription_url1: if subscriber.getUrlString() == self.subscription_url1:
resolve = 1 resolve = 1
conflict.applySubscriberValue() conflict.applySubscriberValue()
if property == 'format': if property_id == 'format':
if subscriber.getUrlString() == self.subscription_url2: if subscriber.getUrlString() == self.subscription_url2:
resolve = 1 resolve = 1
conflict.applySubscriberValue() conflict.applySubscriberValue()
...@@ -1261,7 +1262,7 @@ return [context[%r]] ...@@ -1261,7 +1262,7 @@ return [context[%r]]
If we want to make this test more intersting, it is If we want to make this test more intersting, it is
better to split messages better to split messages
""" """
from Products.ERP5SyncML import SyncMLConstant from erp5.component.module import SyncMLConstant
previous_max_lines = SyncMLConstant.MAX_LEN previous_max_lines = SyncMLConstant.MAX_LEN
try: try:
SyncMLConstant.MAX_LEN = 1 << 8 SyncMLConstant.MAX_LEN = 1 << 8
...@@ -1875,15 +1876,15 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA==" ...@@ -1875,15 +1876,15 @@ wuIFtde33Dp3NkZl9fc2Rmw6fDp8OnX2RmX19fJibDqV1dXcKwwrDCsMKwwrDCsA=="
self.assertEqual(nb_person, len(person_client1.objectValues())) self.assertEqual(nb_person, len(person_client1.objectValues()))
self.assertEqual(nb_person, len(person_client2.objectValues())) self.assertEqual(nb_person, len(person_client2.objectValues()))
for id in range(1, 60): for id_ in range(1, 60):
person_s = person_server._getOb(str(id)) person_s = person_server._getOb(str(id_))
person_c1 = person_client1._getOb(str(id)) person_c1 = person_client1._getOb(str(id_))
person_c2 = person_client2._getOb(str(id)) person_c2 = person_client2._getOb(str(id_))
self.assertXMLViewIsEqual(self.sub_id1, person_s, person_c1) self.assertXMLViewIsEqual(self.sub_id1, person_s, person_c1)
self.assertXMLViewIsEqual(self.sub_id1, person_s, person_c2) self.assertXMLViewIsEqual(self.sub_id1, person_s, person_c2)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestERP5SyncML)) suite.addTest(unittest.makeSuite(TestERP5SyncML))
return suite return suite
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Test Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testERP5SyncML</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.tests.testERP5SyncML</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testERP5SyncML</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Test Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
# #
############################################################################## ##############################################################################
from testERP5SyncML import TestERP5SyncMLMixin from erp5.component.test.testERP5SyncML import TestERP5SyncMLMixin
class TestERP5SyncMLVCard(TestERP5SyncMLMixin): class TestERP5SyncMLVCard(TestERP5SyncMLMixin):
...@@ -43,10 +43,6 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin): ...@@ -43,10 +43,6 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin):
""" """
return ('erp5_base', 'erp5_syncml',) return ('erp5_base', 'erp5_syncml',)
def afterSetUp(self):
self.portal.z_drop_syncml()
self.portal.z_create_syncml()
def getTitle(self): def getTitle(self):
return 'testERP5SyncMLVCard' return 'testERP5SyncMLVCard'
...@@ -106,7 +102,6 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin): ...@@ -106,7 +102,6 @@ class TestERP5SyncMLVCard(TestERP5SyncMLMixin):
def test_04_FirstVCardSynchronization(self): def test_04_FirstVCardSynchronization(self):
# We will try to populate the folder person_client1 # We will try to populate the folder person_client1
# with the data form person_server # with the data form person_server
self.login()
self.deletePublicationAndSubscriptionList() self.deletePublicationAndSubscriptionList()
if 'person_server' in self.portal.objectIds(): if 'person_server' in self.portal.objectIds():
self.portal._delObject('person_server') self.portal._delObject('person_server')
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Test Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testERP5SyncMLVCard</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.tests.testERP5SyncMLVCard</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testERP5SyncMLVCard</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Test Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -33,11 +33,11 @@ from AccessControl import ClassSecurityInfo ...@@ -33,11 +33,11 @@ from AccessControl import ClassSecurityInfo
from Products.ERP5Type.Tool.BaseTool import BaseTool from Products.ERP5Type.Tool.BaseTool import BaseTool
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type.Globals import InitializeClass from Products.ERP5Type.Globals import InitializeClass
from Products.ERP5SyncML.SyncMLConstant import ACTIVITY_PRIORITY, \ from erp5.component.module.SyncMLConstant import ACTIVITY_PRIORITY, \
SynchronizationError SynchronizationError
from Products.ERP5SyncML.SyncMLMessage import SyncMLRequest from erp5.component.module.SyncMLMessage import SyncMLRequest
from Products.ERP5SyncML.Engine.SynchronousEngine import SyncMLSynchronousEngine from erp5.component.module.SyncMLEngineSynchronous import SyncMLSynchronousEngine
from Products.ERP5SyncML.Engine.AsynchronousEngine import SyncMLAsynchronousEngine from erp5.component.module.SyncMLEngineAsynchronous import SyncMLAsynchronousEngine
from Products.ERP5.ERP5Site import getSite from Products.ERP5.ERP5Site import getSite
synchronous_engine = SyncMLSynchronousEngine() synchronous_engine = SyncMLSynchronousEngine()
...@@ -211,7 +211,7 @@ class SynchronizationTool(BaseTool): ...@@ -211,7 +211,7 @@ class SynchronizationTool(BaseTool):
We will look at the url and we will see if we need to send mail, http We will look at the url and we will see if we need to send mail, http
response, or just copy to a file. response, or just copy to a file.
""" """
syncml_logger.info('readResponse sync_id %s, text %s' % (sync_id, text)) syncml_logger.info('readResponse sync_id %s, text %s', sync_id, text)
if text: if text:
# we are still anonymous at this time, use unrestrictedSearchResults # we are still anonymous at this time, use unrestrictedSearchResults
# to fetch the Subcribers # to fetch the Subcribers
...@@ -270,7 +270,7 @@ class SynchronizationTool(BaseTool): ...@@ -270,7 +270,7 @@ class SynchronizationTool(BaseTool):
else: else:
xml = stream.read() xml = stream.read()
stream.close() stream.close()
syncml_logger.debug('readResponse xml from file is %s' % (xml,)) syncml_logger.debug('readResponse xml from file is %s', xml)
if xml: if xml:
return xml return xml
# #
...@@ -313,8 +313,8 @@ class SynchronizationTool(BaseTool): ...@@ -313,8 +313,8 @@ class SynchronizationTool(BaseTool):
if subscriber and subscriber.getSynchronizationState() not in \ if subscriber and subscriber.getSynchronizationState() not in \
("not_running", "initializing", "finished"): ("not_running", "initializing", "finished"):
syncml_logger.error( syncml_logger.error(
'Trying to start a synchronization on server side : %s although synchronisation is already running' 'Trying to start a synchronization on server side : %s although synchronisation is already running',
% (subscriber.getPath(),)) subscriber.getPath())
# Prevent initilisation if sync already running # Prevent initilisation if sync already running
return return
syncml_response = engine.processServerInitialization( syncml_response = engine.processServerInitialization(
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Tool Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>SynchronizationTool</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5SyncML.Tool.SynchronizationTool</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>tool.erp5.SynchronizationTool</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Tool Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
document.erp5.SyncMLConflict
document.erp5.SyncMLPublication
document.erp5.SyncMLSignature
document.erp5.SyncMLSubscription
\ No newline at end of file
interface.erp5.IConduit
\ No newline at end of file
mixin.erp5.SyncMLEngineMixin
\ No newline at end of file
module.erp5.SyncMLEngineAsynchronous
module.erp5.BaseConduit
module.erp5.ERP5Conduit
module.erp5.ERP5ConduitTitleGid
module.erp5.ERP5DocumentConduit
module.erp5.ERP5ShopOrderConduit
module.erp5.SyncMLTransportERP5
module.erp5.SyncMLTransportFile
module.erp5.SyncMLTransportHTTP
module.erp5.SyncMLTransportMail
module.erp5.SharedVCardConduit
module.erp5.SyncMLConstant
module.erp5.SyncMLMessage
module.erp5.SyncMLUtils
module.erp5.SyncMLEngineSynchronous
module.erp5.VCardConduit
module.erp5.XMLSyncUtils
module.erp5.XupdateUtils
module.erp5.testERP5SyncMLMixin
\ No newline at end of file
test.erp5.testERP5DocumentSyncML
test.erp5.testERP5SyncML
test.erp5.testERP5SyncMLVCard
\ No newline at end of file
tool.erp5.SynchronizationTool
\ No newline at end of file
erp5_full_text_mroonga_catalog
erp5_core_proxy_field_legacy
erp5_base
erp5_ingestion
erp5_ingestion_mysql_innodb_catalog
erp5_web
erp5_dms
\ No newline at end of file
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
############################################################################## ##############################################################################
from Products.ERP5SyncML.tests.testERP5SyncMLMixin import TestERP5SyncMLMixin from erp5.component.module.testERP5SyncMLMixin import TestERP5SyncMLMixin
class testSyncMLAsynchronousEngine(TestERP5SyncMLMixin): class testSyncMLAsynchronousEngine(TestERP5SyncMLMixin):
......
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
# #
############################################################################## ##############################################################################
from Products.ERP5SyncML.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST, \ from erp5.component.module.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST, \
XUPDATE_DEL, XUPDATE_UPDATE XUPDATE_DEL, XUPDATE_UPDATE
from Products.ERP5Type.XMLExportImport import MARSHALLER_NAMESPACE_URI from Products.ERP5Type.XMLExportImport import MARSHALLER_NAMESPACE_URI
from zLOG import LOG, INFO from zLOG import LOG, INFO
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.ERP5Conduit import ERP5Conduit
from lxml import etree from lxml import etree
from copy import deepcopy from copy import deepcopy
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
class TioSafeDoNothingConduit(TioSafeBaseConduit): class TioSafeDoNothingConduit(TioSafeBaseConduit):
""" """
......
...@@ -27,8 +27,8 @@ ...@@ -27,8 +27,8 @@
# #
############################################################################## ##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
from Products.ERP5SyncML.Document.SyncMLConflict import SyncMLConflict as Conflict from erp5.component.document.SyncMLConflict import SyncMLConflict as Conflict
from lxml import etree from lxml import etree
class TioSafeNodeConduit(TioSafeBaseConduit): class TioSafeNodeConduit(TioSafeBaseConduit):
......
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
############################################################################## ##############################################################################
from Products.ERP5Type.Utils import cartesianProduct from Products.ERP5Type.Utils import cartesianProduct
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
from Products.ERP5SyncML.Document.SyncMLConflict import SyncMLConflict as Conflict from erp5.component.document.SyncMLConflict import SyncMLConflict as Conflict
from lxml import etree from lxml import etree
from zLOG import LOG from zLOG import LOG
class TioSafeResourceConduit(TioSafeBaseConduit): class TioSafeResourceConduit(TioSafeBaseConduit):
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
############################################################################## ##############################################################################
from lxml import etree from lxml import etree
from Products.ERP5SyncML.XMLSyncUtils import getConduitByName from erp5.component.module.XMLSyncUtils import getConduitByName
from difflib import unified_diff from difflib import unified_diff
from Products.ERP5Type.DiffUtils import DiffFile from Products.ERP5Type.DiffUtils import DiffFile
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
class AccountERP5IntegrationConduit(TioSafeBaseConduit): class AccountERP5IntegrationConduit(TioSafeBaseConduit):
""" """
...@@ -34,7 +34,7 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -34,7 +34,7 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit):
def __init__(self): def __init__(self):
self.xml_object_tag = 'node' self.xml_object_tag = 'node'
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
Return the Account GID of the object. Return the Account GID of the object.
""" """
...@@ -46,7 +46,7 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -46,7 +46,7 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit):
""" """
return 'Account' return 'Account'
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, # pylint: disable=redefined-builtin
reset_local_roles=0, reset_workflow=0, simulate=0, **kw): reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
""" """
This is the method calling to create an object This is the method calling to create an object
...@@ -73,7 +73,7 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -73,7 +73,7 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit):
# Browse the list of arrows and movements # Browse the list of arrows and movements
for node in xml.getchildren(): for node in xml.getchildren():
# Only works on right tags, and no on the comments, ... # Only works on right tags, and no on the comments, ...
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
# Build the split list of a tag to test the namespace # Build the split list of a tag to test the namespace
split_tag = node.tag.split('}') split_tag = node.tag.split('}')
...@@ -101,15 +101,15 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -101,15 +101,15 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit):
) )
return sub_object return sub_object
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, def updateNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception("updateNode: Impossible to update Account") raise Exception("updateNode: Impossible to update Account")
def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception("deleteNode: Impossible to delete Account") raise Exception("deleteNode: Impossible to delete Account")
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the editDocument method inherit of ERP5Conduit. This method This is the editDocument method inherit of ERP5Conduit. This method
is used to save the information of a Account. is used to save the information of a Account.
...@@ -119,9 +119,8 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -119,9 +119,8 @@ class AccountERP5IntegrationConduit(TioSafeBaseConduit):
mapping = {'title': 'title', mapping = {'title': 'title',
'description': 'description'} 'description': 'description'}
# Translate kw with the PropertySheet # Translate kw with the PropertySheet
property = {} property_ = {}
for k, v in kw.items(): for k, v in kw.items():
k = mapping.get(k, k) k = mapping.get(k, k)
property[k] = v property_[k] = v
object._edit(**property) object._edit(**property_)
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>AccountERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.AccountERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.AccountERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
from base64 import b16encode from base64 import b16encode
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
class AccountingERP5IntegrationConduit(TioSafeBaseConduit): class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
""" """
...@@ -36,7 +36,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -36,7 +36,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
def __init__(self): def __init__(self):
self.xml_object_tag = 'transaction' self.xml_object_tag = 'transaction'
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
Return the Accounting GID of the object. Return the Accounting GID of the object.
""" """
...@@ -66,7 +66,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -66,7 +66,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
# Browse the list of categories # Browse the list of categories
for node in categories: for node in categories:
if 'Journal' in node.text: if 'Journal' in node.text:
journal = node.text.split('/')[1] journal = node.text.split('/')[1]
# Check by the name which portal type must be returns # Check by the name which portal type must be returns
if journal in ('JC', 'JD'): if journal in ('JC', 'JD'):
return 'Accounting Transaction' return 'Accounting Transaction'
...@@ -79,9 +79,8 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -79,9 +79,8 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
return 'Payment Transaction' return 'Payment Transaction'
else: else:
raise "getObjectType: ERROR journal code unknow" raise "getObjectType: ERROR journal code unknow"
return
def constructContent(self, object, object_id, portal_type): def constructContent(self, object, object_id, portal_type): # pylint: disable=redefined-builtin
""" """
This allows to specify how to construct a new content. This allows to specify how to construct a new content.
This is really usefull if you want to write your own Conduit. This is really usefull if you want to write your own Conduit.
...@@ -95,7 +94,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -95,7 +94,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
subobject = object._getOb(object_id) subobject = object._getOb(object_id)
return subobject, 1, 1 return subobject, 1, 1
def _createContent(self, xml=None, object=None, object_id=None, def _createContent(self, xml=None, object=None, object_id=None, # pylint: disable=redefined-builtin
sub_object=None, reset_local_roles=0, reset_workflow=0, simulate=0, sub_object=None, reset_local_roles=0, reset_workflow=0, simulate=0,
**kw): **kw):
""" """
...@@ -126,7 +125,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -126,7 +125,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
# Browse the list to work on categories # Browse the list to work on categories
for node in xml.getchildren(): for node in xml.getchildren():
# Only works on right tags, and no on the comments, ... # Only works on right tags, and no on the comments, ...
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
# Build the split list of the tag # Build the split list of the tag
split_tag = node.tag.split('}') split_tag = node.tag.split('}')
...@@ -221,7 +220,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -221,7 +220,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
# Browse the XML subnode # Browse the XML subnode
for subnode in xml.getchildren(): for subnode in xml.getchildren():
# Only works on right tags, and no on the comments, ... # Only works on right tags, and no on the comments, ...
if type(subnode.tag) is not str: if not isinstance(subnode.tag, str):
continue continue
tag = subnode.tag.split('}')[index] tag = subnode.tag.split('}')[index]
# Check the usefull of the different elements # Check the usefull of the different elements
...@@ -236,7 +235,6 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -236,7 +235,6 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
else: else:
if subnode.text: if subnode.text:
# Retrieve the object to bind # Retrieve the object to bind
instance = document.getPortalObject()
subscriber = arrow_dict[tag]['sync'] subscriber = arrow_dict[tag]['sync']
# Encode to the output type # Encode to the output type
link_gid = subnode.text link_gid = subnode.text
...@@ -280,7 +278,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -280,7 +278,7 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
# Browse the XML subnode # Browse the XML subnode
for subnode in xml.getchildren(): for subnode in xml.getchildren():
# Only works on right tags, and no on the comments, ... # Only works on right tags, and no on the comments, ...
if type(subnode.tag) is not str: if not isinstance(subnode.tag, str):
continue continue
tag = subnode.tag.split('}')[index] tag = subnode.tag.split('}')[index]
# Check the usefull of the different elements # Check the usefull of the different elements
...@@ -298,15 +296,15 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -298,15 +296,15 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
elif tag == "quantity": elif tag == "quantity":
accounting_line.setQuantity(subnode.text) accounting_line.setQuantity(subnode.text)
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, def updateNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception("updateNode: Impossible to delete Accounting") raise Exception("updateNode: Impossible to delete Accounting")
def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception("deleteNode: Impossible to delete Accounting") raise Exception("deleteNode: Impossible to delete Accounting")
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the editDocument method inherit of ERP5Conduit. This method This is the editDocument method inherit of ERP5Conduit. This method
is used to save the information of a Accounting. is used to save the information of a Accounting.
...@@ -322,9 +320,8 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -322,9 +320,8 @@ class AccountingERP5IntegrationConduit(TioSafeBaseConduit):
'reference': 'reference', 'reference': 'reference',
} }
# Translate kw with the PropertySheet # Translate kw with the PropertySheet
property = {} property_ = {}
for k, v in kw.items(): for k, v in kw.items():
k = mapping.get(k, k) k = mapping.get(k, k)
property[k] = v property_[k] = v
object._edit(**property) object._edit(**property_)
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>AccountingERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.AccountingERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.AccountingERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit, \ from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit, \
ADDRESS_TAG_LIST ADDRESS_TAG_LIST
from DateTime import DateTime from DateTime import DateTime
from lxml import etree from lxml import etree
...@@ -45,10 +45,10 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -45,10 +45,10 @@ class ERP5NodeConduit(TioSafeBaseConduit):
def __init__(self): def __init__(self):
self.xml_object_tag = 'node' self.xml_object_tag = 'node'
def getObjectAsXML(self, object, domain): def getObjectAsXML(self, object, domain): # pylint: disable=redefined-builtin
return object.Node_asTioSafeXML(context_document=domain) return object.Node_asTioSafeXML(context_document=domain)
def _createSaleTradeCondition(self, object, **kw): def _createSaleTradeCondition(self, object, **kw): # pylint: disable=redefined-builtin
""" Link person to a sale trade condition so that """ Link person to a sale trade condition so that
we can filter person based on the plugin they came from we can filter person based on the plugin they came from
""" """
...@@ -64,7 +64,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -64,7 +64,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
version=001) version=001)
stc.validate() stc.validate()
def _updateSaleTradeCondition(self, object, **kw): def _updateSaleTradeCondition(self, object, **kw): # pylint: disable=redefined-builtin
""" Link person to a sale trade condition so that """ Link person to a sale trade condition so that
we can filter person based on the plugin they came from we can filter person based on the plugin they came from
""" """
...@@ -86,7 +86,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -86,7 +86,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
destination_decision=object.getRelativeUrl(), destination_decision=object.getRelativeUrl(),
destination_administration=object.getRelativeUrl(),) destination_administration=object.getRelativeUrl(),)
def _deleteSaleTradeCondition(self, object, **kw): def _deleteSaleTradeCondition(self, object, **kw): # pylint: disable=redefined-builtin
""" Unvalidate sale trade condition so that """ Unvalidate sale trade condition so that
we can filter person based on the plugin they came from we can filter person based on the plugin they came from
""" """
...@@ -96,7 +96,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -96,7 +96,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
stc = stc_list[0].getObject() stc = stc_list[0].getObject()
stc.invalidate() stc.invalidate()
def afterCreateMethod(self, object, **kw): def afterCreateMethod(self, object, **kw): # pylint: disable=redefined-builtin
""" This method is for actions that has to be done just after object """ This method is for actions that has to be done just after object
creation and which required to have synchronization parameters creation and which required to have synchronization parameters
...@@ -105,7 +105,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -105,7 +105,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
""" """
self._createSaleTradeCondition(object, **kw) self._createSaleTradeCondition(object, **kw)
def afterUpdateMethod(self, object, **kw): def afterUpdateMethod(self, object, **kw): # pylint: disable=redefined-builtin
""" This method is for actions that has to be done just after object """ This method is for actions that has to be done just after object
update and which required to have synchronization parameters update and which required to have synchronization parameters
...@@ -114,7 +114,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -114,7 +114,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
""" """
self._updateSaleTradeCondition(object, **kw) self._updateSaleTradeCondition(object, **kw)
def afterDeleteMethod(self, object, **kw): def afterDeleteMethod(self, object, **kw): # pylint: disable=redefined-builtin
""" This method is for actions that has to be done just after object """ This method is for actions that has to be done just after object
has been deleted and which required to have synchronization parameters has been deleted and which required to have synchronization parameters
...@@ -123,7 +123,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -123,7 +123,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
""" """
self._deleteSaleTradeCondition(object, **kw) self._deleteSaleTradeCondition(object, **kw)
def afterNewObject(self, object): def afterNewObject(self, object): # pylint: disable=redefined-builtin
""" Realise actions after new object creation. """ """ Realise actions after new object creation. """
object.validate() object.validate()
object.updateLocalRolesOnSecurityGroups() object.updateLocalRolesOnSecurityGroups()
...@@ -159,7 +159,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -159,7 +159,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
document.reindexObject() document.reindexObject()
return [] return []
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, # pylint: disable=redefined-builtin
reset_local_roles=0, reset_workflow=0, simulate=0, **kw): reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
""" This is the method calling to create an object. """ """ This is the method calling to create an object. """
# if DEBUG: # if DEBUG:
...@@ -187,14 +187,13 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -187,14 +187,13 @@ class ERP5NodeConduit(TioSafeBaseConduit):
relation = None relation = None
category_list = [] category_list = []
role_list =[] role_list =[]
relation_data_dict = {}
address_tag_mapping = {"street" : "street_address", address_tag_mapping = {"street" : "street_address",
"zip" : "zip_code", "zip" : "zip_code",
"country" : "region",} "country" : "region",}
address_int_index = 0 address_int_index = 0
for node in xml.getchildren(): for node in xml.getchildren():
# works on tags, no on comments # works on tags, no on comments
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
tag = node.tag.split('}')[index] tag = node.tag.split('}')[index]
...@@ -216,7 +215,7 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -216,7 +215,7 @@ class ERP5NodeConduit(TioSafeBaseConduit):
# Build dict of address properties # Build dict of address properties
address_data_dict = {} address_data_dict = {}
for element in node.getchildren(): for element in node.getchildren():
if type(element.tag) is not str: if not isinstance(element.tag, str):
continue continue
element_tag = element.tag.split('}')[index] element_tag = element.tag.split('}')[index]
address_data_dict[address_tag_mapping.get(element_tag, element_tag)] = element.text address_data_dict[address_tag_mapping.get(element_tag, element_tag)] = element.text
...@@ -291,11 +290,11 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -291,11 +290,11 @@ class ERP5NodeConduit(TioSafeBaseConduit):
return sub_object return sub_object
def _deleteContent(self, object=None, object_id=None, **kw): def _deleteContent(self, object=None, object_id=None, **kw): # pylint: disable=redefined-builtin
""" We do not delete nodes """ """ We do not delete nodes """
self.afterDeleteMethod(object[object_id]) self.afterDeleteMethod(object[object_id])
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" This editDocument method allows to set attributes of the object. """ """ This editDocument method allows to set attributes of the object. """
# if DEBUG: # if DEBUG:
# LOG("ERP5NodeConduit.editDocument", INFO, "object = %s with %s" %(object.getPath(), kw)) # LOG("ERP5NodeConduit.editDocument", INFO, "object = %s with %s" %(object.getPath(), kw))
...@@ -320,11 +319,11 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -320,11 +319,11 @@ class ERP5NodeConduit(TioSafeBaseConduit):
'country': 'region', 'country': 'region',
} }
# translate kw with the good PropertySheet # translate kw with the good PropertySheet
property = {} property_ = {}
for k, v in kw.items(): for k, v in kw.items():
k = mapping.get(k, k) k = mapping.get(k, k)
property[k] = v property_[k] = v
object._edit(**property) object._edit(**property_)
def checkAddressConflict(self, document, tag, xml, previous_value, new_value, signature): def checkAddressConflict(self, document, tag, xml, previous_value, new_value, signature):
""" """
...@@ -390,7 +389,6 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -390,7 +389,6 @@ class ERP5NodeConduit(TioSafeBaseConduit):
xpath_expression = xml.get('select') xpath_expression = xml.get('select')
tag = xpath_expression.split('/')[-1] tag = xpath_expression.split('/')[-1]
new_value = xml.text.encode('utf-8') new_value = xml.text.encode('utf-8')
keyword = {}
# retrieve the previous xml etree through xpath # retrieve the previous xml etree through xpath
selected_previous_xml = previous_xml.xpath(xpath_expression) selected_previous_xml = previous_xml.xpath(xpath_expression)
...@@ -417,7 +415,6 @@ class ERP5NodeConduit(TioSafeBaseConduit): ...@@ -417,7 +415,6 @@ class ERP5NodeConduit(TioSafeBaseConduit):
tag = xml.get('select').split('/')[-1] tag = xml.get('select').split('/')[-1]
# this variable is used to retrieve the id of address and to not remove the # this variable is used to retrieve the id of address and to not remove the
# orginal tag (address, street, zip, city or country) # orginal tag (address, street, zip, city or country)
keyword = {}
# retrieve the previous xml etree through xpath # retrieve the previous xml etree through xpath
xpath_expression = xml.get('select') xpath_expression = xml.get('select')
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5NodeConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.ERP5NodeConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5NodeConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -29,12 +29,9 @@ ...@@ -29,12 +29,9 @@
# #
############################################################################## ##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
from Products.ERP5TioSafe.Conduit.ERP5TransactionConduit import ERP5TransactionConduit from erp5.component.module.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST
from Products.ERP5SyncML.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST from zLOG import LOG
from base64 import b16encode
from zLOG import LOG, WARNING
from copy import deepcopy
class ERP5PaymentTransactionConduit(TioSafeBaseConduit): class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
""" """
...@@ -44,18 +41,18 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -44,18 +41,18 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
# Define the object_tag element to add object # Define the object_tag element to add object
self.xml_object_tag = 'transaction' self.xml_object_tag = 'transaction'
def getObjectAsXML(self, object, domain): def getObjectAsXML(self, object, domain): # pylint: disable=redefined-builtin
return object.PaymentTransaction_asTioSafeXML(context_document=domain) return object.PaymentTransaction_asTioSafeXML(context_document=domain)
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, def updateNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception('updateNode: Impossible to update transaction') raise Exception('updateNode: Impossible to update transaction')
def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception('deleteNode: Impossible to delete transaction') raise Exception('deleteNode: Impossible to delete transaction')
def _createSaleTradeCondition(self, object, **kw): def _createSaleTradeCondition(self, object, **kw): # pylint: disable=redefined-builtin
""" Link payment transaction to a sale trade condition so that """ Link payment transaction to a sale trade condition so that
we can filter payment transaction based on the plugin they came from we can filter payment transaction based on the plugin they came from
""" """
...@@ -74,7 +71,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -74,7 +71,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
simulation_state="confirmed"): simulation_state="confirmed"):
transaction = payment_transaction.getObject() transaction = payment_transaction.getObject()
transaction.cancel() transaction.cancel()
#Invalidate the STC #Invalidate the STC
sale_trade_cond.invalidate() sale_trade_cond.invalidate()
...@@ -86,7 +83,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -86,7 +83,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
return stc return stc
def _deleteSaleTradeCondition(self, object, **kw): def _deleteSaleTradeCondition(self, object, **kw): # pylint: disable=redefined-builtin
""" Unvalidate sale trade condition so that """ Unvalidate sale trade condition so that
we can filter payment transaction based on the plugin they came from we can filter payment transaction based on the plugin they came from
""" """
...@@ -95,7 +92,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -95,7 +92,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
for stc in stc_list: for stc in stc_list:
stc.getObject().invalidate() stc.getObject().invalidate()
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, # pylint: disable=redefined-builtin
reset_local_roles=0, reset_workflow=0, simulate=0, **kw): reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
""" """
This is the method calling to create an object This is the method calling to create an object
...@@ -130,7 +127,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -130,7 +127,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
sub_object.setPriceCurrencyValue(link_object) sub_object.setPriceCurrencyValue(link_object)
bank_account_object = integration_site.getDefaultSourcePaymentValue() bank_account_object = integration_site.getDefaultSourcePaymentValue()
sub_object.setDefaultSourcePaymentValue(bank_account_object) sub_object.setDefaultSourcePaymentValue(bank_account_object)
sub_object.setSourceSectionValue(bank_account_object.getParent()) sub_object.setSourceSectionValue(bank_account_object.getParent())
# Mapping between tag and element # Mapping between tag and element
node_dict = { node_dict = {
...@@ -145,10 +142,8 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -145,10 +142,8 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
# Browse the list of arrows and movements # Browse the list of arrows and movements
for node in xml.getchildren(): for node in xml.getchildren():
# Only works on right tags, and no on the comments, ... # Only works on right tags, and no on the comments, ...
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
# Build the slipt list of a tag to test
split_tag = node.tag.split('}')
# Build the tag (without is Namespace) # Build the tag (without is Namespace)
tag = node.tag.split('}')[index] tag = node.tag.split('}')[index]
# Treat sub-element # Treat sub-element
...@@ -178,7 +173,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -178,7 +173,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
return sub_object return sub_object
def afterNewObject(self, object, **kw): def afterNewObject(self, object, **kw): # pylint: disable=redefined-builtin
""" Confirm the payment transaction and, add the grants on this one. """ """ Confirm the payment transaction and, add the grants on this one. """
if object.getPortalType() in ['Payment Transaction',]: if object.getPortalType() in ['Payment Transaction',]:
## first delete default generated accounting transaction line: bank, ## first delete default generated accounting transaction line: bank,
...@@ -200,9 +195,6 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -200,9 +195,6 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
# dictionary of the value of a movement # dictionary of the value of a movement
movement_dict_value = {'category': []} movement_dict_value = {'category': []}
# marker for checking property existency
MARKER = object()
# if exist namespace retrieve only the tag # if exist namespace retrieve only the tag
index = 0 index = 0
if xml.nsmap not in [None, {}]: if xml.nsmap not in [None, {}]:
...@@ -215,7 +207,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -215,7 +207,7 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
# browse the xml and save the sale order line values # browse the xml and save the sale order line values
for subnode in xml.getchildren(): for subnode in xml.getchildren():
# only works on tags, no on the comments or other kind of tag # only works on tags, no on the comments or other kind of tag
if type(subnode.tag) is not str: if not isinstance(subnode.tag, str):
continue continue
tag = subnode.tag.split('}')[index] tag = subnode.tag.split('}')[index]
# set line values in the dict # set line values in the dict
...@@ -241,11 +233,11 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -241,11 +233,11 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
elif key == "price": elif key == "price":
price =float(movement_dict_value[key]) price =float(movement_dict_value[key])
if price > 0: if price > 0:
payment_transaction_line.setSourceCredit(price) payment_transaction_line.setSourceCredit(price)
else: else:
payment_transaction_line.setSourceDebit(-price) payment_transaction_line.setSourceDebit(-price)
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the default editDocument method. This method This is the default editDocument method. This method
can easily be overwritten. can easily be overwritten.
...@@ -258,10 +250,10 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit): ...@@ -258,10 +250,10 @@ class ERP5PaymentTransactionConduit(TioSafeBaseConduit):
'reference': 'reference', 'reference': 'reference',
'causality': 'comment', 'causality': 'comment',
} }
property = {} property_ = {}
# Translate kw with the good PropertySheet # Translate kw with the good PropertySheet
for k, v in kw.items(): for k, v in kw.items():
k = mapping.get(k, k) k = mapping.get(k, k)
property[k] = v property_[k] = v
object._edit(**property) object._edit(**property_)
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5PaymentTransactionConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.ERP5PaymentTransactionConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5PaymentTransactionConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -28,10 +28,9 @@ ...@@ -28,10 +28,9 @@
############################################################################## ##############################################################################
from Products.CMFCore.WorkflowCore import WorkflowException from Products.CMFCore.WorkflowCore import WorkflowException
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
from lxml import etree from lxml import etree
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
from zLOG import LOG
class ERP5ResourceConduit(TioSafeBaseConduit): class ERP5ResourceConduit(TioSafeBaseConduit):
""" """
...@@ -42,10 +41,10 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -42,10 +41,10 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
self.xml_object_tag = 'resource' self.xml_object_tag = 'resource'
self.system_pref = None self.system_pref = None
def getObjectAsXML(self, object, domain): def getObjectAsXML(self, object, domain): # pylint: disable=redefined-builtin
return object.Resource_asTioSafeXML(context_document=domain) return object.Resource_asTioSafeXML(context_document=domain)
def _createContent(self, xml=None, object=None, object_id=None, def _createContent(self, xml=None, object=None, object_id=None, # pylint: disable=redefined-builtin
sub_object=None, reset_local_roles=0, reset_workflow=0, simulate=0, sub_object=None, reset_local_roles=0, reset_workflow=0, simulate=0,
**kw): **kw):
""" """
...@@ -84,10 +83,8 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -84,10 +83,8 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
for node in xml.getchildren(): for node in xml.getchildren():
# Only works on right tags, and no on the comments, ... # Only works on right tags, and no on the comments, ...
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
# Build the split list of the tag
split_tag = node.tag.split('}')
# Build the tag (without is Namespace) # Build the tag (without is Namespace)
tag = node.tag.split('}')[index] tag = node.tag.split('}')[index]
# Treat sub-element # Treat sub-element
...@@ -134,7 +131,6 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -134,7 +131,6 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
# build mapping list here # build mapping list here
mapping_dict = {'category' : [],} mapping_dict = {'category' : [],}
for item in node.getchildren(): for item in node.getchildren():
split_tag = item.tag.split('}')
# Build the tag (without is Namespace) # Build the tag (without is Namespace)
tag = item.tag.split('}')[index] tag = item.tag.split('}')[index]
if tag == "category": if tag == "category":
...@@ -274,11 +270,11 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -274,11 +270,11 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
cat_list.append(base_category) cat_list.append(base_category)
self.system_pref.edit(preferred_product_variation_base_category_list = cat_list) self.system_pref.edit(preferred_product_variation_base_category_list = cat_list)
def afterNewObject(self, object): def afterNewObject(self, object): # pylint: disable=redefined-builtin
object.validate() object.validate()
object.updateLocalRolesOnSecurityGroups() object.updateLocalRolesOnSecurityGroups()
def _deleteContent(self, object=None, object_id=None, **kw): def _deleteContent(self, object=None, object_id=None, **kw): # pylint: disable=redefined-builtin
""" Move the product into "invalidated" state. """ """ Move the product into "invalidated" state. """
document = object.product_module._getOb(object_id) document = object.product_module._getOb(object_id)
# dict which provides the list of transition to move into invalidated state # dict which provides the list of transition to move into invalidated state
...@@ -306,7 +302,7 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -306,7 +302,7 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
if sale_supply.getTitle() == sync_name: if sale_supply.getTitle() == sync_name:
sale_supply.manage_delObjects(ids=[sale_supply_line.getId(),]) sale_supply.manage_delObjects(ids=[sale_supply_line.getId(),])
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the editDocument method inherit of ERP5Conduit. This method This is the editDocument method inherit of ERP5Conduit. This method
is used to save the information of a Product. is used to save the information of a Product.
...@@ -319,11 +315,11 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -319,11 +315,11 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
'description': 'description', 'description': 'description',
} }
# Translate kw with the PropertySheet # Translate kw with the PropertySheet
property = {} property_ = {}
for k, v in kw.items(): for k, v in kw.items():
k = mapping.get(k, k) k = mapping.get(k, k)
property[k] = v property_[k] = v
object._edit(**property) object._edit(**property_)
def _getPropertyMappingCell(self, resource, prop, index): def _getPropertyMappingCell(self, resource, prop, index):
...@@ -404,7 +400,7 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -404,7 +400,7 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
shared_variation = True shared_variation = True
try: try:
# Try to access the category # Try to access the category
category = document.getPortalObject().portal_categories.restrictedTraverse(new_value) document.getPortalObject().portal_categories.restrictedTraverse(new_value)
except KeyError: except KeyError:
# This is an individual variation # This is an individual variation
shared_variation = False shared_variation = False
...@@ -595,12 +591,12 @@ class ERP5ResourceConduit(TioSafeBaseConduit): ...@@ -595,12 +591,12 @@ class ERP5ResourceConduit(TioSafeBaseConduit):
current_value = getter() current_value = getter()
if isinstance(current_value, unicode): if isinstance(current_value, unicode):
current_value = current_value.encode('utf-8') current_value = current_value.encode('utf-8')
if current_value not in [new_value, previous_value]: if current_value not in [new_value, previous_value]: # pylint: disable=undefined-variable
conflict_list.append(self._generateConflict(document.getPhysicalPath(), conflict_list.append(self._generateConflict(document.getPhysicalPath(),
base_tag+'/'+tag, base_tag+'/'+tag,
etree.tostring(xml, encoding='utf-8'), etree.tostring(xml, encoding='utf-8'),
current_value, current_value,
new_value, new_value, # pylint: disable=undefined-variable
kw['signature'])) kw['signature']))
else: else:
setter_id = "set%s" %(tag.capitalize(),) setter_id = "set%s" %(tag.capitalize(),)
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5ResourceConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.ERP5ResourceConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5ResourceConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
from base64 import b16encode from base64 import b16encode
from copy import deepcopy from copy import deepcopy
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
from Products.ERP5SyncML.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST from erp5.component.module.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST
class ERP5TransactionConduit(TioSafeBaseConduit): class ERP5TransactionConduit(TioSafeBaseConduit):
""" """
...@@ -40,20 +40,20 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -40,20 +40,20 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
# Define the object_tag element to add object # Define the object_tag element to add object
self.xml_object_tag = 'transaction' self.xml_object_tag = 'transaction'
def getObjectAsXML(self, object, domain): def getObjectAsXML(self, object, domain): # pylint: disable=redefined-builtin
return object.Transaction_asTioSafeXML(context_document=domain) return object.Transaction_asTioSafeXML(context_document=domain)
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, def updateNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception('updateNode: Impossible to update transaction') raise Exception('updateNode: Impossible to update transaction')
def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception('deleteNode: Impossible to delete transaction') raise Exception('deleteNode: Impossible to delete transaction')
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, # pylint: disable=redefined-builtin
reset_local_roles=0, reset_workflow=0, simulate=0, **kw): reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
""" """
This is the method calling to create an object This is the method calling to create an object
...@@ -96,10 +96,9 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -96,10 +96,9 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
# Browse the list of arrows and movements # Browse the list of arrows and movements
for node in xml.getchildren(): for node in xml.getchildren():
# Only works on right tags, and no on the comments, ... # Only works on right tags, and no on the comments, ...
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
# Build the slipt list of a tag to test # Build the slipt list of a tag to test
split_tag = node.tag.split('}')
# Build the tag (without is Namespace) # Build the tag (without is Namespace)
tag = node.tag.split('}')[index] tag = node.tag.split('}')[index]
# Treat sub-element # Treat sub-element
...@@ -131,7 +130,7 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -131,7 +130,7 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
return sub_object return sub_object
def afterNewObject(self, object): def afterNewObject(self, object): # pylint: disable=redefined-builtin
""" Confirm the sale order and, add the grants on this one. """ """ Confirm the sale order and, add the grants on this one. """
if object.getPortalType() in ['Sale Order',]: if object.getPortalType() in ['Sale Order',]:
object.confirm() object.confirm()
...@@ -217,11 +216,10 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -217,11 +216,10 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
default_source = integration_site.getSourceAdministrationValue() default_source = integration_site.getSourceAdministrationValue()
default_org_gid = integration_site.organisation_module.getSourceSectionValue().getGidFromObject(default_source, encoded=False) default_org_gid = integration_site.organisation_module.getSourceSectionValue().getGidFromObject(default_source, encoded=False)
default_node = integration_site.getDestinationValue() default_node = integration_site.getDestinationValue()
default_node_gid = integration_site.person_module.getSourceSectionValue().getGidFromObject(default_node, encoded=False)
for subnode in xml.getchildren(): for subnode in xml.getchildren():
# only works on tags, no on the comments or other kind of tag # only works on tags, no on the comments or other kind of tag
if type(subnode.tag) is not str: if not isinstance(subnode.tag, str):
continue continue
tag = subnode.tag.split('}')[index] tag = subnode.tag.split('}')[index]
...@@ -255,9 +253,6 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -255,9 +253,6 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
# dictionary of the value of a movement # dictionary of the value of a movement
movement_dict_value = {'category': []} movement_dict_value = {'category': []}
# marker for checking property existency
MARKER = object()
# if exist namespace retrieve only the tag # if exist namespace retrieve only the tag
index = 0 index = 0
if xml.nsmap not in [None, {}]: if xml.nsmap not in [None, {}]:
...@@ -270,7 +265,7 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -270,7 +265,7 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
# browse the xml and save the sale order line values # browse the xml and save the sale order line values
for subnode in xml.getchildren(): for subnode in xml.getchildren():
# only works on tags, no on the comments or other kind of tag # only works on tags, no on the comments or other kind of tag
if type(subnode.tag) is not str: if not isinstance(subnode.tag, str):
continue continue
tag = subnode.tag.split('}')[index] tag = subnode.tag.split('}')[index]
if tag == 'resource': if tag == 'resource':
...@@ -362,7 +357,7 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -362,7 +357,7 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
mapping_of_setter[key](movement_dict_value[key]) mapping_of_setter[key](movement_dict_value[key])
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the default editDocument method. This method This is the default editDocument method. This method
can easily be overwritten. can easily be overwritten.
...@@ -375,9 +370,9 @@ class ERP5TransactionConduit(TioSafeBaseConduit): ...@@ -375,9 +370,9 @@ class ERP5TransactionConduit(TioSafeBaseConduit):
'reference': 'reference', 'reference': 'reference',
'causality': 'comment', 'causality': 'comment',
} }
property = {} property_ = {}
# Translate kw with the good PropertySheet # Translate kw with the good PropertySheet
for k, v in kw.items(): for k, v in kw.items():
k = mapping.get(k, k) k = mapping.get(k, k)
property[k] = v property_[k] = v
object._edit(**property) object._edit(**property_)
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>ERP5TransactionConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.ERP5TransactionConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.ERP5TransactionConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -25,8 +25,7 @@ ...@@ -25,8 +25,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
from lxml import etree
class OrganisationERP5IntegrationConduit(TioSafeBaseConduit): class OrganisationERP5IntegrationConduit(TioSafeBaseConduit):
""" """
...@@ -35,7 +34,7 @@ class OrganisationERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -35,7 +34,7 @@ class OrganisationERP5IntegrationConduit(TioSafeBaseConduit):
def __init__(self): def __init__(self):
self.xml_object_tag = 'node' self.xml_object_tag = 'node'
def getGidFromObject(self, object): def getGidFromObject(self, object): # pylint: disable=redefined-builtin
""" """
Return the Organisation GID of the object. Return the Organisation GID of the object.
""" """
...@@ -47,15 +46,15 @@ class OrganisationERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -47,15 +46,15 @@ class OrganisationERP5IntegrationConduit(TioSafeBaseConduit):
""" """
return 'Organisation' return 'Organisation'
def updateNode(self, xml=None, object=None, previous_xml=None, force=0, def updateNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception("updateNode: Impossible to update Organisation") raise Exception("updateNode: Impossible to update Organisation")
def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, def deleteNode(self, xml=None, object=None, previous_xml=None, force=0, # pylint: disable=redefined-builtin
simulate=0, **kw): simulate=0, **kw):
raise Exception("deleteNode: Impossible to delete Organisation") raise Exception("deleteNode: Impossible to delete Organisation")
def editDocument(self, object=None, **kw): def editDocument(self, object=None, **kw): # pylint: disable=redefined-builtin
""" """
This is the editDocument method inherit of ERP5Conduit. This method This is the editDocument method inherit of ERP5Conduit. This method
is used to save the information of an Organisation. is used to save the information of an Organisation.
...@@ -67,9 +66,8 @@ class OrganisationERP5IntegrationConduit(TioSafeBaseConduit): ...@@ -67,9 +66,8 @@ class OrganisationERP5IntegrationConduit(TioSafeBaseConduit):
'description': 'description', 'description': 'description',
} }
# Translate kw with the PropertySheet # Translate kw with the PropertySheet
property = {} property_ = {}
for k, v in kw.items(): for k, v in kw.items():
k = mapping.get(k, k) k = mapping.get(k, k)
property[k] = v property_[k] = v
object._edit(**property) object._edit(**property_)
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>OrganisationERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.OrganisationERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.OrganisationERP5IntegrationConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -28,11 +28,11 @@ ...@@ -28,11 +28,11 @@
# #
############################################################################## ##############################################################################
from Products.ERP5SyncML.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST, \ from erp5.component.module.SyncMLConstant import XUPDATE_INSERT_OR_ADD_LIST, \
XUPDATE_DEL, XUPDATE_UPDATE XUPDATE_DEL, XUPDATE_UPDATE
from Products.ERP5Type.XMLExportImport import MARSHALLER_NAMESPACE_URI from Products.ERP5Type.XMLExportImport import MARSHALLER_NAMESPACE_URI
from zLOG import LOG, INFO, WARNING from zLOG import LOG, INFO, WARNING
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.ERP5Conduit import ERP5Conduit
from lxml import etree from lxml import etree
from copy import deepcopy from copy import deepcopy
parser = etree.XMLParser(remove_blank_text=True) parser = etree.XMLParser(remove_blank_text=True)
...@@ -83,7 +83,7 @@ class TioSafeBaseConduit(ERP5Conduit): ...@@ -83,7 +83,7 @@ class TioSafeBaseConduit(ERP5Conduit):
) )
return conflict return conflict
def addNode(self, xml=None, object=None, sub_object=None, reset=None, def addNode(self, xml=None, object=None, sub_object=None, reset=None, # pylint: disable=redefined-builtin
simulate=None, **kw): simulate=None, **kw):
""" """
A node is added A node is added
...@@ -132,7 +132,7 @@ class TioSafeBaseConduit(ERP5Conduit): ...@@ -132,7 +132,7 @@ class TioSafeBaseConduit(ERP5Conduit):
return {'conflict_list':conflict_list, 'object': sub_object} return {'conflict_list':conflict_list, 'object': sub_object}
def applyXupdate(self, object=None, object_xml=None, xupdate=None, previous_xml=None, **kw): def applyXupdate(self, object=None, object_xml=None, xupdate=None, previous_xml=None, **kw): # pylint: disable=redefined-builtin
""" Parse the xupdate and then it will call the conduit. """ """ Parse the xupdate and then it will call the conduit. """
conflict_list = [] conflict_list = []
if isinstance(xupdate, unicode): if isinstance(xupdate, unicode):
...@@ -191,7 +191,7 @@ class TioSafeBaseConduit(ERP5Conduit): ...@@ -191,7 +191,7 @@ class TioSafeBaseConduit(ERP5Conduit):
return result_list return result_list
def getObjectAsXML(self, object, domain): def getObjectAsXML(self, object, domain): # pylint: disable=redefined-builtin
""" """
This method must be implemented by subclasses as the way to generate the This method must be implemented by subclasses as the way to generate the
XML is specific to each side XML is specific to each side
...@@ -202,7 +202,7 @@ class TioSafeBaseConduit(ERP5Conduit): ...@@ -202,7 +202,7 @@ class TioSafeBaseConduit(ERP5Conduit):
""" """
raise NotImplementedError raise NotImplementedError
def updateNode(self, xml=None, object=None, object_xml=None, previous_xml=None, force=False, def updateNode(self, xml=None, object=None, object_xml=None, previous_xml=None, force=False, # pylint: disable=redefined-builtin
simulate=False, reset=False, xpath_expression=None, **kw): simulate=False, reset=False, xpath_expression=None, **kw):
""" """
This method browse the xml which allows to update data and update the This method browse the xml which allows to update data and update the
...@@ -230,7 +230,7 @@ class TioSafeBaseConduit(ERP5Conduit): ...@@ -230,7 +230,7 @@ class TioSafeBaseConduit(ERP5Conduit):
# we may have only the part of an xupdate # we may have only the part of an xupdate
else: else:
# previous_xml is required as an etree type # previous_xml is required as an etree type
if type(previous_xml) == str: if isinstance(previous_xml, str):
previous_xml = etree.XML(previous_xml, parser=parser) previous_xml = etree.XML(previous_xml, parser=parser)
if self.isProperty(xml): if self.isProperty(xml):
...@@ -265,7 +265,7 @@ class TioSafeBaseConduit(ERP5Conduit): ...@@ -265,7 +265,7 @@ class TioSafeBaseConduit(ERP5Conduit):
self.afterUpdateMethod(object, **kw) self.afterUpdateMethod(object, **kw)
return conflict_list return conflict_list
def afterUpdateMethod(self, object, **kw): def afterUpdateMethod(self, object, **kw): # pylint: disable=redefined-builtin
""" This method is for actions that has to be done just after object """ This method is for actions that has to be done just after object
update and which required to have synchronization parameters update and which required to have synchronization parameters
""" """
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>TioSafeBaseConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.TioSafeBaseConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.TioSafeBaseConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
# #
############################################################################## ##############################################################################
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
class TioSafeNodeConduit(TioSafeBaseConduit): class TioSafeNodeConduit(TioSafeBaseConduit):
...@@ -37,10 +37,10 @@ class TioSafeNodeConduit(TioSafeBaseConduit): ...@@ -37,10 +37,10 @@ class TioSafeNodeConduit(TioSafeBaseConduit):
def __init__(self): def __init__(self):
self.xml_object_tag = 'node' self.xml_object_tag = 'node'
def getObjectAsXML(self, object, domain): def getObjectAsXML(self, object, domain): # pylint: disable=redefined-builtin
return object.asXML() return object.asXML()
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, # pylint: disable=redefined-builtin
reset_local_roles=0, reset_workflow=0, simulate=0, **kw): reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
# if exist namespace retrieve only the tag # if exist namespace retrieve only the tag
index = 0 index = 0
...@@ -52,7 +52,7 @@ class TioSafeNodeConduit(TioSafeBaseConduit): ...@@ -52,7 +52,7 @@ class TioSafeNodeConduit(TioSafeBaseConduit):
# browse the xml # browse the xml
for node in xml: for node in xml:
# works on tags, no on comments # works on tags, no on comments
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
# Retrieve the tag # Retrieve the tag
tag = node.tag.split('}')[index] tag = node.tag.split('}')[index]
...@@ -84,7 +84,7 @@ class TioSafeNodeConduit(TioSafeBaseConduit): ...@@ -84,7 +84,7 @@ class TioSafeNodeConduit(TioSafeBaseConduit):
return object.person_module(person_id=new_id)[0] return object.person_module(person_id=new_id)[0]
def _deleteContent(self, object=None, object_id=None, **kw): def _deleteContent(self, object=None, object_id=None, **kw): # pylint: disable=redefined-builtin
""" We do not delete nodes """ """ We do not delete nodes """
pass pass
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>TioSafeNodeConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.TioSafeNodeConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.TioSafeNodeConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
############################################################################## ##############################################################################
from Products.ERP5Type.Utils import cartesianProduct from Products.ERP5Type.Utils import cartesianProduct
from Products.ERP5TioSafe.Conduit.TioSafeBaseConduit import TioSafeBaseConduit from erp5.component.module.TioSafeBaseConduit import TioSafeBaseConduit
from lxml import etree from lxml import etree
from zLOG import LOG from zLOG import LOG
...@@ -39,10 +39,10 @@ class TioSafeResourceConduit(TioSafeBaseConduit): ...@@ -39,10 +39,10 @@ class TioSafeResourceConduit(TioSafeBaseConduit):
def __init__(self): def __init__(self):
self.xml_object_tag = 'resource' self.xml_object_tag = 'resource'
def getObjectAsXML(self, object, domain): def getObjectAsXML(self, object, domain): # pylint: disable=redefined-builtin
return object.asXML() return object.asXML()
def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, def _createContent(self, xml=None, object=None, object_id=None, sub_object=None, # pylint: disable=redefined-builtin
reset_local_roles=0, reset_workflow=0, simulate=0, **kw): reset_local_roles=0, reset_workflow=0, simulate=0, **kw):
LOG("TioSafeNodeConduit._createConten", 300, "xml = %s" %(etree.tostring(xml, pretty_print=1),)) LOG("TioSafeNodeConduit._createConten", 300, "xml = %s" %(etree.tostring(xml, pretty_print=1),))
...@@ -52,7 +52,6 @@ class TioSafeResourceConduit(TioSafeBaseConduit): ...@@ -52,7 +52,6 @@ class TioSafeResourceConduit(TioSafeBaseConduit):
index = -1 index = -1
# init the new_id of the product and the checker of the creation # init the new_id of the product and the checker of the creation
new_id = None new_id = None
product_created = False
# this dict contains the element to set to the product # this dict contains the element to set to the product
keyword = {} keyword = {}
# this dict will contains a list of tuple (base_category, vairiation) # this dict will contains a list of tuple (base_category, vairiation)
...@@ -63,7 +62,7 @@ class TioSafeResourceConduit(TioSafeBaseConduit): ...@@ -63,7 +62,7 @@ class TioSafeResourceConduit(TioSafeBaseConduit):
# browse the xml # browse the xml
for node in xml: for node in xml:
# works on tags, not on comments # works on tags, not on comments
if type(node.tag) is not str: if not isinstance(node.tag, str):
continue continue
tag = node.tag.split('}')[index] tag = node.tag.split('}')[index]
LOG("browsing tag %s, value %s" %(tag, node.text), 300, "keyword = %s" %(keyword,)) LOG("browsing tag %s, value %s" %(tag, node.text), 300, "keyword = %s" %(keyword,))
...@@ -121,7 +120,7 @@ class TioSafeResourceConduit(TioSafeBaseConduit): ...@@ -121,7 +120,7 @@ class TioSafeResourceConduit(TioSafeBaseConduit):
return object[new_id] return object[new_id]
def _deleteContent(self, object=None, object_id=None, **kw): def _deleteContent(self, object=None, object_id=None, **kw): # pylint: disable=redefined-builtin
""" This method allows to remove a product in the integration site """ """ This method allows to remove a product in the integration site """
delete_method_id = "deleteProduct" # XXX-AUREL : must find a way to fix this delete_method_id = "deleteProduct" # XXX-AUREL : must find a way to fix this
delete_method = getattr(object, delete_method_id, None) delete_method = getattr(object, delete_method_id, None)
...@@ -139,7 +138,6 @@ class TioSafeResourceConduit(TioSafeBaseConduit): ...@@ -139,7 +138,6 @@ class TioSafeResourceConduit(TioSafeBaseConduit):
conflict_list = [] conflict_list = []
xpath_expression = xml.get('select') xpath_expression = xml.get('select')
tag = xpath_expression.split('/')[-1] tag = xpath_expression.split('/')[-1]
integration_site = document.context.getParentValue()
new_value = xml.text new_value = xml.text
# retrieve the previous xml etree through xpath # retrieve the previous xml etree through xpath
...@@ -174,7 +172,7 @@ class TioSafeResourceConduit(TioSafeBaseConduit): ...@@ -174,7 +172,7 @@ class TioSafeResourceConduit(TioSafeBaseConduit):
# create and fill a conflict when the integration site value, the erp5 # create and fill a conflict when the integration site value, the erp5
# value and the previous value are differents # value and the previous value are differents
current_value = getter_value_dict[tag] current_value = getter_value_dict[tag]
if type(current_value) == float: if isinstance(current_value, float):
current_value = '%.6f' % current_value current_value = '%.6f' % current_value
if isinstance(current_value, unicode): if isinstance(current_value, unicode):
current_value = current_value.encode('utf-8') current_value = current_value.encode('utf-8')
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Module Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default_reference</string> </key>
<value> <string>TioSafeResourceConduit</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value> <string>Products.ERP5TioSafe.Conduit.TioSafeResourceConduit</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>module.erp5.TioSafeResourceConduit</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Module Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_log</string> </key>
<value>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
erp5_accounting erp5_accounting
erp5_syncml
erp5_trade erp5_trade
erp5_web_service erp5_web_service
\ No newline at end of file
module.erp5.AccountERP5IntegrationConduit
module.erp5.AccountingERP5IntegrationConduit
module.erp5.ERP5NodeConduit
module.erp5.ERP5PaymentTransactionConduit
module.erp5.ERP5ResourceConduit
module.erp5.ERP5TransactionConduit
module.erp5.OrganisationERP5IntegrationConduit
module.erp5.TioSafeBaseConduit
module.erp5.TioSafeNodeConduit
module.erp5.TioSafeResourceConduit
\ No newline at end of file
...@@ -35,7 +35,6 @@ From ERP5 subversion repository: ...@@ -35,7 +35,6 @@ From ERP5 subversion repository:
* ERP5Form * ERP5Form
* ERP5OOo * ERP5OOo
* ERP5Security * ERP5Security
* ERP5SyncML
* ERP5Type * ERP5Type
* ZSQLCatalog * ZSQLCatalog
......
#!/usr/bin/python
# coding=UTF-8
import urllib,urllib2
import socket
import time
from optparse import OptionParser
from lxml import etree
parser = etree.XMLParser(remove_blank_text=True)
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)
cmd_parser = OptionParser()
cmd_parser.add_option("--host", help="address of this small server (typically, it's the ip of this computer)")
cmd_parser.add_option("--publication", help="address of the publication (e.g. http://localhost:9080/erp5Serv)")
cmd_parser.add_option("-p", "--port", type="int", help="port used by this server (default is 1234)", default=1234)
(options, args) = cmd_parser.parse_args()
cmd_parser.check_required("--publication")
cmd_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://%s:%s' % (Host, Port)
#socket :
sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # reuse the same socket
# if already open
#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
"""
return etree.tostring(node, encoding='utf-8')
def xml2wbxml(xml):
"""
convert xml string to wbxml using a temporary file
"""
import os
# XXX we must check at the begining if xml2wbxml is installed
# it seems that now there is a python biding for this : pywbxml
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 = etree.XML(text, parser=parser)
# XXX this xpath expression have to be rewrited in a generic way to handle
# namspace
client_url = '%s' % document.xpath('string(//SyncHdr/Source/LocURI)')
# client_url = '%s' % document.xpath('string(//syncml:SyncHdr/syncml:Source/syncml:LocURI)', namespaces={'syncml':'SYNCML:SYNCML1.2'})
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'%(to_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:
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()
Problem
General
It's really difficult to synchronise different zope databases systems.
(there is a product by Zope Corp which does that but is
very expensive and not so public)
There are two different problems
- synchronising the same ODB (object database) on multiple servers / sites
- synchronising some data stored on different ODB on multiple servers / sites
The first case is the case of one company with a global ODB
The second case is the case of 2 companies who want to share their
mutual orders but not other orders
If case 2 is solved, then case 1 too. We shall solve case 2
by using an intermediate XML format specific to each application
Specific problems
Most of synchronisations systems needs a database wich acts like a master, and
all slaves are like a copy of the main database (case 1)
Thoses systems don't allow to copy only a part of the data, they copy all
objects from the master database to all slaves databases.
Proposed Solution
<img src="simple_schema.jpg">
This project proposes to create a Zope Product that have to synchronise
databases. This synchronisation have to update only the part of the database
needed.
Specifically we want to achieve the following goals :
o manage a list of subscribers who can take a subscription to a query.
o manage queries applied to a database of objects.
o generate XML in order to communicate with several databases.
o use filters, so that generated XML only contains part of the attributes of
objects in the ODB (1 XML file per Zope Objet / Document (ex. 1 XML file per
order)). For example, private comments should not be exported in the generated
XML file
o synchronise databases with the content of the XML.
There's already a generic synchronisation system for Zope : ZSyncer. But this system
is too limited for all our needs.
Details
Objects
All objects will have the following attributes
- id : the standard object id
- uid : a global object id wich is unique to each ZODB
- rid : the standard object id in the master ODB the object
was subscribed from (remote id).
- sid : the id of the subsription/synchronisation object wich this
object was generated from.
A mapping from id to rid and rid to id is available through the
subscription sid
First step : initialisation :
<img src="steps.jpg">
1 We create a subscription inside portal_synchronisations in the slave.
We define for that subscription
- id, title, description
- the URL of the master (which contains an index of all
files we can sync) - this URL defines a public
synchronisation handle in the master server
- a local query (SQL Method) to define the local realm of
synchronisation
- an import Conduit in order to validate data,
calculate differences and import differences. This is where
we define the format of the data we receive from the master
- a local PageTemplate/DTML to converte local objects to XML.
This is where we define both the format we send to the master
and the realm of attributes we synchronise (ie. the mapping)
2 The slave sends the "initialisation package" (SyncML specification), in this package,
appears several elements :
- the SynchHdr element with several informations about the protocol used. We will
put the query in this element, and also authentification informations.
- the Alert element, in order to specify what kind of synchronisation we want,
for us it will be the Alert 200 wich specifies a client-initiated, two way
synchronisation.
3 We create a publication in the master database. We define
- id, title, description
- a local query (SQL Method) to define the local realm of
publication (which objects do we publish)
- a local PageTemplate/DTML to convert local objects to XML
(what do we publish in each object and with what format)
- an import Conduit in order to be able to commit changes
sent by subscribed databases into the master database (OPTION)
A this step, we produce all XML files from master ODB
4 The master sends the "Initialisation package" to the client with :
- the SynchHdr element with several informations about the protocol used,
and also authentification informations.
- the Status element, in order to respond to the alert command sent by the client.
A code for the status is returned, it will be typically 212 if the authentification
is fine for the client.
- differences between the two databases.
- the Alert element, in order to specify what kind of synchronisation we want,
for us it will be 201 wich specifies a client-initiated, two-way slow-synchronisation.
This just means that both the server and the client sends all their data. Each
data must specify the DTD used.
At this step, we may eventually record the subscriber in the publication
of the master database for... (OPTION). This is like
the subscribtion is becoming member of mail list to be informed of
changes of a publication
//- if the slave already have some data (for example an addressbook) corresponding
//to the query (for example all people from the company Nexedi), then thoses data
//must be sent by the same time. Each data must specify the DTD used.
//6 Finally the slave import in his databases all objects from the master.
Second step : synchronisation :
General idea
M master
S slave
C conflicts
t continuous time
tn discrete time
1 calculate the difference on the slave DS(tn) = S(tn) - S(tn-1)
1 upload the differences to the master or send by email or whatever
1 calculate the difference on the master DM(tn) = M(tn) - M(tn-1)
1 update the master with differences from the slave M(tn) <- M(tn) + DS(tn)
1 Manage conflicts and if possible solve them on the master C(tn)
1 upload the differences and conflicts resolution to the slave
1 update the slave S(tn) <- S(tn) + DM(tn) + C(tn)
Detail implementation
blabla
References
XMLDiff - http://www.garshol.priv.no/download/xmltools/prod/xmldiff.html
SyncML - http://www.syncml.org
ZSyncer - http://www.zope.org/Members/andym/ZSyncer
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2002-2010 Nexedi SA and Contributors. All Rights Reserved.
# Jean-Paul Smets-Solanes <jp@nexedi.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.
#
##############################################################################
"""
ERP5Catalog provides an extended catalog based on ZSQLCatalog
and extended local roles management
"""
import sys, Permissions, os
from App.Common import package_home
this_module = sys.modules[ __name__ ]
product_path = package_home( globals() )
this_module._dtmldir = os.path.join( product_path, 'dtml' )
# Update ERP5 Globals
from Products.ERP5Type.Utils import initializeProduct, updateGlobals
document_classes = updateGlobals(this_module, globals(),
permissions_module=Permissions)
def initialize( context ):
# Import Product Components
from Tool import SynchronizationTool
import Document
# Define documents, classes, constructors and tools
object_classes = ()
content_constructors = ()
content_classes = ()
portal_tools = (SynchronizationTool.SynchronizationTool,)
# Do initialization step
initializeProduct(context, this_module, globals(),
document_module=Document,
document_classes=document_classes,
object_classes=object_classes,
portal_tools=portal_tools,
content_constructors=content_constructors,
content_classes=content_classes)
Conflict management with n clients, n >= 2
Description :
- We have 4 boxes, a server A et three clients : B, C and D
- first, A, B,C et D are synchronized
- B change the title of /w/x/truc
- C change the title of /w/x/truc
- D change the title of /w/x/truc
- We do the synchronization in this order : B, D and D
- The server A takes the value of B (because nothing was changed on A)
- there is a conflict between A and C
- there is a conflict between A and D
- So we get on the server A 2 Conflict objets and 1 local object, so that
we can retrieve 3 different versions of the object
- Clients C and D must know that there is a conflict from /w/x
The SyncML protocol doesn't allow us to tell to the client that the
conflict is on /w/x/truc
- We have to be able to get on the server the 3 different objects
- getSynchronizationState should return CONFLICT for each subscription
in conflict.
- for each Conflict object, we should have a getRemoteObject method wich
returns the /w/x/truc object from C and the next Conflict should returns
the object from D
Result of getSynchronizationState :
- In the case of a client with only one subscription, this is quite easy,
we should returns the state of the subscription
- In the case of the server, it is more complicated, we can have by the
same time depending on subscribers the following states : CONFLICT,
NOT_SYNCHRONIZED, SYNCHRONIZED...
- So we have to give the state associated with the subscriber, so we should
not returns only a state, but a mapping between subscribers and states
- So we can deduce that we should have a result like this :
[ [subscriber1,state1], [subscriber2,state2]...]
Howto store conflicts :
- We should take again the example with the server and the 3 clients
- A, B, C et D are synchronized
- B, C et D change the title and description of /w/x/truc
and also the title and description of /w/x/machin
- We do the synchronization in this order : B, D and D
- The server A takes the value of B (because nothing was changed on A)
- there is a conflict between A and C
- there is a conflict between A and D
- So we have on the server 2 local objects and 8 Conflict objects (DEPRECATED):
- Conflict for /w/x/truc : title for subscription C (DEPRECATED)
- Conflict for /w/x/truc : title for subscription D (DEPRECATED)
- Conflict for /w/x/truc : description for subscription C (DEPRECATED)
- Conflict for /w/x/truc : description for subscription D (DEPRECATED)
- Conflict for /w/x/machin : title for subscription C (DEPRECATED)
- Conflict for /w/x/machin : title for subscription D (DEPRECATED)
- Conflict for /w/x/machin : description for subscription C (DEPRECATED)
- Conflict for /w/x/machin : description for subscription D (DEPRECATED)
- This is bad, we can do a getRemoteObject because in this case we get
only a part of the remote object, we should have only 4 Conflicts
- XXX I have to change immediatly the way of storing conflict in order to
have the following list :
- Conflict1 for /w/x/truc : title and description for subscription C
- Conflict2 for /w/x/truc : title and description for subscription D
- Conflict3 for /w/x/machin : title and description for subscription C
- Conflict4 for /w/x/machin : title and description for subscription D
- The good way is to store a list of xupdate on each Conflict
Howto solve conflicts :
- Let's says that we take the object given by Conflict 2 for /w/x/truc and
we take the version given by the server for the object /w/x/machin
- Do we have to solve conflict one by one or when we choose one version for
one Conflict, it will remove other versions ???
I guess the best way is to just solve conflict one by one, then we are still
free to make another method wich solve for all versions by the same time.
- So we have to do :
Conflict2.setRemoteObject()
Conflict1.setLocalObject() # wich is the version of D because of the previous call
Conflict3.setLocalObject()
Conflict4.setLocalObject()
- May be we can do a global method, like :
Conflict2.setGlobalRemoteObject() wich implicitly call
Conflict1.setLocalObject()
and Conflict3.setGlobalLocalObject() wich implicitly call
Conflict4.setLocalObject()
- Conflict2.setRemoteObject() have to apply all xupdate strings stored
in Conflict2. Then it have to set the status as CONFLICT_CLIENT_WIN.
- Conflict3.setLocalObject() have to set the status as CONFLICT_MERGE. How ??
- Probably the best way is to call the synchronizationTool wich know everything
about subscription and subscriber.
- synchronizationtool.setLocalObject should have as parameter: the conflict (wich
store the subscriber), that's all
- then we can look at the signature of the object, delete the corresponding
Conflict, and if there is no conflict left, then we can set the signature
as CONFLICT_MERGE
- At this state, we do have the /w/x/truc of D, and the /w/x/machin of B, and
there is no conflict left, at least on the server side.
#- at the time of the next synchronization, the server should send is new version
of /w/x/truc and /w/x/machin to B, C and D, so that everyone is synchronized
without conflict.
# -*- coding: utf-8 -*-
from conduit import IConduit
...@@ -104,7 +104,7 @@ class XMLObject( Folder ): ...@@ -104,7 +104,7 @@ class XMLObject( Folder ):
""" """
Replace the content of this object by providing an xml content Replace the content of this object by providing an xml content
""" """
from Products.ERP5SyncML.Conduit.ERP5Conduit import ERP5Conduit from erp5.component.module.ERP5Conduit import ERP5Conduit
conduit = ERP5Conduit() conduit = ERP5Conduit()
conduit.addNode(object=self, xml=xml) conduit.addNode(object=self, xml=xml)
......
...@@ -10,7 +10,7 @@ class _ERP5(ERP5TypeTestSuite): ...@@ -10,7 +10,7 @@ class _ERP5(ERP5TypeTestSuite):
realtime_output = False realtime_output = False
enabled_product_list = ('CMFActivity', 'CMFCategory', 'ERP5', 'ERP5Catalog', enabled_product_list = ('CMFActivity', 'CMFCategory', 'ERP5', 'ERP5Catalog',
'ERP5Form', 'ERP5Form',
'ERP5OOo', 'ERP5Security', 'ERP5SyncML', 'ERP5Type', 'ERP5OOo', 'ERP5Security', 'ERP5Type',
'Formulator', 'ERP5Workflow', 'Formulator', 'ERP5Workflow',
'HBTreeFolder2', 'MailTemplates', 'HBTreeFolder2', 'MailTemplates',
'PortalTransforms', 'TimerService', 'ZLDAPConnection', 'PortalTransforms', 'TimerService', 'ZLDAPConnection',
...@@ -80,9 +80,7 @@ class ERP5(_ERP5): ...@@ -80,9 +80,7 @@ class ERP5(_ERP5):
or test_case in ('testERP5LdapCatalog', # XXX (Ivan), until LDAP server is available this test will alway fail or test_case in ('testERP5LdapCatalog', # XXX (Ivan), until LDAP server is available this test will alway fail
# tests reading selenium tables from erp5.com # tests reading selenium tables from erp5.com
# not maintained # not maintained
'testAccounting_l10n_fr_m9', 'testAccounting_l10n_fr_m9'
# Not a test
'testERP5SyncMLMixin'
): ):
continue continue
test_list.append(full_test_case) test_list.append(full_test_case)
......
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