diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_makeActiveResult.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_makeActiveResult.xml new file mode 100644 index 0000000000000000000000000000000000000000..11ec3d81864d581a7f11ff2b9b29f6ca5d46ba67 --- /dev/null +++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/Base_makeActiveResult.xml @@ -0,0 +1,161 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="PythonScript" module="Products.PythonScripts.PythonScript"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>Python_magic</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>Script_magic</string> </key> + <value> <int>3</int> </value> + </item> + <item> + <key> <string>__ac_local_roles__</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_bind_names</string> </key> + <value> + <object> + <klass> + <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>_asgns</string> </key> + <value> + <dictionary> + <item> + <key> <string>name_container</string> </key> + <value> <string>container</string> </value> + </item> + <item> + <key> <string>name_context</string> </key> + <value> <string>context</string> </value> + </item> + <item> + <key> <string>name_m_self</string> </key> + <value> <string>script</string> </value> + </item> + <item> + <key> <string>name_subpath</string> </key> + <value> <string>traverse_subpath</string> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>_body</string> </key> + <value> <string>from Products.CMFActivity.ActiveResult import ActiveResult\n +active_result = ActiveResult()\n +severity = len(error_list)\n +if severity == 0:\n + summary = "No error"\n +else:\n + summary = "Error"\n +active_result.edit(summary=summary, severity=severity, detail=\'\\n\'.join(error_list))\n +return active_result\n +</string> </value> + </item> + <item> + <key> <string>_code</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_filepath</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_owner</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_params</string> </key> + <value> <string>title, error_list</string> </value> + </item> + <item> + <key> <string>errors</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>func_code</string> </key> + <value> + <object> + <klass> + <global name="FuncCode" module="Shared.DC.Scripts.Signature"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>co_argcount</string> </key> + <value> <int>2</int> </value> + </item> + <item> + <key> <string>co_varnames</string> </key> + <value> + <tuple> + <string>title</string> + <string>error_list</string> + <string>Products.CMFActivity.ActiveResult</string> + <string>ActiveResult</string> + <string>active_result</string> + <string>len</string> + <string>severity</string> + <string>summary</string> + <string>_getattr_</string> + </tuple> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>func_defaults</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>Base_makeActiveResult</string> </value> + </item> + <item> + <key> <string>warnings</string> </key> + <value> + <tuple/> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/ERP5Site_checkDataWithScript.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/ERP5Site_checkDataWithScript.xml new file mode 100644 index 0000000000000000000000000000000000000000..e434d0e1c2e64a29683bb967196b2a716c6af86e --- /dev/null +++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_core/ERP5Site_checkDataWithScript.xml @@ -0,0 +1,280 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <tuple> + <global name="PythonScript" module="Products.PythonScripts.PythonScript"/> + <tuple/> + </tuple> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>Python_magic</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>Script_magic</string> </key> + <value> <int>3</int> </value> + </item> + <item> + <key> <string>__ac_local_roles__</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_bind_names</string> </key> + <value> + <object> + <klass> + <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>_asgns</string> </key> + <value> + <dictionary> + <item> + <key> <string>name_container</string> </key> + <value> <string>container</string> </value> + </item> + <item> + <key> <string>name_context</string> </key> + <value> <string>context</string> </value> + </item> + <item> + <key> <string>name_m_self</string> </key> + <value> <string>script</string> </value> + </item> + <item> + <key> <string>name_subpath</string> </key> + <value> <string>traverse_subpath</string> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>_body</string> </key> + <value> <string encoding="cdata"><![CDATA[ + +"""Recursively call a script on all subobjects.\n +\n +From document pointed to by \'relative_url\':\n +- If its depth is 1 (ie no slash) and \'id_list\' isn\'t empty, immediately call a\n + script (\'method_id\') on all objects given by id_list. Also call it\n + recursively on subobjects if \'recursive\' is true.\n +- Else, forward this call to its subobjects, which are given by \'id_list\'.\n + If id_list is None:\n + - if \'relative_url\' points to a HBTree and if \'full\' is false,\n + all subobjects for last \'hbtree_days\' are considered.\n + - else, all subobjects are considered.\n +\n + method_id - Script to call.\n + method_kw - Dict containing arguments for \'method_id\'.\n + packet - Maximum size (in number of objects to process)\n + of created activities.\n +\n +For the portal, \'relative_url\' must be false and only module objects are\n +considered if id_list is None.\n +"""\n +\n +document = context.getPortalObject()\n +if relative_url:\n + document = document.restrictedTraverse(relative_url)\n + depth = len(relative_url.split(\'/\'))\n +else:\n + depth = 0\n +\n +maximum_depth = 1\n +\n +assert depth <= maximum_depth\n +\n +def activate(**kw):\n + return context.activate(activity=\'SQLQueue\', lonely=1, tag=tag, **kw)\n +\n +if depth == maximum_depth and id_list:\n + # Immediate recursive check\n + error_list = []\n + if method_kw is None:\n + method_kw = {}\n + def recurse(document):\n + error_list.extend(getattr(document, method_id)(**method_kw))\n + if recursive:\n + for subdocument in document.objectValues():\n + recurse(subdocument)\n + for id in id_list:\n + recurse(document[id])\n + if active_process is None:\n + return error_list\n + if len(error_list):\n + # Create an activity to update active_process,\n + # in order to prevent conflict errors.\n + activate(active_process=active_process, priority=2) \\\n + .Base_asActiveResult(title=relative_url, error_list=error_list)\n +else:\n + if id_list is None:\n + if full or not getattr(document, \'isHBTree\', lambda: 0)():\n + id_list = document.objectIds()\n + if not depth:\n + id_list = tuple(x for x in id_list if x.endswith(\'_module\'))\n + else:\n + from DateTime import DateTime\n + id_list = []\n + for day_ago in xrange(hbtree_days):\n + date = (DateTime()-day_ago).strftime(\'%Y%m%d\')\n + context.log(\'date for objectIds\', date)\n + try:\n + id_list += document.objectIds(base_id=date)\n + except (TypeError, IndexError):\n + pass\n +\n + if active_process is None:\n + active_process = context.newActiveProcess().getPath()\n + kw = dict(relative_url=relative_url, active_process=active_process,\n + tag=tag, full=full, recursive=recursive, packet=packet,\n + method_id=method_id, method_kw=method_kw)\n + if depth < maximum_depth:\n + packet = 1\n + relative_url = relative_url and relative_url + \'/\' or \'\'\n + for i in xrange(0, len(id_list), packet):\n + if packet == 1:\n + kw[\'relative_url\'] = relative_url + id_list[i]\n + else:\n + kw[\'id_list\'] = tuple(id_list[i:i+packet])\n + activate(priority=4).ERP5Site_checkDataWithScript(**kw)\n + + +]]></string> </value> + </item> + <item> + <key> <string>_code</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_filepath</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_owner</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>_params</string> </key> + <value> <string>method_id, relative_url=None, active_process=None, id_list=None, full=0, recursive=1, tag=None, packet=30, hbtree_days=3, method_kw=None</string> </value> + </item> + <item> + <key> <string>errors</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>func_code</string> </key> + <value> + <object> + <klass> + <global name="FuncCode" module="Shared.DC.Scripts.Signature"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>co_argcount</string> </key> + <value> <int>10</int> </value> + </item> + <item> + <key> <string>co_varnames</string> </key> + <value> + <tuple> + <string>method_id</string> + <string>relative_url</string> + <string>active_process</string> + <string>id_list</string> + <string>full</string> + <string>recursive</string> + <string>tag</string> + <string>packet</string> + <string>hbtree_days</string> + <string>method_kw</string> + <string>_getattr_</string> + <string>context</string> + <string>document</string> + <string>len</string> + <string>depth</string> + <string>maximum_depth</string> + <string>AssertionError</string> + <string>activate</string> + <string>error_list</string> + <string>None</string> + <string>recurse</string> + <string>_getiter_</string> + <string>id</string> + <string>_getitem_</string> + <string>getattr</string> + <string>tuple</string> + <string>DateTime</string> + <string>xrange</string> + <string>day_ago</string> + <string>date</string> + <string>_inplacevar_</string> + <string>TypeError</string> + <string>IndexError</string> + <string>dict</string> + <string>kw</string> + <string>i</string> + <string>_write_</string> + <string>_apply_</string> + </tuple> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>func_defaults</string> </key> + <value> + <tuple> + <none/> + <none/> + <none/> + <int>0</int> + <int>1</int> + <none/> + <int>30</int> + <int>3</int> + <none/> + </tuple> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>ERP5Site_checkDataWithScript</string> </value> + </item> + <item> + <key> <string>warnings</string> </key> + <value> + <tuple/> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/product/ERP5/bootstrap/erp5_core/bt/revision b/product/ERP5/bootstrap/erp5_core/bt/revision index 7edd58a8bfe04ca7c3249c6c6d2af5c75392a39e..f08bce7b1cdfccb3c6535b9136460570f5632578 100644 --- a/product/ERP5/bootstrap/erp5_core/bt/revision +++ b/product/ERP5/bootstrap/erp5_core/bt/revision @@ -1 +1 @@ -840 \ No newline at end of file +841 \ No newline at end of file diff --git a/product/ERP5/tests/testERP5Base.py b/product/ERP5/tests/testERP5Base.py index 5e86c5d5ad4ec9181ab7d2b979f72c75688ea560..7deeb89de200f8ef05b991645fad59c589be8a85 100644 --- a/product/ERP5/tests/testERP5Base.py +++ b/product/ERP5/tests/testERP5Base.py @@ -34,7 +34,7 @@ from DateTime import DateTime from Products.ERP5Type.Utils import convertToUpperCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.Sequence import SequenceList -from Products.ERP5Type.tests.utils import FileUpload +from Products.ERP5Type.tests.utils import createZODBPythonScript, FileUpload from AccessControl.SecurityManagement import newSecurityManager class TestERP5Base(ERP5TypeTestCase): @@ -1171,6 +1171,33 @@ class TestERP5Base(ERP5TypeTestCase): self.assertNotEquals(None, assignment.getStopDate()) self.assertEquals(DateTime().day(), assignment.getStopDate().day()) + def test_ERP5Site_checkDataWithScript(self): + test = 'test_ERP5Site_checkDataWithScript' + createZODBPythonScript(self.getSkinsTool().custom, test, '', + 'return context.getRelativeUrl(),') + + organisation = self.getOrganisationModule() \ + .newContent(portal_type='Organisation') + organisation.setDefaultAddressCity('Lille') + organisation.setDefaultAddressZipCode('59000') + person = self.getPersonModule().newContent(portal_type='Person') + person.setDefaultEmailText('nobody@example.com') + + portal_activities = self.getActivityTool() + active_process = portal_activities.newActiveProcess() + portal_activities.ERP5Site_checkDataWithScript(method_id=test, tag=test, + active_process=active_process.getPath()) + self.tic() + relative_url_list = sum((x.detail.split('\n') + for x in active_process.getResultList()), []) + + self.assertEquals(len(relative_url_list), len(set(relative_url_list))) + for obj in organisation, person, person.getDefaultEmailValue(): + self.assertTrue(obj.getRelativeUrl() in relative_url_list) + for relative_url in relative_url_list: + self.assertTrue('/' in relative_url) + self.assertNotEquals(None, self.portal.unrestrictedTraverse(relative_url)) + def test_suite(): suite = unittest.TestSuite()