Commit e6f7850b authored by Jérome Perrin's avatar Jérome Perrin

Merge remote-tracking branch 'origin/master' into zope4py2

parents fd247eeb 9dadb6dd
...@@ -263,7 +263,7 @@ ...@@ -263,7 +263,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python:here.portal_categories.role.getCategoryChildTranslatedLogicalPathItemList(base=True)</string> </value> <value> <string>python:here.portal_categories.role.getCategoryChildTranslatedLogicalPathItemList(base=True, display_none_category=False)</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -7,32 +7,35 @@ categories from all available GAP. ...@@ -7,32 +7,35 @@ categories from all available GAP.
portal = context.getPortalObject() portal = context.getPortalObject()
display_cache = {}
def display(x): def display(x):
if x not in display_cache: gap_id = x.getReference()
gap_id = x.getReference() if gap_id:
if gap_id: return '%s - %s' % (
display_cache[x] = '%s - %s' % ( gap_id,
gap_id, x.getTranslatedShortTitle() or x.getTranslatedTitle())
x.getTranslatedShortTitle() or x.getTranslatedTitle()) return x.getIndentedTitle()
else:
display_cache[x] = x.getIndentedTitle()
return display_cache[x]
def getGapItemList(only_preferred_gap, gap_root=None): def getGapItemList(only_preferred_gap, gap_root=None):
if only_preferred_gap: if only_preferred_gap and gap_root:
if gap_root: return portal.portal_categories.resolveCategory(gap_root).getCategoryChildItemList(
return portal.portal_categories.resolveCategory(gap_root).getCategoryChildItemList( base=False,
base=False, is_self_excluded=True, display_method=display, is_self_excluded=True,
display_method=display,
display_none_category=False,
local_sort_id=('int_index', 'reference', 'id')) local_sort_id=('int_index', 'reference', 'id'))
result = [] result = []
for country in portal.portal_categories.gap.contentValues(): for gap_root_title, gap_root in context.AccountModule_getAvailableGapList():
for gap_root in country.contentValues(): if gap_root:
result.extend(gap_root.getCategoryChildItemList( result.append((gap_root_title, None))
base=False, is_self_excluded=True, display_method=display, result.extend(
local_sort_id=('int_index', 'reference', 'id'))) portal.portal_categories.resolveCategory(gap_root).getCategoryChildItemList(
base=False,
is_self_excluded=True,
display_method=display,
display_none_category=False,
local_sort_id=('int_index', 'reference', 'id')))
return result return result
from Products.ERP5Type.Cache import CachingMethod from Products.ERP5Type.Cache import CachingMethod
......
...@@ -12,6 +12,8 @@ def getSubFieldDict(): ...@@ -12,6 +12,8 @@ def getSubFieldDict():
for item in item_list: for item in item_list:
# Get value of the item # Get value of the item
item_value = item[int(not is_right_display)] item_value = item[int(not is_right_display)]
if item_value is None:
continue
# Hash key from item_value # Hash key from item_value
item_split = item_value.split('/') item_split = item_value.split('/')
......
...@@ -278,7 +278,7 @@ ...@@ -278,7 +278,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: context.ERP5Site_getAccountItemList(section_category=request.get(\'your_section_category\', preferences.getPreferredAccountingTransactionSectionCategory()), section_category_strict=request.get(\'your_section_category_strict\', preferences.getPreferredAccountingSectionCategoryStrict()), from_date=request.get(\'your_from_date\', preferences.getPreferredAccountingTransactionFromDate()))</string> </value> <value> <string>python: [item for item in context.ERP5Site_getAccountItemList(section_category=request.get(\'your_section_category\', preferences.getPreferredAccountingTransactionSectionCategory()), section_category_strict=request.get(\'your_section_category_strict\', preferences.getPreferredAccountingSectionCategoryStrict()), from_date=request.get(\'your_from_date\', preferences.getPreferredAccountingTransactionFromDate())) if item[0]]</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -278,7 +278,7 @@ ...@@ -278,7 +278,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: context.ERP5Site_getWorkflowStateItemList(portal_type=\'Accounting Transaction\', state_var=\'simulation_state\')</string> </value> <value> <string>python: context.ERP5Site_getWorkflowStateItemList(portal_type=\'Accounting Transaction\', state_var=\'simulation_state\', display_none_category=False)</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -34,6 +34,8 @@ from Products.ERP5Type.XMLObject import XMLObject ...@@ -34,6 +34,8 @@ from Products.ERP5Type.XMLObject import XMLObject
class Login(EncryptedPasswordMixin, XMLObject, LoginAccountProviderMixin): class Login(EncryptedPasswordMixin, XMLObject, LoginAccountProviderMixin):
"""Login
"""
meta_type = 'ERP5 Login' meta_type = 'ERP5 Login'
portal_type = 'Login' portal_type = 'Login'
add_permission = Permissions.AddPortalContent add_permission = Permissions.AddPortalContent
......
...@@ -40,7 +40,8 @@ from Products.CMFCore.utils import _checkPermission ...@@ -40,7 +40,8 @@ from Products.CMFCore.utils import _checkPermission
from Products.CMFCore.exceptions import AccessControl_Unauthorized from Products.CMFCore.exceptions import AccessControl_Unauthorized
class EncryptedPasswordMixin(object): class EncryptedPasswordMixin(object):
"""Encrypted Password Mixin
"""
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declareObjectProtected(Permissions.AccessContentsInformation) security.declareObjectProtected(Permissions.AccessContentsInformation)
......
...@@ -114,7 +114,7 @@ ...@@ -114,7 +114,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: [(\'\', \'\')] + [(x.getTitle(), x.getRelativeUrl()) for x in context.portal_catalog(portal_type=\'Budget Model\')]</string> </value> <value> <string>python: [(x.getTranslatedTitle(), x.getRelativeUrl()) for x in context.portal_catalog(portal_type=\'Budget Model\')]</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -280,7 +280,7 @@ ...@@ -280,7 +280,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: context.ERP5Site_getWorkflowStateItemList(portal_type=\'Budget\', state_var=\'validation_state\')</string> </value> <value> <string>python: context.ERP5Site_getWorkflowStateItemList(portal_type=\'Budget\', state_var=\'validation_state\', display_none_category=False)</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -263,7 +263,7 @@ ...@@ -263,7 +263,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: here.portal_categories[field.getId().replace(\'your_\', \'\', 1).replace(\'_list\', \'\')].getCategoryChildCompactLogicalPathItemList(local_sort_id="int_index", checked_permission=\'View\')</string> </value> <value> <string>python: here.portal_categories[field.getId().replace(\'your_\', \'\', 1).replace(\'_list\', \'\')].getCategoryChildCompactLogicalPathItemList(local_sort_id="int_index", checked_permission=\'View\', display_none_category=False)</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -50,6 +50,7 @@ from Products.ERP5Form.Form import field_value_cache ...@@ -50,6 +50,7 @@ from Products.ERP5Form.Form import field_value_cache
from Products.ERP5Form.Form import getFieldValue from Products.ERP5Form.Form import getFieldValue
from Products.ERP5Form import ProxyField from Products.ERP5Form import ProxyField
from DateTime import DateTime from DateTime import DateTime
import lxml.html
from Products.Formulator.Widget import NSMAP from Products.Formulator.Widget import NSMAP
ODG_XML_WRAPPING_XPATH = 'draw:text-box/text:p/text:span' ODG_XML_WRAPPING_XPATH = 'draw:text-box/text:p/text:span'
...@@ -534,6 +535,8 @@ class TestListField(ERP5TypeTestCase): ...@@ -534,6 +535,8 @@ class TestListField(ERP5TypeTestCase):
def afterSetUp(self): def afterSetUp(self):
self.field = ListField('test_field') self.field = ListField('test_field')
self.field.values['items'] = [('My first Line', '1'), ('My Second Line', '2')]
self.field.values['default'] = '2'
self.widget = self.field.widget self.widget = self.field.widget
self.createCategories() self.createCategories()
self.tic() self.tic()
...@@ -553,9 +556,6 @@ class TestListField(ERP5TypeTestCase): ...@@ -553,9 +556,6 @@ class TestListField(ERP5TypeTestCase):
int_index=2) int_index=2)
def test_render_odt(self): def test_render_odt(self):
items = [('My first Line', '1'), ('My Second Line', '2')]
self.field.values['items'] = items
self.field.values['default'] = '2'
element = self.field.render_odt(as_string=False) element = self.field.render_odt(as_string=False)
self.assertEqual('{%(text)s}p' % NSMAP, element.tag) self.assertEqual('{%(text)s}p' % NSMAP, element.tag)
self.assertEqual('My Second Line', element.text) self.assertEqual('My Second Line', element.text)
...@@ -565,6 +565,44 @@ class TestListField(ERP5TypeTestCase): ...@@ -565,6 +565,44 @@ class TestListField(ERP5TypeTestCase):
element = self.field.render_odt(as_string=False) element = self.field.render_odt(as_string=False)
self.assertEqual('??? (3)', element.text) self.assertEqual('??? (3)', element.text)
def test_render(self):
select, input_element, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
# listfields render an input to confirm that the field was posted
# in the form's action script
self.assertEqual(input_element.name, 'default_field_test_field:int')
self.assertEqual(input_element.type, 'hidden')
self.assertEqual(select.tag, 'select')
first, second = select
self.assertEqual(first.tag, 'option')
self.assertEqual(first.text_content(), 'My first Line')
self.assertEqual(first.attrib['value'], '1')
self.assertEqual(second.tag, 'option')
self.assertEqual(second.text_content(), 'My Second Line')
self.assertEqual(second.attrib['value'], '2',)
self.assertTrue(second.attrib['selected'])
def test_render_escape_html(self):
self.field.values['default'] = ''
self.field.values['items'] = [
('<script>alert("text content")</script>', '<script>alert("value")</script>'),]
(script, ), _, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
self.assertEqual(script.attrib['value'], '<script>alert("value")</script>')
self.assertEqual(script.text_content(), '<script>alert("text content")</script>')
# selected
self.field.values['default'] = self.field.values['items'][0][1]
(script, ), _, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
self.assertEqual(script.attrib['value'], '<script>alert("value")</script>')
self.assertEqual(script.text_content(), '<script>alert("text content")</script>')
def test_render_disabled(self):
self.field.values['default'] = ''
# None items are rendered as disabled
self.field.values['items'] = [('Disabled', None)]
(disabled, ), _, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
self.assertTrue(disabled.attrib['disabled'])
self.assertFalse(disabled.attrib.get('value'))
def test_listField_value_order(self): def test_listField_value_order(self):
'''This test check the list field value order '''This test check the list field value order
...@@ -606,6 +644,46 @@ class TestMultiListField(ERP5TypeTestCase): ...@@ -606,6 +644,46 @@ class TestMultiListField(ERP5TypeTestCase):
self.field.values['items'] = [('A', 'a',), ('B', 'b')] self.field.values['items'] = [('A', 'a',), ('B', 'b')]
self.field.values['default'] = ['a', 'b'] self.field.values['default'] = ['a', 'b']
def test_render(self):
select, input_element, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
# listfields render an input to confirm that the field was posted
# in the form's action script
self.assertEqual(input_element.name, 'default_field_test_field:int')
self.assertEqual(input_element.type, 'hidden')
self.assertEqual(select.tag, 'select')
first, second = select
self.assertEqual(first.tag, 'option')
self.assertEqual(first.text_content(), 'A')
self.assertEqual(first.attrib['value'], 'a')
self.assertTrue(second.attrib['selected'])
self.assertEqual(second.tag, 'option')
self.assertEqual(second.text_content(), 'B')
self.assertEqual(second.attrib['value'], 'b',)
self.assertTrue(second.attrib['selected'])
def test_render_escape_html(self):
self.field.values['default'] = []
self.field.values['items'] = [
('<script>alert("text content")</script>', '<script>alert("value")</script>')]
(script, ), _, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
self.assertEqual(script.attrib['value'], '<script>alert("value")</script>')
self.assertEqual(script.text_content(), '<script>alert("text content")</script>')
# selected
self.field.values['default'] = [self.field.values['items'][0][1]]
(script, ), _, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
self.assertEqual(script.attrib['value'], '<script>alert("value")</script>')
self.assertEqual(script.text_content(), '<script>alert("text content")</script>')
def test_render_disabled(self):
# None items are rendered as disabled
self.field.values['default'] = []
self.field.values['items'] = [('Disabled', None)]
(disabled, ), _, = lxml.html.fragments_fromstring(self.field.render()) # pylint:disable=unbalanced-tuple-unpacking
self.assertTrue(disabled.attrib['disabled'])
self.assertFalse(disabled.attrib.get('value'))
def test_render_view(self): def test_render_view(self):
self.assertEqual('A<br />\nB', self.field.render_view(value=['a', 'b'])) self.assertEqual('A<br />\nB', self.field.render_view(value=['a', 'b']))
......
...@@ -56,7 +56,7 @@ for header in re.findall("<h[1-6].*?</h[1-6]>", doc_content or blank): ...@@ -56,7 +56,7 @@ for header in re.findall("<h[1-6].*?</h[1-6]>", doc_content or blank):
html_quote(header_reference_prefix), html_quote(header_reference_prefix),
'_anchor">', '_anchor">',
html_quote(header_reference), html_quote(header_reference),
'</div></a>'] '</a></div>']
) )
closer = int(header_current) * '</ol>' closer = int(header_current) * '</ol>'
......
...@@ -316,7 +316,7 @@ ...@@ -316,7 +316,7 @@
</tal:block--> </tal:block-->
<section class="ci-book-table-of-content"><p class="ci-book-toc-faux-h1">Table of Contents</p><ol><li><div><a href="#introduction0_anchor">Introduction</div></a><ol><li><div><a href="#references1_anchor">References</div></a><ol><li><div><a href="#applicable-documents2_anchor">Applicable Documents</div></a></li><li><div><a href="#referenced-documents3_anchor">Referenced Documents</div></a></li></ol><li><div><a href="#abbreviations4_anchor">Abbreviations</div></a></li><li><div><a href="#figures5_anchor">Figures</div></a></li><li><div><a href="#tables6_anchor">Tables</div></a></li></ol><li><div><a href="#synthese7_anchor">Synthese</div></a><ol><li><div><a href="#risks-and-measures8_anchor">Risks and measures</div></a><ol><li><div><a href="#risk-of-casualties-if-device-does-not-stop-and-destroys-itself9_anchor">Risk of casualties if device does not stop and destroys itself</div></a></li><li><div><a href="#risk-of-killing-birds-and-polluting-the-environment10_anchor">Risk of killing birds and polluting the environment</div></a></li><li><div><a href="#noise-and-vibration-levels11_anchor">Noise and vibration levels</div></a></li></ol></li></ol><li><div><a href="#header-embedded-document12_anchor">Header Embedded Document</div></a><ol><li><div><a href="#header-embedded-document-content-examples13_anchor">Header Embedded Document content Examples</div></a></li></ol><li><div><a href="#reports14_anchor">Reports</div></a><ol><li><div><a href="#project-reports15_anchor">Project Reports</div></a></li><li><div><a href="#sale-order-reports16_anchor">Sale Order Reports</div></a></ol></ol></section> <section class="ci-book-table-of-content"><p class="ci-book-toc-faux-h1">Table of Contents</p><ol><li><div><a href="#introduction0_anchor">Introduction</a></div><ol><li><div><a href="#references1_anchor">References</a></div><ol><li><div><a href="#applicable-documents2_anchor">Applicable Documents</a></div></li><li><div><a href="#referenced-documents3_anchor">Referenced Documents</a></div></li></ol><li><div><a href="#abbreviations4_anchor">Abbreviations</a></div></li><li><div><a href="#figures5_anchor">Figures</a></div></li><li><div><a href="#tables6_anchor">Tables</a></div></li></ol><li><div><a href="#synthese7_anchor">Synthese</a></div><ol><li><div><a href="#risks-and-measures8_anchor">Risks and measures</a></div><ol><li><div><a href="#risk-of-casualties-if-device-does-not-stop-and-destroys-itself9_anchor">Risk of casualties if device does not stop and destroys itself</a></div></li><li><div><a href="#risk-of-killing-birds-and-polluting-the-environment10_anchor">Risk of killing birds and polluting the environment</a></div></li><li><div><a href="#noise-and-vibration-levels11_anchor">Noise and vibration levels</a></div></li></ol></li></ol><li><div><a href="#header-embedded-document12_anchor">Header Embedded Document</a></div><ol><li><div><a href="#header-embedded-document-content-examples13_anchor">Header Embedded Document content Examples</a></div></li></ol><li><div><a href="#reports14_anchor">Reports</a></div><ol><li><div><a href="#project-reports15_anchor">Project Reports</a></div></li><li><div><a href="#sale-order-reports16_anchor">Sale Order Reports</a></div></ol></ol></section>
......
...@@ -89,7 +89,7 @@ ...@@ -89,7 +89,7 @@
<section class="ci-book-table-of-content"><p class="ci-book-toc-faux-h1">Inhaltsverzeichnis</p><ol><li><div><a href="#synthese0_anchor">Synthese</div></a><ol><li><div><a href="#risks-and-measures1_anchor">Risks and measures</div></a><ol><li><div><a href="#risk-of-casualties-if-device-does-not-stop-and-destroys-itself2_anchor">Risk of casualties if device does not stop and destroys itself</div></a></li><li><div><a href="#risk-of-killing-birds-and-polluting-the-environment3_anchor">Risk of killing birds and polluting the environment</div></a></li><li><div><a href="#noise-and-vibration-levels4_anchor">Noise and vibration levels</div></a></li></ol></li></ol><li><div><a href="#reports5_anchor">Reports</div></a><ol><li><div><a href="#project-reports6_anchor">Project Reports</div></a></li><li><div><a href="#sale-order-reports7_anchor">Sale Order Reports</div></a></ol></ol></section> <section class="ci-book-table-of-content"><p class="ci-book-toc-faux-h1">Inhaltsverzeichnis</p><ol><li><div><a href="#synthese0_anchor">Synthese</a></div><ol><li><div><a href="#risks-and-measures1_anchor">Risks and measures</a></div><ol><li><div><a href="#risk-of-casualties-if-device-does-not-stop-and-destroys-itself2_anchor">Risk of casualties if device does not stop and destroys itself</a></div></li><li><div><a href="#risk-of-killing-birds-and-polluting-the-environment3_anchor">Risk of killing birds and polluting the environment</a></div></li><li><div><a href="#noise-and-vibration-levels4_anchor">Noise and vibration levels</a></div></li></ol></li></ol><li><div><a href="#reports5_anchor">Reports</a></div><ol><li><div><a href="#project-reports6_anchor">Project Reports</a></div></li><li><div><a href="#sale-order-reports7_anchor">Sale Order Reports</a></div></ol></ol></section>
<h1><a name="synthese0_anchor"></a>Synthese<a class="custom-para" href=#synthese0_anchor><span style="font-size:.75em;line-height:1em;padding-left:.5em;">&para;</span></a></h1> <h1><a name="synthese0_anchor"></a>Synthese<a class="custom-para" href=#synthese0_anchor><span style="font-size:.75em;line-height:1em;padding-left:.5em;">&para;</span></a></h1>
......
...@@ -118,7 +118,7 @@ ...@@ -118,7 +118,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: getattr(here.portal_categories[field.getId().replace(\'your_\', \'\', 1).replace(\'_relative_url\', \'\')], preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', base=1)</string> </value> <value> <string>python: getattr(here.portal_categories[field.getId().replace(\'your_\', \'\', 1).replace(\'_relative_url\', \'\')], preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', base=1, display_none_category=False)</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -397,7 +397,7 @@ ...@@ -397,7 +397,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_default_view_action_reference</string> </key> <key> <string>configuration_default_view_action_reference</string> </key>
......
...@@ -367,7 +367,7 @@ ...@@ -367,7 +367,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_default_jio_document_page_gadget_url</string> </key> <key> <string>configuration_default_jio_document_page_gadget_url</string> </key>
......
...@@ -397,7 +397,7 @@ ...@@ -397,7 +397,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_default_view_action_reference</string> </key> <key> <string>configuration_default_view_action_reference</string> </key>
......
...@@ -395,7 +395,7 @@ ...@@ -395,7 +395,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_default_jio_document_page_gadget_url</string> </key> <key> <string>configuration_default_jio_document_page_gadget_url</string> </key>
......
...@@ -397,7 +397,7 @@ ...@@ -397,7 +397,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_default_view_action_reference</string> </key> <key> <string>configuration_default_view_action_reference</string> </key>
......
...@@ -367,7 +367,7 @@ ...@@ -367,7 +367,7 @@
</item> </item>
<item> <item>
<key> <string>configuration_content_security_policy</string> </key> <key> <string>configuration_content_security_policy</string> </key>
<value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value> <value> <string>default-src \'self\'; img-src \'self\' data:; media-src \'self\' blob:; connect-src \'self\' https://content.dropboxapi.com https://api.dropboxapi.com mail.tiolive.com data: *.host.vifib.net *.node.vifib.com *.erp5.net *.nexedi.net https://netdna.bootstrapcdn.com; script-src \'self\' \'unsafe-eval\' \'unsafe-inline\'; font-src \'self\' netdna.bootstrapcdn.com; style-src \'self\' netdna.bootstrapcdn.com \'unsafe-inline\' data:; frame-src \'self\' data:</string> </value>
</item> </item>
<item> <item>
<key> <string>configuration_default_jio_document_page_gadget_url</string> </key> <key> <string>configuration_default_jio_document_page_gadget_url</string> </key>
......
...@@ -118,7 +118,7 @@ ...@@ -118,7 +118,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: getattr(here.portal_categories.use, preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', base=True)</string> </value> <value> <string>python: getattr(here.portal_categories.use, preferences.getPreference(\'preferred_category_child_item_list_method_id\', \'getCategoryChildCompactLogicalPathItemList\'))(local_sort_id=(\'int_index\', \'translated_title\'), checked_permission=\'View\', base=True, display_none_category=False)</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -22,7 +22,11 @@ ...@@ -22,7 +22,11 @@
.declareMethod("render", function () { .declareMethod("render", function () {
var gadget = this; var gadget = this;
return new RSVP.Queue() return new RSVP.Queue(
// Stabilise UI tests with a tiny delay, which should be unnoticeable
// to users.
RSVP.delay(200)
)
.push(function () { .push(function () {
return RSVP.all([ return RSVP.all([
gadget.getUrlForList([{command: 'history_previous'}]), gadget.getUrlForList([{command: 'history_previous'}]),
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
</tr> </tr>
<tr> <tr>
<td>assertEval</td> <td>assertEval</td>
<td>(function() { selenium.browserbot.getCurrentWindow().document.getElementById("field_my_foo_category_title").value = "%"; return true;})() <td>(function() { selenium.browserbot.getCurrentWindow().document.getElementById("field_my_foo_category_title").value = "Qua%"; return true;})()
<td>true</td> <td>true</td>
</tr> </tr>
<tr> <tr>
......
...@@ -68,6 +68,12 @@ UID_SAFE_BITSIZE = 63 ...@@ -68,6 +68,12 @@ UID_SAFE_BITSIZE = 63
# enough while yielding one order of magnitude collision probability # enough while yielding one order of magnitude collision probability
# improvement. # improvement.
UID_ALLOCATION_TRY_COUNT = 10 UID_ALLOCATION_TRY_COUNT = 10
# Limit the number of UNION-joined subqueries per query when looking for
# blocking activities. Used to take a slice from a list.
# XXX: 5000 is known to work on a case on "after_tag" dependency, which fails
# at 5400 with:
# ProgrammingError: (1064, "memory exhausted near [...]")
_MAX_DEPENDENCY_UNION_SUBQUERY_COUNT = -5000
def sort_message_key(message): def sort_message_key(message):
# same sort key as in SQLBase.getMessageList # same sort key as in SQLBase.getMessageList
...@@ -181,37 +187,42 @@ def _validate_after_tag_and_method_id(value, render_string): ...@@ -181,37 +187,42 @@ def _validate_after_tag_and_method_id(value, render_string):
# same order as the dependency value items expected by the next item # same order as the dependency value items expected by the next item
# - callable rendering given values into an SQL condition # - callable rendering given values into an SQL condition
# (value, render_string) -> str # (value, render_string) -> str
# - minimal applicable processing_node value (excluded)
_DEPENDENCY_TESTER_DICT = { _DEPENDENCY_TESTER_DICT = {
'after_method_id': ( 'after_method_id': (
('method_id', ), ('method_id', ),
sqltest_dict['method_id'], sqltest_dict['method_id'],
DEPENDENCY_IGNORED_ERROR_STATE,
), ),
'after_path': ( 'after_path': (
('path', ), ('path', ),
sqltest_dict['path'], sqltest_dict['path'],
DEPENDENCY_IGNORED_ERROR_STATE,
), ),
'after_message_uid': ( 'after_message_uid': (
('uid', ), ('uid', ),
sqltest_dict['uid'], sqltest_dict['uid'],
DEPENDENCY_IGNORED_ERROR_STATE,
), ),
'after_path_and_method_id': ( 'after_path_and_method_id': (
('path', 'method_id'), ('path', 'method_id'),
_validate_after_path_and_method_id, _validate_after_path_and_method_id,
DEPENDENCY_IGNORED_ERROR_STATE,
), ),
'after_tag': ( 'after_tag': (
('tag', ), ('tag', ),
sqltest_dict['tag'], sqltest_dict['tag'],
DEPENDENCY_IGNORED_ERROR_STATE,
), ),
'after_tag_and_method_id': ( 'after_tag_and_method_id': (
('tag', 'method_id'), ('tag', 'method_id'),
_validate_after_tag_and_method_id, _validate_after_tag_and_method_id,
DEPENDENCY_IGNORED_ERROR_STATE,
), ),
'serialization_tag': ( 'serialization_tag': (
('serialization_tag', ), ('serialization_tag', ),
lambda value, render_string: ( sqltest_dict['serialization_tag'],
'processing_node > -1 AND ' + -1,
sqltest_dict['serialization_tag'](value, render_string)
),
), ),
} }
...@@ -460,7 +471,7 @@ CREATE TABLE %s ( ...@@ -460,7 +471,7 @@ CREATE TABLE %s (
dependency_value, dependency_value,
) in message.activity_kw.iteritems(): ) in message.activity_kw.iteritems():
try: try:
column_list, _ = dependency_tester_dict[dependency_name] column_list, _, _ = dependency_tester_dict[dependency_name]
except KeyError: except KeyError:
continue continue
# There are 2 types of dependencies: # There are 2 types of dependencies:
...@@ -569,14 +580,16 @@ CREATE TABLE %s ( ...@@ -569,14 +580,16 @@ CREATE TABLE %s (
if not dependency_value_dict: if not dependency_value_dict:
# No more non-blocked message for this dependency, skip it. # No more non-blocked message for this dependency, skip it.
continue continue
column_list, to_sql = dependency_tester_dict[dependency_name] column_list, to_sql, min_processing_node = dependency_tester_dict[
dependency_name
]
row2key = ( row2key = (
_ITEMGETTER0 _ITEMGETTER0
if len(column_list) == 1 else if len(column_list) == 1 else
_IDENTITY _IDENTITY
) )
base_sql_suffix = ' WHERE processing_node > %i AND (%%s) LIMIT 1)' % ( base_sql_suffix = ' WHERE processing_node > %i AND (%%s) LIMIT 1)' % (
DEPENDENCY_IGNORED_ERROR_STATE, min_processing_node,
) )
sql_suffix_list = [ sql_suffix_list = [
base_sql_suffix % to_sql(dependency_value, quote) base_sql_suffix % to_sql(dependency_value, quote)
...@@ -585,22 +598,30 @@ CREATE TABLE %s ( ...@@ -585,22 +598,30 @@ CREATE TABLE %s (
base_sql_prefix = '(SELECT %s FROM ' % ( base_sql_prefix = '(SELECT %s FROM ' % (
','.join(column_list), ','.join(column_list),
) )
for row in db.query( subquery_list = [
' UNION '.join( base_sql_prefix + table_name + sql_suffix
base_sql_prefix + table_name + sql_suffix for table_name in table_name_list
for table_name in table_name_list for sql_suffix in sql_suffix_list
for sql_suffix in sql_suffix_list ]
), while subquery_list:
max_rows=0, # Join queries with a UNION, to reduce per-query latency.
)[1]: # Also, limit the number of subqueries per query, as their number can
# Each row is a value which blocks some activities. # largely exceed the number of activities being considered multiplied
dependent_message_set = dependency_value_dict[row2key(row)] # by the number of activty tables: it is also proportional to the
# queue blocked messages for processing in the beginning of next # number of distinct values being looked for in the current column.
# outermost iteration. for row in db.query(
new_blocked_message_set.update(dependent_message_set) ' UNION '.join(subquery_list[_MAX_DEPENDENCY_UNION_SUBQUERY_COUNT:]),
# ...but update result immediately, in case there is no next max_rows=0,
# outermost iteration. )[1]:
result.difference_update(dependent_message_set) # Each row is a value which blocks some activities.
dependent_message_set = dependency_value_dict[row2key(row)]
# queue blocked messages for processing in the beginning of next
# outermost iteration.
new_blocked_message_set |= dependent_message_set
# ...but update result immediately, in case there is no next
# outermost iteration.
result -= dependent_message_set
del subquery_list[_MAX_DEPENDENCY_UNION_SUBQUERY_COUNT:]
dependency_value_dict.clear() dependency_value_dict.clear()
return result return result
......
...@@ -116,10 +116,6 @@ ...@@ -116,10 +116,6 @@
<key> <string>all_columns</string> </key> <key> <string>all_columns</string> </key>
<value> <value>
<list> <list>
<tuple>
<string>language</string>
<string>Language</string>
</tuple>
<tuple> <tuple>
<string>revision</string> <string>revision</string>
<string>Revision</string> <string>Revision</string>
...@@ -185,6 +181,10 @@ ...@@ -185,6 +181,10 @@
<string>version</string> <string>version</string>
<string>Version</string> <string>Version</string>
</tuple> </tuple>
<tuple>
<string>language</string>
<string>Language</string>
</tuple>
<tuple> <tuple>
<string>description</string> <string>description</string>
<string>Description</string> <string>Description</string>
......
...@@ -6,28 +6,92 @@ portal_caches/erp5_content_medium/default_ram_cache ...@@ -6,28 +6,92 @@ portal_caches/erp5_content_medium/default_ram_cache
portal_caches/erp5_content_short portal_caches/erp5_content_short
portal_caches/erp5_content_short/default_ram_cache portal_caches/erp5_content_short/default_ram_cache
portal_caches/erp5_session_cache portal_caches/erp5_session_cache
portal_caches/erp5_session_cache/** portal_caches/erp5_session_cache/2
portal_caches/erp5_ui_long portal_caches/erp5_ui_long
portal_caches/erp5_ui_long/default_ram_cache portal_caches/erp5_ui_long/default_ram_cache
portal_caches/erp5_ui_medium portal_caches/erp5_ui_medium
portal_caches/erp5_ui_medium/default_ram_cache portal_caches/erp5_ui_medium/default_ram_cache
portal_caches/erp5_ui_short portal_caches/erp5_ui_short
portal_caches/erp5_ui_short/default_ram_cache portal_caches/erp5_ui_short/default_ram_cache
portal_categories/action_type/* portal_categories/action_type/global
portal_categories/callable_type/** portal_categories/action_type/object_action
portal_categories/action_type/object_button
portal_categories/action_type/object_dialog
portal_categories/action_type/object_exchange
portal_categories/action_type/object_exchange_raw
portal_categories/action_type/object_fast_input
portal_categories/action_type/object_fast_input_raw
portal_categories/action_type/object_icon
portal_categories/action_type/object_jio_action
portal_categories/action_type/object_jio_action_raw
portal_categories/action_type/object_jio_button
portal_categories/action_type/object_jio_button_raw
portal_categories/action_type/object_jio_exchange
portal_categories/action_type/object_jio_exchange_raw
portal_categories/action_type/object_jio_fast_input
portal_categories/action_type/object_jio_fast_input_raw
portal_categories/action_type/object_jio_js_script
portal_categories/action_type/object_jio_jump
portal_categories/action_type/object_jio_jump_raw
portal_categories/action_type/object_jio_print
portal_categories/action_type/object_jio_print_raw
portal_categories/action_type/object_jio_report
portal_categories/action_type/object_jio_report_raw
portal_categories/action_type/object_jio_search
portal_categories/action_type/object_jio_view
portal_categories/action_type/object_jump
portal_categories/action_type/object_list
portal_categories/action_type/object_onlyjio_action
portal_categories/action_type/object_onlyjio_action_raw
portal_categories/action_type/object_onlyjio_button
portal_categories/action_type/object_onlyjio_button_raw
portal_categories/action_type/object_onlyjio_jump
portal_categories/action_type/object_onlyjio_jump_raw
portal_categories/action_type/object_onlyjio_view
portal_categories/action_type/object_onlyxhtml_view
portal_categories/action_type/object_print
portal_categories/action_type/object_print_raw
portal_categories/action_type/object_report
portal_categories/action_type/object_report_raw
portal_categories/action_type/object_search
portal_categories/action_type/object_view
portal_categories/action_type/object_web_view
portal_categories/action_type/workflow
portal_categories/callable_type/script
portal_categories/callable_type/script/diff_filter
portal_categories/constraint_type/audit portal_categories/constraint_type/audit
portal_categories/constraint_type/configuration portal_categories/constraint_type/configuration
portal_categories/constraint_type/default portal_categories/constraint_type/default
portal_categories/constraint_type/post_upgrade portal_categories/constraint_type/post_upgrade
portal_categories/constraint_type/pre_upgrade portal_categories/constraint_type/pre_upgrade
portal_categories/constraint_type/upgrader portal_categories/constraint_type/upgrader
portal_categories/elementary_type/** portal_categories/elementary_type/boolean
portal_categories/elementary_type/content
portal_categories/elementary_type/data
portal_categories/elementary_type/date
portal_categories/elementary_type/float
portal_categories/elementary_type/int
portal_categories/elementary_type/lines
portal_categories/elementary_type/long
portal_categories/elementary_type/multiple selection
portal_categories/elementary_type/object
portal_categories/elementary_type/selection
portal_categories/elementary_type/string
portal_categories/elementary_type/tales
portal_categories/elementary_type/text
portal_categories/elementary_type/tokens
portal_contribution_registry/default_predicate portal_contribution_registry/default_predicate
portal_domains/base_day_domain portal_domains/base_day_domain
portal_domains/base_month_domain portal_domains/base_month_domain
portal_domains/base_week_domain portal_domains/base_week_domain
portal_domains/base_year_domain portal_domains/base_year_domain
portal_domains/parent_domain portal_domains/parent_domain
portal_ids/** portal_ids/1
portal_ids/2
portal_ids/3
portal_ids/4
portal_ids/5
portal_ids/6
portal_ids/mysql_non_continuous_increasing_non_zodb
portal_memcached/default_memcached_plugin portal_memcached/default_memcached_plugin
portal_preferences/default_site_preference portal_preferences/default_site_preference
\ No newline at end of file
...@@ -88,7 +88,11 @@ class TestInvalidationBug(ERP5TypeTestCase): ...@@ -88,7 +88,11 @@ class TestInvalidationBug(ERP5TypeTestCase):
self.assertEqual(result_list[1], [0,0]) # activity buffer first self.assertEqual(result_list[1], [0,0]) # activity buffer first
self.assertEqual(result_list[-3], [1,0]) # catalog self.assertEqual(result_list[-3], [1,0]) # catalog
self.assertEqual(result_list[-2], None) # ZODB self.assertEqual(result_list[-2], None) # ZODB
self.assertEqual(result_list[-1], [1,1]) # activity tables last result_catalog_count, result_activity_count = result_list[-1]
# activity tables last (there may be multiple activities, but there must be
# at least one).
self.assertEqual(result_catalog_count, 1)
self.assertGreaterEqual(result_activity_count, 1)
# TODO: - skip this test for ZEO>=5 because it's covered upstream # TODO: - skip this test for ZEO>=5 because it's covered upstream
# (and later remove it) # (and later remove it)
...@@ -168,8 +172,9 @@ class TestInvalidationBug(ERP5TypeTestCase): ...@@ -168,8 +172,9 @@ class TestInvalidationBug(ERP5TypeTestCase):
unpatch() unpatch()
activity_tool.manage_addToProcessingList(node_list) activity_tool.manage_addToProcessingList(node_list)
self.commit() self.commit()
## When the bug is not fixed, we get a -3 failed activity ## When the bug is not fixed, we get a failed activity
self.assertNoPendingMessage() ## which would cause tic to fail
self.tic()
def _testReindex(self): def _testReindex(self):
print("To reproduce bugs easily, distribution step should be skipped for" print("To reproduce bugs easily, distribution step should be skipped for"
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
# #
############################################################################## ##############################################################################
import cgi
import unittest import unittest
import os import os
import requests import requests
...@@ -34,6 +35,7 @@ from requests.adapters import HTTPAdapter ...@@ -34,6 +35,7 @@ from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry from requests.packages.urllib3.util.retry import Retry
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
from AccessControl import getSecurityManager
from Testing import ZopeTestCase from Testing import ZopeTestCase
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.utils import addUserToDeveloperRole, findContentChain from Products.ERP5Type.tests.utils import addUserToDeveloperRole, findContentChain
...@@ -674,9 +676,20 @@ def makeTestMethod(validator, portal_type, view_name, bt_name): ...@@ -674,9 +676,20 @@ def makeTestMethod(validator, portal_type, view_name, bt_name):
self.portal, self.portal,
portal_type) portal_type)
document = createSubContent(module, portal_type_list) document = createSubContent(module, portal_type_list)
view = getattr(document, view_name)
response = self.publish(
'%s/%s' % (document.getPath(), view_name),
user=str(getSecurityManager().getUser()),
handle_errors=False,
)
charset = 'iso8859-15'
content_type = response.getHeader('content-type')
if content_type:
_, params = cgi.parse_header(content_type)
charset = params.get('charset', charset)
self.assert_(*validate_xhtml( validator=validator, self.assert_(*validate_xhtml( validator=validator,
source=view(), source=response.getBody().decode(charset),
view_name=view_name, view_name=view_name,
bt_name=bt_name)) bt_name=bt_name))
return testMethod return testMethod
...@@ -742,6 +755,19 @@ if validator_to_use == 'tidy': ...@@ -742,6 +755,19 @@ if validator_to_use == 'tidy':
elif validator_to_use == 'nu': elif validator_to_use == 'nu':
validator = NuValidator(show_warnings) validator = NuValidator(show_warnings)
expected_failure_list = (
# this view needs VCS preference set (this test suite does not support
# setting preferences, but this might be a way to fix this).
'test_erp5_forge_Business_Template_BusinessTemplate_viewVcsStatus',
# this view only works when solver decision has a relation to a solver.
# One way to fix this would be to allow a custom "init script" to be called
# on a portal type.
'test_erp5_simulation_Solver_Decision_SolverDecision_viewConfiguration',
# this view redirects to an external URL
'test_erp5_web_Static_Web_Site_WebSite_view',
)
def test_suite(): def test_suite():
# add the tests # add the tests
if validator is not None: if validator is not None:
...@@ -749,15 +775,7 @@ def test_suite(): ...@@ -749,15 +775,7 @@ def test_suite():
# on getBusinessTemplateList call # on getBusinessTemplateList call
addTestMethodDynamically(TestXHTML, validator, addTestMethodDynamically(TestXHTML, validator,
('erp5_core',) + TestXHTML.getBusinessTemplateList(), ('erp5_core',) + TestXHTML.getBusinessTemplateList(),
expected_failure_list=( expected_failure_list=expected_failure_list)
# this view needs VCS preference set (this test suite does not support
# setting preferences, but this might be a way to fix this).
'test_erp5_forge_Business_Template_BusinessTemplate_viewVcsStatus',
# this view only works when solver decision has a relation to a solver.
# One way to fix this would be to allow a custom "init script" to be called
# on a portal type.
'test_erp5_simulation_Solver_Decision_SolverDecision_viewConfiguration',
))
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestXHTML)) suite.addTest(unittest.makeSuite(TestXHTML))
return suite return suite
...@@ -38,7 +38,7 @@ marker_ = [] ...@@ -38,7 +38,7 @@ marker_ = []
def log(description, content=marker_, level=INFO): def log(description, content=marker_, level=INFO):
"""Deprecated method """Deprecated method
Use erp5.componement.Log instead. Use erp5.component.module.Log instead.
Kept for compatbility to allow instance upgrade. Kept for compatbility to allow instance upgrade.
""" """
......
...@@ -114,15 +114,7 @@ def test_suite(): ...@@ -114,15 +114,7 @@ def test_suite():
testclass, testclass,
testXHTML.validator, testXHTML.validator,
tested_business_template_list, tested_business_template_list,
expected_failure_list=( expected_failure_list=testXHTML.expected_failure_list,
# this view needs VCS preference set (this test suite does not support
# setting preferences, but this might be a way to fix this).
'test_erp5_forge_Business_Template_BusinessTemplate_viewVcsStatus',
# this view only works when solver decision has a relation to a solver.
# One way to fix this would be to allow a custom "init script" to be called
# on a portal type.
'test_erp5_simulation_Solver_Decision_SolverDecision_viewConfiguration',
),
) )
# required to create content in portal_components # required to create content in portal_components
......
...@@ -1027,7 +1027,7 @@ class MultiItemsWidget(ItemsWidget): ...@@ -1027,7 +1027,7 @@ class MultiItemsWidget(ItemsWidget):
if item_value in value: if item_value in value:
rendered_item = self.render_selected_item( rendered_item = self.render_selected_item(
escape(ustr(item_text)), escape(ustr(item_text)),
escape(ustr(item_value)), item_value,
key, key,
css_class, css_class,
extra_item) extra_item)
...@@ -1037,7 +1037,7 @@ class MultiItemsWidget(ItemsWidget): ...@@ -1037,7 +1037,7 @@ class MultiItemsWidget(ItemsWidget):
else: else:
rendered_item = self.render_item( rendered_item = self.render_item(
escape(ustr(item_text)), escape(ustr(item_text)),
escape(ustr(item_value)), item_value,
key, key,
css_class, css_class,
extra_item) extra_item)
......
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