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

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

parents cc2a8658 b7a60478
Pipeline #19891 failed with stage
in 0 seconds
...@@ -33,7 +33,7 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces ...@@ -33,7 +33,7 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces
from Products.ERP5Type.XMLObject import XMLObject from Products.ERP5Type.XMLObject import XMLObject
class Login(XMLObject, LoginAccountProviderMixin, EncryptedPasswordMixin): class Login(EncryptedPasswordMixin, XMLObject, LoginAccountProviderMixin):
meta_type = 'ERP5 Login' meta_type = 'ERP5 Login'
portal_type = 'Login' portal_type = 'Login'
add_permission = Permissions.AddPortalContent add_permission = Permissions.AddPortalContent
......
...@@ -60,7 +60,7 @@ class UserExistsError( ...@@ -60,7 +60,7 @@ class UserExistsError(
super(UserExistsError, self).__init__('user id %s already exists' % (user_id, )) super(UserExistsError, self).__init__('user id %s already exists' % (user_id, ))
class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin, ERP5UserMixin): class Person(EncryptedPasswordMixin, Node, LoginAccountProviderMixin, ERP5UserMixin):
""" """
An Person object holds the information about An Person object holds the information about
an person (ex. you, me, someone in the company, an person (ex. you, me, someone in the company,
......
...@@ -39,37 +39,45 @@ class IEncryptedPassword(Interface): ...@@ -39,37 +39,45 @@ class IEncryptedPassword(Interface):
def checkPassword(value): def checkPassword(value):
""" """
Check the password, usefull when changing password Check the password `value` match the current password, usefull when changing password.
""" """
def checkPasswordValueAcceptable(value): def checkPasswordValueAcceptable(value):
""" """
Check if the password value is acceptable - i.e. follows site rules. Check if the password `value` is acceptable in regard to password policy.
""" """
def setEncodedPassword(value, format='default'): # pylint: disable=redefined-builtin def checkUserCanChangePassword():
""" """
Set an already encoded password. Check if the current logged in user have permission to change password, on this
IEncryptedPassword.
Raise Products.CMFCore.exceptions.AccessControl_Unauthorized in case they don't
have the permission.
This method is deprecated and is not used by IEncryptedPassword internally.
""" """
def _forceSetPassword(value): def setPassword(value):
""" """
Because both _setPassword and setPassword are considered as Set the password to `value` (a string holding the password in clear text).
public method (they are callable from user directly or through edit method)
_forceSetPassword is needed to reset password without security check by Passing an empty value (such as None or empty string) will erase previously defined
Password Tool. This method is not callable through edit method as it not password, which usually prevent login with this password.
begins with _set*
""" """
def checkUserCanChangePassword(): def setEncodedPassword(value, format='default'): # pylint: disable=redefined-builtin
""" """
check user have permission to change his password. Raise in case he cannot. Set an already encoded password.
""" """
def setPassword(value) : def edit(self, **kw):
""" """
Set the password, only if the password is not empty and if Edit the password and other properties of the documents through user interface.
checkUserCanChangePassword don't raise any error
This method is responsible for supporting the case where a IEncryptedPassword is
edited with a my_password field that is empty by default and not resetting the password
when edited with password=None.
""" """
def getPassword(*args, **kw): def getPassword(*args, **kw):
...@@ -83,7 +91,7 @@ class IEncryptedPassword(Interface): ...@@ -83,7 +91,7 @@ class IEncryptedPassword(Interface):
Default: None Default: None
format (string) format (string)
String defining the format in which the password is expected. String defining the format in which the password is expected.
If passowrd is not available in that format, KeyError will be If password is not available in that format, KeyError will be
raised. raised.
Default: 'default' Default: 'default'
""" """
...@@ -39,7 +39,7 @@ from Products.ERP5Type.Globals import PersistentMapping ...@@ -39,7 +39,7 @@ from Products.ERP5Type.Globals import PersistentMapping
from Products.CMFCore.utils import _checkPermission from Products.CMFCore.utils import _checkPermission
from Products.CMFCore.exceptions import AccessControl_Unauthorized from Products.CMFCore.exceptions import AccessControl_Unauthorized
class EncryptedPasswordMixin: class EncryptedPasswordMixin(object):
# Declarative security # Declarative security
security = ClassSecurityInfo() security = ClassSecurityInfo()
...@@ -68,7 +68,7 @@ class EncryptedPasswordMixin: ...@@ -68,7 +68,7 @@ class EncryptedPasswordMixin:
usage. usage.
""" """
if not self.getPortalObject().portal_preferences.isAuthenticationPolicyEnabled(): if not self.getPortalObject().portal_preferences.isAuthenticationPolicyEnabled():
# not a policy so basically all passwords are accceptable # not policy enabled, so basically all passwords are accceptable
return True return True
if not self.isPasswordValid(value): if not self.isPasswordValid(value):
raise ValueError("Password does not comply with password policy") raise ValueError("Password does not comply with password policy")
...@@ -87,7 +87,7 @@ class EncryptedPasswordMixin: ...@@ -87,7 +87,7 @@ class EncryptedPasswordMixin:
password = self.password = PersistentMapping() password = self.password = PersistentMapping()
self.password[format] = value self.password[format] = value
security.declarePublic('setEncodedPassword') security.declareProtected(Permissions.SetOwnPassword, 'setEncodedPassword')
def setEncodedPassword( def setEncodedPassword(
self, self,
value, value,
...@@ -95,27 +95,20 @@ class EncryptedPasswordMixin: ...@@ -95,27 +95,20 @@ class EncryptedPasswordMixin:
): ):
""" """
""" """
self.checkUserCanChangePassword()
self._setEncodedPassword(value, format=format) self._setEncodedPassword(value, format=format)
self.reindexObject() self.reindexObject()
def _forceSetPassword(self, value): def _forceSetPassword(self, value):
# this method is kept for backward compatibility, as there might be interaction
# workflows on this method.
self.password = PersistentMapping() self.password = PersistentMapping()
self._setEncodedPassword(pw_encrypt(value)) if value:
self._setEncodedPassword(pw_encrypt(value))
def _setPassword(self, value): def _setPassword(self, value):
self.checkUserCanChangePassword()
self.checkPasswordValueAcceptable(value) self.checkPasswordValueAcceptable(value)
self._forceSetPassword(value) self._forceSetPassword(value)
security.declarePublic('setPassword')
def setPassword(self, value) :
"""
"""
if value is not None:
self._setPassword(value)
self.reindexObject()
security.declareProtected(Permissions.AccessContentsInformation, 'getPassword') security.declareProtected(Permissions.AccessContentsInformation, 'getPassword')
def getPassword(self, *args, **kw): def getPassword(self, *args, **kw):
""" """
...@@ -140,4 +133,17 @@ class EncryptedPasswordMixin: ...@@ -140,4 +133,17 @@ class EncryptedPasswordMixin:
password = default_password password = default_password
return password return password
security.declareProtected(Permissions.ModifyPortalContent, 'edit')
def edit(self, *args, **kw):
"""edit, with support for empty password for the user interface.
In the user interface, we can have a my_password field, that will not
be pre-filled with the current password, but will be empty. To accomodate
this case, we don't edit the password if it is empty.
"""
if kw.get('password') is None:
kw.pop('password', None)
return super(EncryptedPasswordMixin, self).edit(*args, **kw)
InitializeClass(EncryptedPasswordMixin) InitializeClass(EncryptedPasswordMixin)
...@@ -181,13 +181,19 @@ class PresencePeriod(Movement, PeriodicityMixin): ...@@ -181,13 +181,19 @@ class PresencePeriod(Movement, PeriodicityMixin):
timezone = self._getTimezone(next_start_date) timezone = self._getTimezone(next_start_date)
next_start_date = self._getNextDay(next_start_date, timezone) next_start_date = self._getNextDay(next_start_date, timezone)
while 1:
# We use 366*28 below, because gregorian calendar repeat itself every 28 years, so we
# don't need to loop more than this if we don't find a date, because it might be an
# impossible combination of week and month (eg. week number 30 can not be in January)
for _ in range(366 * 28):
if (self._validateDay(next_start_date)) and \ if (self._validateDay(next_start_date)) and \
(self._validateWeek(next_start_date)) and \ (self._validateWeek(next_start_date)) and \
(self._validateMonth(next_start_date)): (self._validateMonth(next_start_date)):
break break
else: else:
next_start_date = self._getNextDay(next_start_date, timezone) next_start_date = self._getNextDay(next_start_date, timezone)
else:
return None
return DateTime( return DateTime(
next_start_date.year(), next_start_date.year(),
......
...@@ -1937,6 +1937,48 @@ class TestCalendar(ERP5ReportTestCase): ...@@ -1937,6 +1937,48 @@ class TestCalendar(ERP5ReportTestCase):
self.assertEqual([], assignment.asMovementList()) self.assertEqual([], assignment.asMovementList())
def test_GroupCalendarPeriodWeeksAndMonthPeriodicity(self):
"""Tests that combinations of periodicity weeks and months are handled correctly.
"""
node = self.portal.organisation_module.newContent(portal_type='Organisation',)
group_calendar = self.portal.group_calendar_module.newContent(
portal_type='Group Calendar')
group_calendar_period = group_calendar.newContent(
portal_type='Group Presence Period')
group_calendar_period.setStartDate('2000/01/01 08:00:00 UTC')
group_calendar_period.setStopDate('2000/01/01 09:00:00 UTC')
group_calendar_period.setQuantity(10)
group_calendar_period.setResourceValue(
self.portal.portal_categories.calendar_period_type.type1)
# this group calendar repeats every days of the first week of the year and the second
# months, which is impossible.
group_calendar_period.setPeriodicityWeekList((1, ))
group_calendar_period.setPeriodicityMonthList((2, ))
self.tic()
assignment = self.portal.group_calendar_assignment_module.newContent(
specialise_value=group_calendar,
resource_value=self.portal.portal_categories.calendar_period_type.type1,
start_date=DateTime('2000/01/01 08:00:00 UTC'),
stop_date=DateTime('2010/01/01 18:00:00 UTC'),
destination_value=node)
assignment.confirm()
self.tic()
self.assertFalse(assignment.asMovementList()) # ... and no infinite loop
# edge case, repeat every Friday of week 9 in February, this does not happen every year
group_calendar_period.setPeriodicityWeekList((9, ))
group_calendar_period.setPeriodicityMonthList((2, ))
group_calendar_period.setPeriodicityWeekDayList(['Friday'])
self.assertEqual(
[m.getStartDate() for m in assignment.asMovementList()],
[DateTime('2003/02/28 09:00:00 UTC'),
DateTime('2004/02/27 09:00:00 UTC'),
DateTime('2008/02/29 09:00:00 UTC'),
DateTime('2009/02/27 09:00:00 UTC'),])
def test_PersonModule_viewLeaveRequestReport(self): def test_PersonModule_viewLeaveRequestReport(self):
# in this test, type1 is the type for presences, type2 & type3 are types # in this test, type1 is the type for presences, type2 & type3 are types
# for leaves. # for leaves.
......
...@@ -4,7 +4,6 @@ from Products.ERP5Type import Permissions ...@@ -4,7 +4,6 @@ from Products.ERP5Type import Permissions
class Person(ERP5Person): class Person(ERP5Person):
security = ClassSecurityInfo() security = ClassSecurityInfo()
security.declarePublic('getCertificate')
def _getCertificateLoginDocument(self): def _getCertificateLoginDocument(self):
for _erp5_login in self.objectValues( for _erp5_login in self.objectValues(
...@@ -50,6 +49,7 @@ class Person(ERP5Person): ...@@ -50,6 +49,7 @@ class Person(ERP5Person):
return self.getPortalObject().portal_certificate_authority\ return self.getPortalObject().portal_certificate_authority\
.revokeCertificateByCommonName(self._getCertificateLoginDocument().getReference()) .revokeCertificateByCommonName(self._getCertificateLoginDocument().getReference())
security.declarePublic('getCertificate')
def getCertificate(self): def getCertificate(self):
"""Returns new SSL certificate""" """Returns new SSL certificate"""
self._checkCertificateRequest() self._checkCertificateRequest()
......
...@@ -63,27 +63,32 @@ class PortalTypeConfiguratorItem(ConfiguratorItemMixin, XMLObject): ...@@ -63,27 +63,32 @@ class PortalTypeConfiguratorItem(ConfiguratorItemMixin, XMLObject):
# arguments: # arguments:
# * target_portal_type # * target_portal_type
# * add_propertysheet_list # * add_propertysheet_list
type_information = getattr(portal.portal_types, self.target_portal_type) portal_type_value = portal.portal_types[self.target_portal_type]
property_sheet_list = portal_type_value.getTypePropertySheetList()
extra_property_sheet_list = []
for name in self.add_propertysheet_list: for name in self.add_propertysheet_list:
if not name in type_information.property_sheet_list: if name not in property_sheet_list:
new_property_sheet_list = list(type_information.property_sheet_list) extra_property_sheet_list.append(name)
new_property_sheet_list.append(name) # TODO: This class must support many other portal types features.
type_information.property_sheet_list = tuple(new_property_sheet_list) business_template_value = self.getBusinessConfigurationValue().getSpecialiseValue()
if extra_property_sheet_list:
business_configuration = self.getBusinessConfigurationValue() if fixit:
bt5_obj = business_configuration.getSpecialiseValue() portal_type_value.setTypePropertySheetList(
property_sheet_list + extra_property_sheet_list,
old_property_sheet_list = bt5_obj.getTemplatePortalTypePropertySheetList() )
new_property_sheet_list = (list(old_property_sheet_list) + business_template_value.edit(
['%s | %s' % (self.target_portal_type, name) template_portal_type_property_sheet_list=list(
for name in self.add_propertysheet_list] business_template_value.getTemplatePortalTypePropertySheetList()
) ) + [
if fixit: '%s | %s' % (self.target_portal_type, name)
bt5_obj.edit( for name in extra_property_sheet_list
template_portal_type_property_sheet_list=new_property_sheet_list) ],
# )
# TODO:This class must support many other features we can use in ZMI. return [
# 'Associate Property Sheets %r to %r in %r' % (
extra_property_sheet_list,
return ['Property Sheets configuration should be added in %s' % \ self.target_portal_type,
bt5_obj.getTitle(),] business_template_value.getTitle(),
),
]
return []
...@@ -5,7 +5,9 @@ keep_bt5_id_list = [] ...@@ -5,7 +5,9 @@ keep_bt5_id_list = []
bt5_update_catalog_list = ('erp5_ingestion_mysql_innodb_catalog', 'erp5_full_text_mroonga_catalog') bt5_update_catalog_list = ('erp5_ingestion_mysql_innodb_catalog', 'erp5_full_text_mroonga_catalog')
bt5_installation_list = bt5_update_catalog_list + ( bt5_installation_list = tuple(
context.getPortalObject().getCoreBusinessTemplateList(),
) + bt5_update_catalog_list + (
'erp5_configurator_standard', 'erp5_configurator_standard',
'erp5_upgrader_officejs_sdk', 'erp5_upgrader_officejs_sdk',
'erp5_administration', 'erp5_administration',
......
...@@ -183,7 +183,7 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase): ...@@ -183,7 +183,7 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase):
""" Make sure Installed business Templates are """ Make sure Installed business Templates are
what it is expected. """ what it is expected. """
expected_business_template_list = [ expected_business_template_list = self.portal.getCoreBusinessTemplateList() + [
'erp5_accounting', 'erp5_accounting',
'erp5_administration', 'erp5_administration',
'erp5_base', 'erp5_base',
...@@ -191,7 +191,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase): ...@@ -191,7 +191,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase):
'erp5_code_mirror', 'erp5_code_mirror',
'erp5_configurator', 'erp5_configurator',
'erp5_configurator_standard', 'erp5_configurator_standard',
'erp5_core',
'erp5_core_proxy_field_legacy', 'erp5_core_proxy_field_legacy',
'erp5_crm', 'erp5_crm',
'erp5_dms', 'erp5_dms',
...@@ -218,7 +217,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase): ...@@ -218,7 +217,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase):
'erp5_minipaint', 'erp5_minipaint',
'erp5_monaco_editor', 'erp5_monaco_editor',
'erp5_multimedia', 'erp5_multimedia',
'erp5_mysql_innodb_catalog',
'erp5_notebook', 'erp5_notebook',
'erp5_officejs', 'erp5_officejs',
'erp5_officejs_connector', 'erp5_officejs_connector',
...@@ -228,7 +226,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase): ...@@ -228,7 +226,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase):
'erp5_only_office', 'erp5_only_office',
'erp5_pdm', 'erp5_pdm',
'erp5_project', 'erp5_project',
'erp5_property_sheets',
'erp5_run_my_doc', 'erp5_run_my_doc',
'erp5_simulation', 'erp5_simulation',
'erp5_slideshow_style', 'erp5_slideshow_style',
...@@ -246,7 +243,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase): ...@@ -246,7 +243,6 @@ class TestOfficeJSSDKConfigurator(SecurityTestCase):
'erp5_web_renderjs_ui_test', 'erp5_web_renderjs_ui_test',
'erp5_web_renderjs_ui_test_core', 'erp5_web_renderjs_ui_test_core',
'erp5_web_service', 'erp5_web_service',
'erp5_xhtml_style',
'officejs_todomvc' 'officejs_todomvc'
] ]
self.assertSameSet(expected_business_template_list, self.assertSameSet(expected_business_template_list,
......
...@@ -276,6 +276,16 @@ class TestAlarm(ERP5TypeTestCase): ...@@ -276,6 +276,16 @@ class TestAlarm(ERP5TypeTestCase):
self.tic() self.tic()
self.checkDate(alarm, right_first_date, right_second_date, right_third_date,right_fourth_date) self.checkDate(alarm, right_first_date, right_second_date, right_third_date,right_fourth_date)
def test_week_and_month_impossible_combination(self):
alarm = self.newAlarm(enabled=True)
alarm.setPeriodicityStartDate(DateTime(2000, 1, 1))
# week 41 can not be in January
alarm.setPeriodicityWeekList((41, ))
alarm.setPeriodicityMonthList((1, ))
self.tic()
# next alarm date never advance
self.checkDate(alarm, DateTime(2000, 1, 1), DateTime(2000, 1, 1), DateTime(2000, 1, 1),)
def test_12_Every5Minutes(self): def test_12_Every5Minutes(self):
alarm = self.newAlarm(enabled=True) alarm = self.newAlarm(enabled=True)
now = DateTime() now = DateTime()
......
...@@ -441,13 +441,30 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor): ...@@ -441,13 +441,30 @@ class TestERP5Type(PropertySheetTestCase, LogInterceptor):
checkRelationUnset(self) checkRelationUnset(self)
# Test _setRegion doesn't reindex the object. # Test _setRegion doesn't reindex the object.
person_object._setRegion(category_id) def getTitleFromCatalog():
row, = self.portal.portal_catalog(
select_list=['title'],
uid=person_object.getUid(),
)
return row.title
modified_title = getTitleFromCatalog() + '_not_reindexed'
catalog_connection = self.getSQLConnection()()
catalog_connection.query(
'UPDATE catalog SET title=%s WHERE uid=%i' % (
catalog_connection.string_literal(modified_title),
person_object.getUid(),
),
)
self.commit() self.commit()
self.assertFalse(person_object.hasActivity()) # sanity check
self.assertEqual(getTitleFromCatalog(), modified_title)
person_object._setRegion(category_id)
self.tic()
self.assertEqual(getTitleFromCatalog(), modified_title)
person_object.setRegion(None) person_object.setRegion(None)
self.commit()
self.assertTrue(person_object.hasActivity())
self.tic() self.tic()
self.assertNotEqual(getTitleFromCatalog(), modified_title)
# category tool, base categories, properties # category tool, base categories, properties
# are likely to be handled specifically for accessor generation, # are likely to be handled specifically for accessor generation,
......
...@@ -32,6 +32,7 @@ import mock ...@@ -32,6 +32,7 @@ import mock
from AccessControl.SecurityManagement import newSecurityManager from AccessControl.SecurityManagement import newSecurityManager
from AccessControl import Unauthorized from AccessControl import Unauthorized
from AccessControl.ZopeGuards import guarded_getattr
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
...@@ -238,25 +239,36 @@ class TestPerson(ERP5TypeTestCase): ...@@ -238,25 +239,36 @@ class TestPerson(ERP5TypeTestCase):
self.assertTrue(person.getUserId()) self.assertTrue(person.getUserId())
self.assertFalse(self.portal.person_module._p_changed) self.assertFalse(self.portal.person_module._p_changed)
def testSetPasswordSecurity(self): def testSetPasswordSecurityOnPerson(self):
p = self._makeOne(id='person') self._testSetPasswordSecurity(
p.manage_permission(Permissions.SetOwnPassword, [], 0) self._makeOne())
self.assertRaises(Unauthorized, p.setPassword, 'secret')
self.assertRaises(Unauthorized, p.edit, password='secret') def testSetPasswordSecurityOnERP5Login(self):
self._testSetPasswordSecurity(
# setPassword(None) has no effect, because in the user interface we always self._makeOne().newContent(portal_type='ERP5 Login'))
# show an empty field for password. Note that it also does not require any
# specific permission. def _testSetPasswordSecurity(self, login):
p.setPassword(None) login.manage_permission(Permissions.SetOwnPassword, [], 0)
self.assertFalse(p.getPassword()) with self.assertRaises(Unauthorized):
guarded_getattr(login, 'setPassword')('secret')
with self.assertRaises(Unauthorized):
guarded_getattr(login, 'edit')(password='secret')
# edit(password=None) has no effect. It's a special case, because in the user interface
# we show an empty field for password.
login.edit(password=None)
self.assertFalse(login.getPassword())
# Make sure that edit method cannot call __setPasswordByForce and nothing # Make sure that edit method cannot call __setPasswordByForce and nothing
# changes. # changes.
p.edit(password_by_force='waaa') login.edit(password_by_force='waaa')
self.assertFalse(p.getPassword()) self.assertFalse(login.getPassword())
p.manage_permission(Permissions.SetOwnPassword, ['Anonymous'], 0) login.manage_permission(Permissions.SetOwnPassword, ['Anonymous'], 0)
p.setPassword('secret') login.setPassword('secret')
self.assertTrue(p.getPassword()) password = login.getPassword()
self.assertTrue(password)
login.edit(password=None)
self.assertEqual(login.getPassword(), password)
def testSetUserIdSecurity(self): def testSetUserIdSecurity(self):
# Changing an already set user id needs "manage users" permissions, # Changing an already set user id needs "manage users" permissions,
......
...@@ -220,5 +220,10 @@ class TestDedup(ERP5TypeTestCase): ...@@ -220,5 +220,10 @@ class TestDedup(ERP5TypeTestCase):
whl._p_deactivate() whl._p_deactivate()
finally: finally:
Workflow.dedupStrings = orig_dedupStrings Workflow.dedupStrings = orig_dedupStrings
self.assertEqual(deduped, [35]) # A single deduplication should have happened, as the loop exits on bucket
self.assertEqual(len(list(whl)), 36) # split.
new_obj_length, = deduped # pylint: disable=unbalanced-tuple-unpacking
# The exact boundary does not matter much, but it should be greater than
# some arbitrary value considered satisfying.
self.assertGreaterEqual(new_obj_length, 24)
self.assertEqual(len(list(whl)), new_obj_length + 1)
...@@ -156,19 +156,19 @@ if book_include_reference_table: ...@@ -156,19 +156,19 @@ if book_include_reference_table:
image_link_list = book.WebPage_createImageOverview(book_content) image_link_list = book.WebPage_createImageOverview(book_content)
for referenced_document in book_link_list.get("reference_list", []): for referenced_document in book_link_list.get("reference_list", []):
book_reference_list.append(referenced_document.get("item")) book_reference_list.append(referenced_document.get("item"))
book_content = book_content.replace(referenced_document.get("input"), referenced_document.get("output"),1) book_content = book_content.replace(referenced_document.get("input"), referenced_document.get("output"))
for applicable_document in book_link_list.get("applicable_list", []): for applicable_document in book_link_list.get("applicable_list", []):
book_applicable_document_list.append(applicable_document.get("item")) book_applicable_document_list.append(applicable_document.get("item"))
book_content = book_content.replace(applicable_document.get("input"), applicable_document.get("output"),1) book_content = book_content.replace(applicable_document.get("input"), applicable_document.get("output"))
for abbreviation in book_link_list.get("abbreviation_list", []): for abbreviation in book_link_list.get("abbreviation_list", []):
book_abbreviation_list.append(abbreviation.get("item")) book_abbreviation_list.append(abbreviation.get("item"))
book_content = book_content.replace(abbreviation.get("input"), abbreviation.get("output"),1) book_content = book_content.replace(abbreviation.get("input"), abbreviation.get("output"))
for figure in image_link_list.get("figure_list", []): for figure in image_link_list.get("figure_list", []):
book_image_list.append(figure.get("item")) book_image_list.append(figure.get("item"))
book_content = book_content.replace(figure.get("input"), figure.get("output"), 1) book_content = book_content.replace(figure.get("input"), figure.get("output"), 1)
for table in table_link_list.get("table_list", []): for table in table_link_list.get("table_list", []):
book_table_list.append(table.get("item")) book_table_list.append(table.get("item"))
book_content = book_content.replace(table.get("input"), table.get("output"), 1) book_content = book_content.replace(table.get("input"), table.get("output"))
# in order for the reference tables to be in the table of content, they must # in order for the reference tables to be in the table of content, they must
# be added beforehand to content # be added beforehand to content
......
...@@ -2,117 +2,128 @@ ...@@ -2,117 +2,128 @@
<ZopeData> <ZopeData>
<record id="1" aka="AAAAAAAAAAE="> <record id="1" aka="AAAAAAAAAAE=">
<pickle> <pickle>
<global name="Worklist" module="erp5.portal_type"/> <global name="Image" module="erp5.portal_type"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item> <item>
<key> <string>_identity_criterion</string> </key> <key> <string>_Access_contents_information_Permission</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>_range_criterion</string> </key> <key> <string>_Add_portal_content_Permission</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>action</string> </key> <key> <string>_Change_local_roles_Permission</string> </key>
<value> <string encoding="cdata"><![CDATA[ <value>
<tuple>
ERP5Site_viewDocumentList?send_state=%(send_state)s&local_roles=%(local_roles)s&portal_type=%(portal_type)s&reset=1 <string>Assignor</string>
<string>Manager</string>
]]></string> </value> </tuple>
</item> </value>
<item>
<key> <string>action_name</string> </key>
<value> <string>Documents Failed To Send (%(count)s)</string> </value>
</item> </item>
<item> <item>
<key> <string>categories</string> </key> <key> <string>_Modify_portal_content_Permission</string> </key>
<value> <value>
<tuple> <tuple>
<string>action_type/global</string> <string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple> </tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>criterion_property</string> </key> <key> <string>_View_Permission</string> </key>
<value> <value>
<tuple> <tuple>
<string>send_state</string> <string>Assignee</string>
<string>local_roles</string> <string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple> </tuple>
</value> </value>
</item> </item>
<item> <item>
<key> <string>guard_expression</string> </key> <key> <string>_count</string> </key>
<value> <value>
<none/> <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>_mt_index</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
<item>
<key> <string>_tree</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value> <string>6f858aff4a47a4f505f1391940cf1eaf</string> </value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>image/png</string> </value>
</item>
<item>
<key> <string>height</string> </key>
<value> <int>842</int> </value>
</item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>worklist_failed_to_send</string> </value> <value> <string>template_test_book_citation_bmp</string> </value>
</item> </item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>portal_type</string> </key>
<value> <string>Worklist</string> </value> <value> <string>Image</string> </value>
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>width</string> </key>
<value> <string>failed_to_send</string> </value> <value> <int>595</int> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <record id="2" aka="AAAAAAAAAAI=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="Length" module="BTrees.Length"/>
</pickle> </pickle>
<pickle> <int>0</int> </pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle> <pickle>
<dictionary> <global name="OOBTree" module="BTrees.OOBTree"/>
<item> </pickle>
<key> <string>data</string> </key> <pickle>
<value> <none/>
<dictionary>
<item>
<key> <string>local_roles</string> </key>
<value>
<list>
<string>Assignor</string>
</list>
</value>
</item>
<item>
<key> <string>send_state</string> </key>
<value>
<list>
<string>failed</string>
</list>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="4" aka="AAAAAAAAAAQ=">
<pickle> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="OOBTree" module="BTrees.OOBTree"/>
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <none/>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle> </pickle>
</record> </record>
</ZopeData> </ZopeData>
<p>${WebPage_insertTableOfReferences}</p>
<h1>Test Citation</h1>
<p> TEST RD </p>
<p>Hello [<a href="http://www.nexedi.com" title="Nexedi">RD</a>]</p>
<p>Hello [<a href="http://www.nexedi.com" title="Nexedi">RD</a>]</p>
<p>Hello [<a href="http://www.nexedi.cn" title="Nexedi">RD</a>]</p>
<table align="center" border="1" cellpadding="1" cellspacing="1">
<caption>Companies, technologies and users</caption>
<thead>
<tr>
<th scope="col">Company</th>
<th scope="col">Country</th>
<th scope="col">Technology</th>
<th scope="col">Sample users</th>
</tr>
</thead>
</table>
<table align="center" border="1" cellpadding="1" cellspacing="1">
<caption>Companies, technologies and users</caption>
<thead>
<tr>
<th scope="col">Company</th>
<th scope="col">Country</th>
<th scope="col">Technology</th>
<th scope="col">Sample users</th>
</tr>
</thead>
</table>
<table align="center" border="1" cellpadding="1" cellspacing="1">
<caption>Company</caption>
<thead>
<tr>
<th scope="col">Company</th>
<th scope="col">Country</th>
</tr>
</thead>
</table>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Web Page" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_Access_contents_information_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Add_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Change_local_roles_Permission</string> </key>
<value>
<tuple>
<string>Assignor</string>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>_Modify_portal_content_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>_View_Permission</string> </key>
<value>
<tuple>
<string>Assignee</string>
<string>Assignor</string>
<string>Manager</string>
<string>Owner</string>
</tuple>
</value>
</item>
<item>
<key> <string>content_md5</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>template_test_book_citation_html</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Web Page</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -1644,6 +1644,24 @@ class TestCorporateIdentityTemplateList(ERP5TypeTestCase): ...@@ -1644,6 +1644,24 @@ class TestCorporateIdentityTemplateList(ERP5TypeTestCase):
) )
) )
@changeSkin('Book')
def test_pdfBookCitation(self):
"""
"""
self.runPdfTestPattern(
"template_test_book_citation_html",
"template_test_book_citation_bmp",
"template_test_image_source_pdf",
**dict(
page_number=3,
use_skin="Book",
test_method="WebPage_exportAsBook",
format="pdf",
override_revision=1,
include_reference_table = 1
)
)
@changeSkin('Book') @changeSkin('Book')
def test_pdfBookPrint(self): def test_pdfBookPrint(self):
""" """
......
...@@ -32,7 +32,7 @@ from erp5.component.document.Ticket import Ticket ...@@ -32,7 +32,7 @@ from erp5.component.document.Ticket import Ticket
from erp5.component.mixin.EncryptedPasswordMixin import EncryptedPasswordMixin from erp5.component.mixin.EncryptedPasswordMixin import EncryptedPasswordMixin
class CredentialRequest(Ticket, EncryptedPasswordMixin): class CredentialRequest(EncryptedPasswordMixin, Ticket):
""" """
""" """
...@@ -54,11 +54,6 @@ class CredentialRequest(Ticket, EncryptedPasswordMixin): ...@@ -54,11 +54,6 @@ class CredentialRequest(Ticket, EncryptedPasswordMixin):
, PropertySheet.Url , PropertySheet.Url
) )
def checkUserCanChangePassword(self):
# every body can change a password of a credential request as annonymous
# should be able to do it
pass
def checkPasswordValueAcceptable(self, value): def checkPasswordValueAcceptable(self, value):
# all passwords are acceptable on Credential Request # all passwords are acceptable on Credential Request
pass pass
......
translate = context.Base_translateString
item_list = [("", "")] + [
(translate(x), y) for x,y in [
("Draft", "draft"), ("Shared", "shared"), ("Released", "released"),
]
]
if context.getTypeBasedMethod('getPreferredAttachedDocumentPublicationState')() == "published":
item_list.append((translate("Published"), "published"))
return item_list
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </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>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Base_getAttachedDocumentPublicationStateItemList</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -142,7 +142,7 @@ ...@@ -142,7 +142,7 @@
<dictionary> <dictionary>
<item> <item>
<key> <string>_text</string> </key> <key> <string>_text</string> </key>
<value> <string>python: [("", ""),] + [(here.Base_translateString(x), y) for x,y in [("Draft", "draft"), ("Shared", "shared"), ("Released", "released"),]]</string> </value> <value> <string>here/Base_getAttachedDocumentPublicationStateItemList</string> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
</item> </item>
<item> <item>
<key> <string>enabled</string> </key> <key> <string>enabled</string> </key>
<value> <int>1</int> </value> <value> <int>0</int> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
...@@ -151,7 +151,7 @@ ...@@ -151,7 +151,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>998.1956.58639.53486</string> </value> <value> <string>998.1960.1198.56217</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -169,7 +169,7 @@ ...@@ -169,7 +169,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1644230881.1</float> <float>1644930593.2</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -21,7 +21,7 @@ kw['conversion_dict'] = dict( ...@@ -21,7 +21,7 @@ kw['conversion_dict'] = dict(
header_spacing=5 header_spacing=5
) )
kw['css_path']="payslip_css/payslip" kw['css_path']="payslip_css/payslip"
kw['document_language']=target_language kw['document_language']=target_language or 'fr'
kw['start_date']=context.getStartDate() or None kw['start_date']=context.getStartDate() or None
kw['stop_date']=context.getStopDate() or None kw['stop_date']=context.getStopDate() or None
kw['get_doc_after_save'] = send_to_maileva kw['get_doc_after_save'] = send_to_maileva
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Zuite" module="Products.Zelenium.zuite"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_objects</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>renderjs_ui_report_language_zuite</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testGeneralPrint</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test General Print</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test General Print</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/sale_order_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//ul[@class="document-listview"]//a[text()='Print']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//ul[@class="document-listview"]//a[text()='Print']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@id="field_your_format"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_format"]</td>
<td>html</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_target_language"]</td>
<td>fr</td>
</tr>
<!-- overwrite createObjectURL to read server response and append result to Dom -->
<tr>
<td>getEval</td>
<td>
window.URL.createObjectURL = function (blob) {
window.jIO.util.readBlobAsText(blob)
.then(function (answer) {
text_node = document.createElement('div');
text_node.innerHTML = answer.target.result;
text_node.setAttribute("id", "text_node_for_blob");
document.getElementById("selenium_myiframe").contentWindow.document.body.appendChild(text_node);
})
.then(undefined, function(error) {console.log(error);});
return '';
};
</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@value="Print"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text()='Data received.']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@id='text_node_for_blob']</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//font[contains(text(), "Fournisseur")]</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//font[contains(text(), "Mode de livraison")]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testProductionOrderPrintProductionOrder</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Production Order Report</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Produdction Order Report</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/production_order_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//ul[@class="document-listview"]//a[text()='Print Production Order']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//ul[@class="document-listview"]//a[text()='Print Production Order']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@id="field_your_format"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_format"]</td>
<td>html</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_target_language"]</td>
<td>fr</td>
</tr>
<!-- overwrite createObjectURL to read server response and append result to Dom -->
<tr>
<td>getEval</td>
<td>
window.URL.createObjectURL = function (blob) {
window.jIO.util.readBlobAsText(blob)
.then(function (answer) {
text_node = document.createElement('div');
text_node.innerHTML = answer.target.result;
text_node.setAttribute("id", "text_node_for_blob");
document.getElementById("selenium_myiframe").contentWindow.document.body.appendChild(text_node);
})
.then(undefined, function(error) {console.log(error);});
return '';
};
</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@value="Print Production Order"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text()='Data received.']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@id='text_node_for_blob']</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Fournisseur")]</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Date du document")]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testProductionPackingListPrintProductionPackingList</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Production Packing List Report</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Produdction Packing List Report</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/production_packing_list_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//ul[@class="document-listview"]//a[text()='Print Production Packing List']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//ul[@class="document-listview"]//a[text()='Print Production Packing List']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@id="field_your_format"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_format"]</td>
<td>html</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_target_language"]</td>
<td>fr</td>
</tr>
<!-- overwrite createObjectURL to read server response and append result to Dom -->
<tr>
<td>getEval</td>
<td>
window.URL.createObjectURL = function (blob) {
window.jIO.util.readBlobAsText(blob)
.then(function (answer) {
text_node = document.createElement('div');
text_node.innerHTML = answer.target.result;
text_node.setAttribute("id", "text_node_for_blob");
document.getElementById("selenium_myiframe").contentWindow.document.body.appendChild(text_node);
})
.then(undefined, function(error) {console.log(error);});
return '';
};
</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@value="Print Packing List"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text()='Data received.']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@id='text_node_for_blob']</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Fournisseur")]</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Date du document")]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testProjectRelatedTaskReport</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Project Report</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Project Report</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/project_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//ul[@class="document-listview"]//a[text()='Related Tasks Report']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//ul[@class="document-listview"]//a[text()='Related Tasks Report']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@id="field_your_format"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_format"]</td>
<td>html</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_target_language"]</td>
<td>fr</td>
</tr>
<!-- overwrite createObjectURL to read server response and append result to Dom -->
<tr>
<td>getEval</td>
<td>
window.URL.createObjectURL = function (blob) {
window.jIO.util.readBlobAsText(blob)
.then(function (answer) {
text_node = document.createElement('div');
text_node.innerHTML = answer.target.result;
text_node.setAttribute("id", "text_node_for_blob");
document.getElementById("selenium_myiframe").contentWindow.document.body.appendChild(text_node);
})
.then(undefined, function(error) {console.log(error);});
return '';
};
</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@value="Related Tasks Report"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text()='Data received.']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@id='text_node_for_blob']</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//font[contains(text(), "Date de début")]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testSaleOrderOrderSummaryReport</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Sale Order Report</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Sale Order Report</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/sale_order_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//ul[@class="document-listview"]//a[text()='Order Summary']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//ul[@class="document-listview"]//a[text()='Order Summary']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@id="field_your_format"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_format"]</td>
<td>html</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_target_language"]</td>
<td>fr</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_quantity_unit_list"]</td>
<td>day</td>
</tr>
<!-- overwrite createObjectURL to read server response and append result to Dom -->
<tr>
<td>getEval</td>
<td>
window.URL.createObjectURL = function (blob) {
window.jIO.util.readBlobAsText(blob)
.then(function (answer) {
text_node = document.createElement('div');
text_node.innerHTML = answer.target.result;
text_node.setAttribute("id", "text_node_for_blob");
document.getElementById("selenium_myiframe").contentWindow.document.body.appendChild(text_node);
})
.then(undefined, function(error) {console.log(error);});
return '';
};
</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@value="Order Summary"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text()='Data received.']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@id='text_node_for_blob']</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//font[contains(text(), "Date de livraison")]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testSaleOrderPrintOrder</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Sale Order Report</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Sale Order Report</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/sale_order_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//ul[@class="document-listview"]//a[text()='Print Order']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//ul[@class="document-listview"]//a[text()='Print Order']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@id="field_your_format"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_format"]</td>
<td>html</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_target_language"]</td>
<td>fr</td>
</tr>
<!-- overwrite createObjectURL to read server response and append result to Dom -->
<tr>
<td>getEval</td>
<td>
window.URL.createObjectURL = function (blob) {
window.jIO.util.readBlobAsText(blob)
.then(function (answer) {
text_node = document.createElement('div');
text_node.innerHTML = answer.target.result;
text_node.setAttribute("id", "text_node_for_blob");
document.getElementById("selenium_myiframe").contentWindow.document.body.appendChild(text_node);
})
.then(undefined, function(error) {console.log(error);});
return '';
};
</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@value="Print Order"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text()='Data received.']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@id='text_node_for_blob']</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Fournisseur")]</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Date du document")]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ZopePageTemplate" module="Products.PageTemplates.ZopePageTemplate"/>
</pickle>
<pickle>
<dictionary>
<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_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>content_type</string> </key>
<value> <string>text/html</string> </value>
</item>
<item>
<key> <string>expand</string> </key>
<value> <int>0</int> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>testSalePackingListPrintPackingList</string> </value>
</item>
<item>
<key> <string>output_encoding</string> </key>
<value> <string>utf-8</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <unicode></unicode> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<html xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Test Sale Packing List Report</title>
</head>
<body>
<table cellpadding="1" cellspacing="1" border="1">
<thead>
<tr><td rowspan="1" colspan="3">Test Sale Packing List Report</td></tr>
</thead><tbody>
<tal:block metal:use-macro="here/Zuite_CommonTemplate/macros/init" />
<!-- Initialize -->
<tr>
<td>open</td>
<td>${base_url}/web_site_module/renderjs_runner/#/sale_packing_list_module</td>
<td></td>
</tr>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_app_loaded" />
<tal:block tal:define="click_configuration python: {'text': 'Add'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/click_on_header_link" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/submit_dialog" />
<tal:block tal:define="notification_configuration python: {'class': 'success',
'text': 'Object created.'}">
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_notification" />
</tal:block>
<tal:block metal:use-macro="here/Zuite_CommonTemplateForRenderjsUi/macros/wait_for_content_loaded" />
<tr>
<td>waitForElementPresent</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//div[contains(@data-gadget-url, 'gadget_erp5_panel.html')]//div[contains(@data-gadget-url, 'gadget_erp5_field_multicheckbox.html')]//label</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//a[@data-i18n="Export"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//ul[@class="document-listview"]//a[text()='Print Packing List']</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//ul[@class="document-listview"]//a[text()='Print Packing List']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//select[@id="field_your_format"]</td>
<td></td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_format"]</td>
<td>html</td>
</tr>
<tr>
<td>type</td>
<td>//select[@id="field_your_target_language"]</td>
<td>fr</td>
</tr>
<!-- overwrite createObjectURL to read server response and append result to Dom -->
<tr>
<td>getEval</td>
<td>
window.URL.createObjectURL = function (blob) {
window.jIO.util.readBlobAsText(blob)
.then(function (answer) {
text_node = document.createElement('div');
text_node.innerHTML = answer.target.result;
text_node.setAttribute("id", "text_node_for_blob");
document.getElementById("selenium_myiframe").contentWindow.document.body.appendChild(text_node);
})
.then(undefined, function(error) {console.log(error);});
return '';
};
</td>
<td></td>
</tr>
<tr>
<td>click</td>
<td>//input[@value="Print Packing List"]</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//button[text()='Data received.']</td>
<td></td>
</tr>
<tr>
<td>waitForElementPresent</td>
<td>//div[@id='text_node_for_blob']</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Fournisseur")]</td>
<td></td>
</tr>
<tr>
<td>verifyElementPresent</td>
<td>//div[@id='text_node_for_blob']//p[contains(text(), "Date du document")]</td>
<td></td>
</tr>
</tbody></table>
</body>
</html>
\ No newline at end of file
##############################################################################
#
# Copyright (c) 2011 Nexedi SARL and Contributors. All Rights Reserved.
# Kazuhiko <kazuhiko@nexedi.com>
# Rafael Monnerat <rafael@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.
#
##############################################################################
import unittest
from Products.ERP5Type.tests.ERP5TypeFunctionalTestCase import ERP5TypeFunctionalTestCase
class TestFunctionalRJSReportLanguage(ERP5TypeFunctionalTestCase):
foreground = 0
run_only = "renderjs_ui_report_language_zuite"
def afterSetUp(self):
ERP5TypeFunctionalTestCase.afterSetUp(self)
portal = self.getPortalObject()
portal.portal_preferences.default_site_preference.edit(preferred_report_style="ODS")
if portal.portal_preferences.default_site_preference.getPreferenceState() !='global':
portal.portal_preferences.default_site_preference.enable()
if not getattr(portal.portal_categories.quantity_unit, 'day', None):
portal.portal_categories.quantity_unit.newContent(
portal_type='Category',
id = 'day',
title='Day'
)
self.tic()
def getBusinessTemplateList(self):
return (
'erp5_web_renderjs_ui',
'erp5_web_renderjs_ui_test',
'erp5_ui_test_core',
'erp5_trade',
)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestFunctionalRJSReportLanguage))
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>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>testFunctionalRJSReportLanguage</string> </value>
</item>
<item>
<key> <string>default_source_reference</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>test.erp5.testFunctionalRJSReportLanguage</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">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>error_message</string> </key>
<value>
<list>
<persistent> <string encoding="base64">AAAAAAAAAAU=</string> </persistent>
</list>
</value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="5" aka="AAAAAAAAAAU=">
<pickle>
<global name="Message" module="Products.ERP5Type.Message"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>default</string> </key>
<value> <string>ID is invalid, should be \'${id_prefix}.VERSION.REFERENCE\'</string> </value>
</item>
<item>
<key> <string>domain</string> </key>
<value> <string>erp5_ui</string> </value>
</item>
<item>
<key> <string>mapping</string> </key>
<value>
<dictionary>
<item>
<key> <string>id_prefix</string> </key>
<value> <string>test</string> </value>
</item>
</dictionary>
</value>
</item>
<item>
<key> <string>message</string> </key>
<value> <string>ID is invalid, should be \'${id_prefix}.VERSION.REFERENCE\'</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
erp5_web_renderjs_ui_test
erp5_trade
erp5_ods_style
erp5_mrp
erp5_l10n_fr
\ No newline at end of file
portal_tests/renderjs_ui_report_language_zuite
portal_tests/renderjs_ui_report_language_zuite/**
\ No newline at end of file
test.erp5.testFunctionalRJSReportLanguage
\ No newline at end of file
erp5_full_text_mroonga_catalog
\ No newline at end of file
erp5_report_renderjs_ui_test
\ No newline at end of file
""" """
This script should returns always two list of Business Template. This script may be overridden.
- The first list is to resolve dependencies and upgrade. It is expected to return two lists of Business Templates:
- The second list is what you want to keep. This is useful if we want to keep - The first is a tuple containing names of Business Templates to install and
a old business template without updating it and without removing it keep up-to-date. Their dependencies are also installed and kept up-to-date.
- The second is a list containing names of Business Templates which should be
kept if already installed, ignored if missing, and not be upgraded nor
removed.
""" """
return (
return ('erp5_base',), ["erp5_upgrader"] tuple(context.getPortalObject().getCoreBusinessTemplateList() + ['erp5_base']),
['erp5_upgrader'],
)
return ('erp5_web',), ["erp5_upgrader", "erp5_upgrader_test"] return (
tuple(context.getPortalObject().getCoreBusinessTemplateList() + ['erp5_web']),
["erp5_upgrader", "erp5_upgrader_test"],
)
...@@ -79,7 +79,7 @@ class WebSite(WebSection): ...@@ -79,7 +79,7 @@ class WebSite(WebSection):
if name in language_list: if name in language_list:
default_language = self.getDefaultAvailableLanguage() default_language = self.getDefaultAvailableLanguage()
if request.get('AcceptLanguage') is not None: if request.get('AcceptLanguage') is not None:
request['AcceptLanguage'].set(name, 100) request['AcceptLanguage'].set(name, 10)
request.set(WEBSITE_LANGUAGE_KEY, name) request.set(WEBSITE_LANGUAGE_KEY, name)
if self.isTempObject() or name == default_language: if self.isTempObject() or name == default_language:
redirect_path_list = [self.getOriginalDocument().absolute_url()] redirect_path_list = [self.getOriginalDocument().absolute_url()]
......
...@@ -28,6 +28,7 @@ def generateDocumentListHTML(result_list, document_list): ...@@ -28,6 +28,7 @@ def generateDocumentListHTML(result_list, document_list):
if (document_list): if (document_list):
result_list.append('<aside id="document_list"><ul class="h-feed">') result_list.append('<aside id="document_list"><ul class="h-feed">')
for section in document_list: for section in document_list:
publication_date = section['effective_date'] or section['modification_date']
result_list.append(""" result_list.append("""
<li class="h-entry"> <li class="h-entry">
<div class="e-content"> <div class="e-content">
...@@ -41,8 +42,8 @@ def generateDocumentListHTML(result_list, document_list): ...@@ -41,8 +42,8 @@ def generateDocumentListHTML(result_list, document_list):
('<p class="p-summary">%s</p>' % _(section['description'])) if section.get('description') else '', ('<p class="p-summary">%s</p>' % _(section['description'])) if section.get('description') else '',
('<p class="p-author h-card">%s</p>' % _(section['document'].Document_getContributorTitleList()[0])), ('<p class="p-author h-card">%s</p>' % _(section['document'].Document_getContributorTitleList()[0])),
__(section['url']), __(section['url']),
__(section['modification_date'].HTML4()), __(publication_date.HTML4()),
_(section['modification_date'].rfc822()) _(publication_date.rfc822())
)) ))
result_list.append('</ul></aside>') result_list.append('</ul></aside>')
...@@ -75,6 +76,6 @@ result_list.append('</nav>') ...@@ -75,6 +76,6 @@ result_list.append('</nav>')
# Documents # Documents
if include_document: if include_document:
generateDocumentListHTML(result_list, web_section.WebSection_getSiteMapTree(include_subsection=False, exclude_default_document=True, depth=1, property_mapping=('translated_title', 'description', 'modification_date'))) generateDocumentListHTML(result_list, web_section.WebSection_getSiteMapTree(include_subsection=False, exclude_default_document=True, depth=1, property_mapping=('translated_title', 'description', 'effective_date', 'modification_date')))
return ''.join(result_list) return ''.join(result_list)
...@@ -90,7 +90,7 @@ ...@@ -90,7 +90,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//ul[@class="h-feed"]//li[@class="h-entry"]//a[@class="u-url" and @rel='permalink' and contains(@href, 'web_site_module/erp5_web_js_style_test_site/erp5_web_js_style_test_contentpage')]//time[@class="dt-published" and contains(@datetime, 'T')]</td> <td>//aside[@id='document_list']//ul[@class="h-feed"]//li[@class="h-entry"]//a[@class="u-url" and @rel='permalink' and contains(@href, 'web_site_module/erp5_web_js_style_test_site/erp5_web_js_style_test_contentpage')]//time[@class="dt-published" and text()='Tue, 13 Dec 2011 11:22:33 +0500' and @datetime='2011-12-13T06:22:33Z']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -341,7 +341,7 @@ ...@@ -341,7 +341,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -315,7 +315,7 @@ ...@@ -315,7 +315,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -143,7 +143,7 @@ ...@@ -143,7 +143,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -213,7 +213,7 @@ ...@@ -213,7 +213,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -283,7 +283,7 @@ ...@@ -283,7 +283,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -143,7 +143,7 @@ ...@@ -143,7 +143,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -213,7 +213,7 @@ ...@@ -213,7 +213,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -283,7 +283,7 @@ ...@@ -283,7 +283,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -138,7 +138,7 @@ ...@@ -138,7 +138,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -203,7 +203,7 @@ ...@@ -203,7 +203,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -268,7 +268,7 @@ ...@@ -268,7 +268,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -139,7 +139,7 @@ ...@@ -139,7 +139,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -209,7 +209,7 @@ ...@@ -209,7 +209,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -270,7 +270,7 @@ ...@@ -270,7 +270,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -178,7 +178,7 @@ ...@@ -178,7 +178,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
...@@ -348,7 +348,7 @@ ...@@ -348,7 +348,7 @@
</tr> </tr>
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//aside[@id='document_list']//p[contains(text(), 'Date: ') and contains(text(), 'GMT')]</td> <td>//aside[@id='document_list']//p[text()='Date: Tue, 13 Dec 2011 06:22:33 GMT']</td>
<td></td> <td></td>
</tr> </tr>
......
...@@ -34,6 +34,8 @@ web_page_content_en_id = "erp5_web_js_style_test_contentpage_en" ...@@ -34,6 +34,8 @@ web_page_content_en_id = "erp5_web_js_style_test_contentpage_en"
web_page_content_fr_id = "erp5_web_js_style_test_contentpage_fr" web_page_content_fr_id = "erp5_web_js_style_test_contentpage_fr"
web_page_content_zh_id = "erp5_web_js_style_test_contentpage_zh" web_page_content_zh_id = "erp5_web_js_style_test_contentpage_zh"
publicate_date = DateTime('2011/12/13 11:22:33 GMT+5')
### English web page ### English web page
module = portal.getDefaultModule(web_page_portal_type) module = portal.getDefaultModule(web_page_portal_type)
if getattr(module, web_page_frontend_en_id, None) is not None: if getattr(module, web_page_frontend_en_id, None) is not None:
...@@ -43,6 +45,7 @@ web_page = module.newContent( ...@@ -43,6 +45,7 @@ web_page = module.newContent(
id=web_page_frontend_en_id, id=web_page_frontend_en_id,
reference=web_page_frontend_reference, reference=web_page_frontend_reference,
contributor_value=contributor, contributor_value=contributor,
effective_date=publicate_date,
language="en", language="en",
version="001", version="001",
text_content=""" text_content="""
...@@ -61,6 +64,7 @@ web_page = module.newContent( ...@@ -61,6 +64,7 @@ web_page = module.newContent(
id=web_page_content_en_id, id=web_page_content_en_id,
reference=web_page_content_reference, reference=web_page_content_reference,
contributor_value=contributor, contributor_value=contributor,
effective_date=publicate_date,
title="%s title" % web_page_content_reference, title="%s title" % web_page_content_reference,
description="%s description" % web_page_content_reference, description="%s description" % web_page_content_reference,
language="en", language="en",
...@@ -79,6 +83,7 @@ web_page = module.newContent( ...@@ -79,6 +83,7 @@ web_page = module.newContent(
id=web_page_frontend_fr_id, id=web_page_frontend_fr_id,
reference=web_page_frontend_reference, reference=web_page_frontend_reference,
contributor_value=contributor, contributor_value=contributor,
effective_date=publicate_date,
language="fr", language="fr",
version="001", version="001",
text_content=""" text_content="""
...@@ -97,6 +102,7 @@ web_page = module.newContent( ...@@ -97,6 +102,7 @@ web_page = module.newContent(
id=web_page_content_fr_id, id=web_page_content_fr_id,
reference=web_page_content_reference, reference=web_page_content_reference,
contributor_value=contributor, contributor_value=contributor,
effective_date=publicate_date,
title="%s title" % web_page_content_reference, title="%s title" % web_page_content_reference,
description="%s description" % web_page_content_reference, description="%s description" % web_page_content_reference,
language="fr", language="fr",
...@@ -115,6 +121,7 @@ web_page = module.newContent( ...@@ -115,6 +121,7 @@ web_page = module.newContent(
id=web_page_frontend_zh_id, id=web_page_frontend_zh_id,
reference=web_page_frontend_reference, reference=web_page_frontend_reference,
contributor_value=contributor, contributor_value=contributor,
effective_date=publicate_date,
language="zh", language="zh",
version="001", version="001",
text_content=""" text_content="""
...@@ -133,6 +140,7 @@ web_page = module.newContent( ...@@ -133,6 +140,7 @@ web_page = module.newContent(
id=web_page_content_zh_id, id=web_page_content_zh_id,
reference=web_page_content_reference, reference=web_page_content_reference,
contributor_value=contributor, contributor_value=contributor,
effective_date=publicate_date,
title="%s title" % web_page_content_reference, title="%s title" % web_page_content_reference,
description="%s description" % web_page_content_reference, description="%s description" % web_page_content_reference,
language="zh", language="zh",
......
...@@ -92,6 +92,15 @@ div[data-gadget-url$="gadget_erp5_page_project_front_page.html"] .front-project- ...@@ -92,6 +92,15 @@ div[data-gadget-url$="gadget_erp5_page_project_front_page.html"] .front-project-
margin-bottom: 8px; margin-bottom: 8px;
} }
div[data-gadget-url$="gadget_erp5_page_project_front_page.html"] .front-project-list .project-box .project-title a {
color: #267B87;
font-weight: normal;
font-size: 14px;
line-height: 33px;
margin-bottom: 8px;
margin-left: 14px;
}
div[data-gadget-url$="gadget_erp5_page_project_front_page.html"] .front-project-list .project-box span.margined { div[data-gadget-url$="gadget_erp5_page_project_front_page.html"] .front-project-list .project-box span.margined {
margin-right: 5px; margin-right: 5px;
} }
......
...@@ -242,7 +242,7 @@ ...@@ -242,7 +242,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>982.36779.34422.1348</string> </value> <value> <string>998.5120.55627.52002</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -260,7 +260,7 @@ ...@@ -260,7 +260,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1584457148.55</float> <float>1644420658.08</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -301,11 +301,15 @@ ...@@ -301,11 +301,15 @@
function createProjectHtmlElement(project_id, project_title, function createProjectHtmlElement(project_id, project_title,
project_url, supervisor, supervisor_url) { project_url, supervisor, supervisor_url) {
var project_link = domsugar('a', { //title_div will have 2 elements: span (with title text) and a link (with text "Project Page")
href: project_url //update styles: " div[data-gadget-url$="gadget_erp5_page_project_front_page.html"] a" to be a smaller text
}, [project_title]), var project_title_span = domsugar('span', {}, [project_title]),
project_link = domsugar('a', {
href: project_url,
id: project_title + "-project_page_link"
}, ["(Project Page)"]),
title_div = domsugar('div', { class: "project-title" }, title_div = domsugar('div', { class: "project-title" },
[project_link]), [project_title_span, project_link]),
left_info_div = domsugar('div', { class: "project-left" }), left_info_div = domsugar('div', { class: "project-left" }),
supervisor_field_label = domsugar('label', {}, [SUPERVISOR_FIELD_TITLE]), supervisor_field_label = domsugar('label', {}, [SUPERVISOR_FIELD_TITLE]),
supervisor_value_link = domsugar('a', { supervisor_value_link = domsugar('a', {
...@@ -562,6 +566,7 @@ ...@@ -562,6 +566,7 @@
}) })
.declareJob("detachRenderProjectForumLink", function () { .declareJob("detachRenderProjectForumLink", function () {
return;
var gadget = this, var gadget = this,
i, i,
forum_link_html, forum_link_html,
......
...@@ -234,7 +234,7 @@ ...@@ -234,7 +234,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>982.41488.58477.39116</string> </value> <value> <string>998.5123.35694.4864</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -252,7 +252,7 @@ ...@@ -252,7 +252,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1584697605.84</float> <float>1644428660.52</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
...@@ -92,12 +92,17 @@ ...@@ -92,12 +92,17 @@
<!-- Check project present --> <!-- Check project present -->
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='test-project']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//span[text()='test-project']</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='(Project Page)']</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>click</td> <td>click</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='test-project']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='(Project Page)']</td>
<td></td> <td></td>
</tr> </tr>
<!-- check project quick view page elements --> <!-- check project quick view page elements -->
......
...@@ -66,13 +66,13 @@ ...@@ -66,13 +66,13 @@
<!-- Check draft project --> <!-- Check draft project -->
<tr> <tr>
<td>assertElementNotPresent</td> <td>assertElementNotPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='draft-project']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//span[text()='draft-project']</td>
<td></td> <td></td>
</tr> </tr>
<!-- Check empty project --> <!-- Check empty project -->
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='empty-project']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//span[text()='empty-project']</td>
<td></td> <td></td>
</tr> </tr>
<!-- Check empty Task line --> <!-- Check empty Task line -->
...@@ -158,12 +158,12 @@ ...@@ -158,12 +158,12 @@
<!-- Check documented project --> <!-- Check documented project -->
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='documented-project']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//span[text()='documented-project']</td>
<td></td> <td></td>
</tr> </tr>
<!-- Check Task line --> <!-- Check Task line -->
<tr> <tr>
<td>assertElementPresent</td> <td>waitForElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-line']//span[@class='status none margined green' and contains(@id, 'documented-project') and contains(@id, 'Task') and contains(@id, '-status')]</td> <td>//div[@class='front-project-list']//div[@class='project-line']//span[@class='status none margined green' and contains(@id, 'documented-project') and contains(@id, 'Task') and contains(@id, '-status')]</td>
<td></td> <td></td>
</tr> </tr>
...@@ -266,16 +266,16 @@ ...@@ -266,16 +266,16 @@
<td>//div[@class='front-project-list']//div[@class='project-line']//span[contains(@id, 'documented-project') and contains(@id, 'Task-Report') and contains(@id, '-outdated') and text()='0']</td> <td>//div[@class='front-project-list']//div[@class='project-line']//span[contains(@id, 'documented-project') and contains(@id, 'Task-Report') and contains(@id, '-outdated') and text()='0']</td>
<td></td> <td></td>
</tr> </tr>
<!-- Check Forum link --> <!-- Check Forum link
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-right']//a[contains(@id, 'documented-project') and contains(@id, 'link-forum') and @href='test-forum-link' and text()='Project Forum']</td> <td>//div[@class='front-project-list']//div[@class='project-right']//a[contains(@id, 'documented-project') and contains(@id, 'link-forum') and @href='test-forum-link' and text()='Project Forum']</td>
<td></td> <td></td>
</tr> </tr> -->
<!-- Check failed project --> <!-- Check failed project -->
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='failed-project']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//span[text()='failed-project']</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
......
...@@ -55,12 +55,17 @@ ...@@ -55,12 +55,17 @@
<!-- Check project present --> <!-- Check project present -->
<tr> <tr>
<td>assertElementPresent</td> <td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='test-project-home']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//span[text()='test-project-home']</td>
<td></td>
</tr>
<tr>
<td>assertElementPresent</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[@id='test-project-home-project_page_link' and text()='(Project Page)']</td>
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td>click</td> <td>click</td>
<td>//div[@class='front-project-list']//div[@class='project-title']//a[text()='test-project-home']</td> <td>//div[@class='front-project-list']//div[@class='project-title']//a[@id='test-project-home-project_page_link' and text()='(Project Page)']</td>
<td></td> <td></td>
</tr> </tr>
<!-- check project quick view page elements --> <!-- check project quick view page elements -->
......
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
</item> </item>
<item> <item>
<key> <string>title</string> </key> <key> <string>title</string> </key>
<value> <string>User Id</string> </value> <value> <string>User ID</string> </value>
</item> </item>
</dictionary> </dictionary>
</value> </value>
......
...@@ -61,7 +61,11 @@ class ActivityRuntimeEnvironment(object): ...@@ -61,7 +61,11 @@ class ActivityRuntimeEnvironment(object):
def getPriority(self): def getPriority(self):
result = self._priority result = self._priority
if result is None: if result is None:
return self._message.line.priority message = self._message
line = message.line
if line is None:
return message.activity_kw.get('priority', 1)
return line.priority
return result return result
security.declarePublic('edit') security.declarePublic('edit')
......
...@@ -197,6 +197,7 @@ class Message(BaseMessage): ...@@ -197,6 +197,7 @@ class Message(BaseMessage):
traceback = None traceback = None
document_uid = None document_uid = None
is_registered = False is_registered = False
line = None
def __init__( def __init__(
self, self,
......
...@@ -66,7 +66,9 @@ def for_each_activity(wrapped): ...@@ -66,7 +66,9 @@ def for_each_activity(wrapped):
for activity in ActivityTool.activity_dict: for activity in ActivityTool.activity_dict:
wrapped(self, activity) wrapped(self, activity)
self.abort() self.abort()
self.assertFalse(getMessageList()) self.assertFalse([
x.__dict__ for x in getMessageList()
])
return wraps(wrapped)(wrapper) return wraps(wrapped)(wrapper)
def registerFailingTransactionManager(*args, **kw): def registerFailingTransactionManager(*args, **kw):
...@@ -314,6 +316,7 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor): ...@@ -314,6 +316,7 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor):
self.commit() self.commit()
self.assertEqual(organisation.getTitle(),self.title1) self.assertEqual(organisation.getTitle(),self.title1)
self.assertEqual(organisation.getDescription(),self.title1) self.assertEqual(organisation.getDescription(),self.title1)
self.tic()
@for_each_activity @for_each_activity
def testTryTwoMethodsAndFlushThem(self, activity): def testTryTwoMethodsAndFlushThem(self, activity):
...@@ -427,6 +430,9 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor): ...@@ -427,6 +430,9 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor):
result = active_process.getResultList()[0] result = active_process.getResultList()[0]
self.assertEqual(result.method_id , 'getTitle') self.assertEqual(result.method_id , 'getTitle')
self.assertEqual(result.result , self.title1) self.assertEqual(result.result , self.title1)
# Execute any further activity which may have been spawned by activity
# execution (ex: fulltext indeation of the active process).
self.tic()
def TryActiveProcessWithResultDict(self, activity): def TryActiveProcessWithResultDict(self, activity):
""" """
...@@ -456,6 +462,9 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor): ...@@ -456,6 +462,9 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor):
result = result_dict[3] result = result_dict[3]
self.assertEqual(result_dict[3].method_id, 'getTitle') self.assertEqual(result_dict[3].method_id, 'getTitle')
self.assertEqual(result.result , self.title1) self.assertEqual(result.result , self.title1)
# Execute any further activity which may have been spawned by activity
# execution (ex: fulltext indeation of the active process).
self.tic()
@for_each_activity @for_each_activity
def testTryMethodAfterMethod(self, activity): def testTryMethodAfterMethod(self, activity):
...@@ -2339,10 +2348,24 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor): ...@@ -2339,10 +2348,24 @@ class TestCMFActivity(ERP5TypeTestCase, LogInterceptor):
obj = activity_tool.newActiveProcess() obj = activity_tool.newActiveProcess()
obj.reindexObject(activate_kw={'tag': 'foo', 'after_tag': 'bar'}) obj.reindexObject(activate_kw={'tag': 'foo', 'after_tag': 'bar'})
self.commit() self.commit()
# Check that both messages were inserted.
# Also serves as a sanity check on indexation activities group_method_id.
indexation_group_metdod_id = 'portal_catalog/catalogObjectList'
self.assertEqual(
len([
x
for x in activity_tool.getMessageList(path=obj.getPath())
if x.activity_kw.get('group_method_id') == indexation_group_metdod_id
]),
2,
)
invoked = [] invoked = []
def invokeGroup(self, *args): def invokeGroup(self, method_id, message_list, *args):
invoked.append(len(args[1])) # Ignore any other activity which may be spawned from these catalog
return ActivityTool_invokeGroup(self, *args) # indexations (ex: fulltext indexations).
if method_id == indexation_group_metdod_id:
invoked.append(len(message_list))
return ActivityTool_invokeGroup(self, method_id, message_list, *args)
ActivityTool_invokeGroup = activity_tool.__class__.invokeGroup ActivityTool_invokeGroup = activity_tool.__class__.invokeGroup
try: try:
activity_tool.__class__.invokeGroup = invokeGroup activity_tool.__class__.invokeGroup = invokeGroup
......
...@@ -114,13 +114,13 @@ class WebSiteTraversalHook(WebSectionTraversalHook): ...@@ -114,13 +114,13 @@ class WebSiteTraversalHook(WebSectionTraversalHook):
default_language = container.getDefaultAvailableLanguage() default_language = container.getDefaultAvailableLanguage()
if default_language and container.isStaticLanguageSelection(): if default_language and container.isStaticLanguageSelection():
if request.get('AcceptLanguage') is not None: if request.get('AcceptLanguage') is not None:
request['AcceptLanguage'].set(default_language, 80) request['AcceptLanguage'].set(default_language, 8)
else: else:
accept_language = request.get('AcceptLanguage') accept_language = request.get('AcceptLanguage')
if accept_language is not None: if accept_language is not None:
selected_language = accept_language.select_language( selected_language = accept_language.select_language(
container.getAvailableLanguageList()) container.getAvailableLanguageList())
if selected_language: if selected_language:
request['AcceptLanguage'].set(selected_language, 80) request['AcceptLanguage'].set(selected_language, 8)
elif default_language: elif default_language:
request['AcceptLanguage'].set(default_language, 80) request['AcceptLanguage'].set(default_language, 8)
...@@ -279,6 +279,20 @@ class ERP5Site(ResponseHeaderGenerator, FolderMixIn, PortalObjectBase, CacheCook ...@@ -279,6 +279,20 @@ class ERP5Site(ResponseHeaderGenerator, FolderMixIn, PortalObjectBase, CacheCook
PortalObjectBase.__init__(self, id) PortalObjectBase.__init__(self, id)
self.creation_date = DateTime() self.creation_date = DateTime()
security.declarePublic('getCoreBusinessTemplateList')
def getCoreBusinessTemplateList(self):
# Return the list of business templates expected to be installed when this
# class is instanciated. Allows including these business templates in the
# list of business templates to upgrade (ex: in upgrade unit tests) without
# duplicating this list.
return [
'erp5_property_sheets',
'erp5_core',
self.erp5_catalog_storage,
'erp5_jquery',
'erp5_xhtml_style',
]
security.declarePrivate('reindexObject') security.declarePrivate('reindexObject')
def reindexObject(self, idxs=[]): def reindexObject(self, idxs=[]):
"""from Products.CMFDefault.Portal""" """from Products.CMFDefault.Portal"""
...@@ -2406,8 +2420,7 @@ class ERP5Generator(PortalGenerator): ...@@ -2406,8 +2420,7 @@ class ERP5Generator(PortalGenerator):
""" """
template_tool = p.portal_templates template_tool = p.portal_templates
if template_tool.getInstalledBusinessTemplate('erp5_core') is None: if template_tool.getInstalledBusinessTemplate('erp5_core') is None:
for bt in ('erp5_property_sheets', 'erp5_core', p.erp5_catalog_storage, 'erp5_jquery', for bt in p.getCoreBusinessTemplateList():
'erp5_xhtml_style'):
if not bt: if not bt:
continue continue
url = getBootstrapBusinessTemplateUrl(bt) url = getBootstrapBusinessTemplateUrl(bt)
......
...@@ -144,12 +144,24 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject): ...@@ -144,12 +144,24 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
security.declarePrivate('activeScript') security.declarePrivate('activeScript')
def activeScript(self, script_name, ob_url, status, tdef_id): def activeScript(self, script_name, ob_url, status, tdef_id):
script = self.scripts[script_name] # BBB for when an upgrade to callInterationScript still has unexecuted
ob = self.unrestrictedTraverse(ob_url) # activeScript activities leftover from the previous code.
tdef = self.interactions.get(tdef_id) self.callInterationScript(
sci = StateChangeInfo( script_name=script_name,
ob, self, status, tdef, None, None, None) ob=self.unrestrictedTraverse(ob_url),
script(sci) status=status,
tdef_id=tdef_id,
)
security.declarePrivate('callInterationScript')
def callInterationScript(self, script_name, ob, status, tdef_id):
self.scripts[script_name](
StateChangeInfo(
ob, self, status,
self.interactions.get(tdef_id),
None, None, None,
),
)
def _checkTransitionGuard(self, t, ob, **kw): def _checkTransitionGuard(self, t, ob, **kw):
# This check can be implemented with a guard expression, but # This check can be implemented with a guard expression, but
......
...@@ -195,6 +195,9 @@ class DiscoverableMixin(CachedConvertableMixin): ...@@ -195,6 +195,9 @@ class DiscoverableMixin(CachedConvertableMixin):
document.share() document.share()
elif publication_state == "released": elif publication_state == "released":
document.release() document.release()
elif publication_state == "published":
document.publish()
maybeChangeState(self) maybeChangeState(self)
# Finish ingestion by calling method # Finish ingestion by calling method
......
...@@ -6,6 +6,12 @@ ...@@ -6,6 +6,12 @@
</pickle> </pickle>
<pickle> <pickle>
<dictionary> <dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>DiscoverableMixin</string> </value> <value> <string>DiscoverableMixin</string> </value>
...@@ -53,13 +59,28 @@ ...@@ -53,13 +59,28 @@
<item> <item>
<key> <string>workflow_history</string> </key> <key> <string>workflow_history</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="2" aka="AAAAAAAAAAI="> <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> <pickle>
<global name="PersistentMapping" module="Persistence.mapping"/> <global name="PersistentMapping" module="Persistence.mapping"/>
</pickle> </pickle>
...@@ -72,7 +93,7 @@ ...@@ -72,7 +93,7 @@
<item> <item>
<key> <string>component_validation_workflow</string> </key> <key> <string>component_validation_workflow</string> </key>
<value> <value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent> <persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value> </value>
</item> </item>
</dictionary> </dictionary>
...@@ -81,7 +102,7 @@ ...@@ -81,7 +102,7 @@
</dictionary> </dictionary>
</pickle> </pickle>
</record> </record>
<record id="3" aka="AAAAAAAAAAM="> <record id="4" aka="AAAAAAAAAAQ=">
<pickle> <pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/> <global name="WorkflowHistoryList" module="Products.ERP5Type.Workflow"/>
</pickle> </pickle>
......
# - Years always starts at 0h of the current year's first day and # - Years always starts at 0h of the current year's first day and
# finish 0h of the next year's first day. # finish 0h of the next year's first day.
from Products.ERP5Type.Message import translateString from Products.ERP5Type.Message import translateString
...@@ -27,21 +27,21 @@ if depth == 0: ...@@ -27,21 +27,21 @@ if depth == 0:
count = 0 count = 0
while count < 12: while count < 12:
# Create one Temp Object # Create one Temp Object
o = newTempBase(portal, id='year' ,uid='new_%s' % zfill('year',4)) o = newTempBase(portal, id='year', uid='new_%s' % zfill('year',4))
# Seting delimiter # Setting delimiter
if current_date.month() in [1, 7]: if current_date.month() in [1, 7]:
o.setProperty('delimiter_type', 1) o.setProperty('delimiter_type', 1)
else: else:
o.setProperty('delimiter_type', 0) o.setProperty('delimiter_type', 0)
# Setting Axis Dates start and stop # Setting Axis Dates start and stop
o.setProperty('start',current_date) o.setProperty('start', current_date)
if current_date.month() != 12: if current_date.month() != 12:
stop_date = DateTime(current_date.year(),current_date.month() +1,1) stop_date = DateTime(current_date.year(), current_date.month() +1, 1)
else: else:
stop_date = DateTime(year+1, 1, 1) stop_date = DateTime(year+1, 1, 1)
o.setProperty('stop', stop_date) o.setProperty('stop', stop_date)
o.setProperty('relative_position', int(current_date)) o.setProperty('relative_position', int(current_date))
title = translateString('${month_name} ${year}', title = translateString('${month_name} ${year}',
...@@ -50,9 +50,9 @@ if depth == 0: ...@@ -50,9 +50,9 @@ if depth == 0:
o.setProperty('title', title) o.setProperty('title', title)
# Defining Link # Defining Link
link = '%s&bound_start=%s&lane_path=base_month_domain' % ( default_link_url, url_quote(str(current_date))) link = '%s&bound_start=%s&lane_path=base_month_domain' % (default_link_url, url_quote(str(current_date)))
o.setProperty('link', link) o.setProperty('link', link)
category_list.append(o) category_list.append(o)
current_date = DateTime(str(current_date.year()) + '/' + str((current_date.month() +1)) + '/1') current_date = DateTime(str(current_date.year()) + '/' + str((current_date.month() +1)) + '/1')
count += 1 count += 1
...@@ -61,12 +61,12 @@ else: ...@@ -61,12 +61,12 @@ else:
for category in category_list: for category in category_list:
domain = parent.generateTempDomain(id = 'sub' + category.getProperty('id')) domain = parent.generateTempDomain(id = 'sub' + category.getProperty('id'))
domain.edit(title = category.getTitle(), domain.edit(title=category.getTitle(),
membership_criterion_base_category = ('parent', ), membership_criterion_base_category=('parent', ),
membership_criterion_category = (category,), membership_criterion_category=(category, ),
domain_generator_method_id = script.id, domain_generator_method_id=script.id,
uid = category.getUid()) uid=category.getUid())
domain_list.append(domain) domain_list.append(domain)
return domain_list return domain_list
...@@ -24,7 +24,8 @@ for value in value_list: ...@@ -24,7 +24,8 @@ for value in value_list:
new_dict['value'] = value new_dict['value'] = value
sub_field_list.append(new_dict) sub_field_list.append(new_dict)
sub_field_list.append(default_sub_field_property_dict) if not sub_field_list or default_sub_field_property_dict['editable']:
sub_field_list.append(default_sub_field_property_dict)
sub_field_list[0]['title'] = title sub_field_list[0]['title'] = title
return sub_field_list return sub_field_list
...@@ -10,10 +10,10 @@ ...@@ -10,10 +10,10 @@
# - Check skin names. # - Check skin names.
# - Check script names (from skin folders and workflows). # - Check script names (from skin folders and workflows).
import re import re
ABBREVIATION_WORD_SET = (( ABBREVIATION_WORD_SET = set((
"BBAN", "BIC", "BOM", "CAD", "CRM", "CSS", "CSV", "CTX", "DMS", "DNS", "BBAN", "BIC", "BOM", "CA", "CAD", "CRM", "CSS", "CSV", "CTX", "DMS", "DNS",
"EAN", "ERP5", "FAX", "GAP", "GID", "GPG", "HTML", "HTTP", "IBAN", "ID", "EAN", "ERP5", "FAX", "FTP", "GAP", "GID", "GPG", "HTML", "HTTP", "IBAN",
"IMAP", "IP", "KM", "MIME", "MRP", "NVP", "ODT", "PDF", "PDM", "PO", "ID", "IMAP", "IP", "KM", "MIME", "MRP", "NVP", "ODT", "PDF", "PDM", "PO",
"RAM", "RSS", "SMS", "SOAP", "SQL", "SVN", "TALES", "TCP", "TSV", "UBM", "RAM", "RSS", "SMS", "SOAP", "SQL", "SVN", "TALES", "TCP", "TSV", "UBM",
"UID", "UOM", "URI", "URL", "VADS", "VAT", "VCS", "VPN", "XML", "ZODB", "UID", "UOM", "URI", "URL", "VADS", "VAT", "VCS", "VPN", "XML", "ZODB",
)) ))
...@@ -75,8 +75,14 @@ def checkField(folder, form, field): ...@@ -75,8 +75,14 @@ def checkField(folder, form, field):
template_field = getFieldFromProxyField(field) template_field = getFieldFromProxyField(field)
if path.endswith("FieldLibrary"): if path.endswith("FieldLibrary"):
if not(template_field is field): if not(template_field is field):
if not(1 in [field.id.startswith(x) for x in ('my_view_mode_', field_id = field.id
'my_core_mode_', 'my_report_mode_', 'my_list_mode_', 'my_dialog_mode_')]): try:
prefix, field_id = field_id.split('_', 1)
except ValueError:
prefix = ''
if prefix not in ('my', 'your') and not any([field_id.startswith(x) for x in (
'view_mode_', 'core_mode_', 'report_mode_', 'list_mode_', 'dialog_mode_',
)]):
error_message += "%s: %s : Bad ID for a Field Library Field" % (path, field.id) error_message += "%s: %s : Bad ID for a Field Library Field" % (path, field.id)
if template_field is None: if template_field is None:
if field.get_value('enabled'): if field.get_value('enabled'):
......
...@@ -301,9 +301,7 @@ class PasswordTool(BaseTool): ...@@ -301,9 +301,7 @@ class PasswordTool(BaseTool):
) )
login_dict, = user_dict['login_list'] login_dict, = user_dict['login_list']
login = portal.unrestrictedTraverse(login_dict['path']) login = portal.unrestrictedTraverse(login_dict['path'])
login.checkPasswordValueAcceptable(password) # this will raise if password does not match policy login.setPassword(password) # this will raise if password does not match policy
login._forceSetPassword(password)
login.reindexObject()
return redirect(REQUEST, site_url, return redirect(REQUEST, site_url,
translateString("Password changed.")) translateString("Password changed."))
......
...@@ -203,7 +203,14 @@ class PeriodicityMixin: ...@@ -203,7 +203,14 @@ class PeriodicityMixin:
previous_date = next_start_date previous_date = next_start_date
next_start_date = max(self._getNextMinute(next_start_date, timezone), next_start_date = max(self._getNextMinute(next_start_date, timezone),
current_date) current_date)
while 1:
# We'll try every date to check if they validate the periodicity
# constraints, but there might not be any valid date (for example,
# repeat every 2nd week in August can never be validated). Because
# gregorian calendar repeat every 28 years, if we did not get a match
# in the next 28 years we stop looping.
max_date = next_start_date + (28 * 366)
while next_start_date < max_date:
if not self._validateMonth(next_start_date): if not self._validateMonth(next_start_date):
next_start_date = self._getNextMonth(next_start_date, timezone) next_start_date = self._getNextMonth(next_start_date, timezone)
elif not (self._validateDay(next_start_date) and elif not (self._validateDay(next_start_date) and
......
...@@ -40,7 +40,8 @@ from Products.ERP5Type.Utils import convertToUpperCase ...@@ -40,7 +40,8 @@ from Products.ERP5Type.Utils import convertToUpperCase
from Products.ERP5Type.tests.ERP5TypeTestCase import ( from Products.ERP5Type.tests.ERP5TypeTestCase import (
ERP5TypeTestCase, _getConversionServerUrlList) ERP5TypeTestCase, _getConversionServerUrlList)
from Products.ERP5Type.tests.Sequence import SequenceList from Products.ERP5Type.tests.Sequence import SequenceList
from Products.ERP5Type.tests.utils import FileUpload, createZODBPythonScript from Products.ERP5Type.tests.utils import FileUpload, removeZODBPythonScript, \
createZODBPythonScript
from Products.ERP5OOo.OOoUtils import OOoBuilder from Products.ERP5OOo.OOoUtils import OOoBuilder
from Products.CMFCore.utils import getToolByName from Products.CMFCore.utils import getToolByName
from zExceptions import BadRequest from zExceptions import BadRequest
...@@ -2025,6 +2026,53 @@ return result ...@@ -2025,6 +2026,53 @@ return result
self.assertTrue(document is not None) self.assertTrue(document is not None)
self.assertEqual(document.getData(), data) self.assertEqual(document.getData(), data)
def test_publication_state_in_Base_viewNewFileDialog(self):
"""
Checks that with type based method returning 'published',
we can upload with Base_viewNewFileDialog and declare the document as 'published'
"""
person = self.portal.person_module.newContent(portal_type="Person")
method_id = "Person_getPreferredAttachedDocumentPublicationState"
skin_folder = self.portal.portal_skins.custom
if not getattr(skin_folder, method_id, False):
createZODBPythonScript(skin_folder, method_id, "", "return")
skin_folder[method_id].ZPythonScript_edit('', 'return ""')
self.tic()
item_list = person.Base_viewNewFileDialog.your_publication_state.get_value("items")
self.assertEqual(
item_list,
[('', ''), ('Draft', 'draft'), ('Shared', 'shared'), ('Released', 'released')])
skin_folder[method_id].ZPythonScript_edit('', 'return None')
self.tic()
item_list = person.Base_viewNewFileDialog.your_publication_state.get_value("items")
self.assertEqual(
item_list,
[('', ''), ('Draft', 'draft'), ('Shared', 'shared'), ('Released', 'released')])
skin_folder[method_id].ZPythonScript_edit('', 'return "published"')
self.tic()
item_list = person.Base_viewNewFileDialog.your_publication_state.get_value("items")
self.assertEqual(
item_list, [
('', ''), ('Draft', 'draft'), ('Shared', 'shared'),
('Released', 'released'), ('Published', 'published')
])
# clean up and check if we don't have the script and published state in the list
removeZODBPythonScript(skin_folder, method_id)
self.tic()
self.assertEqual(
person.getTypeBasedMethod('getPreferredAttachedDocumentPublicationSection').getId(),
"Base_getPreferredAttachedDocumentPublicationSection"
)
self.portal.changeSkin(None)
item_list = person.Base_viewNewFileDialog.your_publication_state.get_value("items")
self.assertEqual(
item_list,
[('', ''), ('Draft', 'draft'), ('Shared', 'shared'), ('Released', 'released')])
class Base_contributeMixin: class Base_contributeMixin:
"""Tests for Base_contribute script. """Tests for Base_contribute script.
...@@ -2149,6 +2197,24 @@ class Base_contributeMixin: ...@@ -2149,6 +2197,24 @@ class Base_contributeMixin:
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf')) file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic() self.tic()
self.assertEqual(contributed_document.getValidationState(), 'released') self.assertEqual(contributed_document.getValidationState(), 'released')
contributed_document.setReference(None)
self.tic()
contributed_document = person.Base_contribute(
synchronous_metadata_discovery=False,
publication_state='published',
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'published')
contributed_document.setReference(None)
self.tic()
contributed_document = person.Base_contribute(
synchronous_metadata_discovery=True,
publication_state='published',
file=makeFileUpload('TEST-en-002.pdf', as_name='doc.pdf'))
self.tic()
self.assertEqual(contributed_document.getValidationState(), 'published')
def test_Base_contribute_publication_state_vs_finishIngestion_script(self): def test_Base_contribute_publication_state_vs_finishIngestion_script(self):
"""Contribute dialog allow choosing a publication state, but there's """Contribute dialog allow choosing a publication state, but there's
......
...@@ -127,10 +127,10 @@ class ERP5LoginUserManager(BasePlugin): ...@@ -127,10 +127,10 @@ class ERP5LoginUserManager(BasePlugin):
is_authentication_policy_enabled = self.getPortalObject().portal_preferences.isAuthenticationPolicyEnabled() is_authentication_policy_enabled = self.getPortalObject().portal_preferences.isAuthenticationPolicyEnabled()
if check_password: if check_password:
password = credentials.get('password') password = credentials.get('password')
if not password or not pw_validate( login_password = login_value.getPassword()
login_value.getPassword(), if (not password
password, or login_password is None
): or not pw_validate(login_password, password)):
if is_authentication_policy_enabled: if is_authentication_policy_enabled:
login_value.notifyLoginFailure() login_value.notifyLoginFailure()
return return
......
...@@ -332,14 +332,59 @@ class TestUserManagement(UserManagementTestCase): ...@@ -332,14 +332,59 @@ class TestUserManagement(UserManagementTestCase):
_, _, password = self._makePerson(login=login) _, _, password = self._makePerson(login=login)
self._assertUserExists(login, password) self._assertUserExists(login, password)
def test_PersonWithLoginWithEmptyPasswordAreNotUsers(self): def test_PersonWithLoginWithNonePasswordAreNotUsers(self):
"""Tests a person with a login but None as a password is not a valid user."""
# check password set to None at creation
_, login, _ = self._makePerson(password=None)
self._assertUserDoesNotExists(login, None)
self._assertUserDoesNotExists(login, 'None')
self._assertUserDoesNotExists(login, '')
# check password set to None after being set
user_data, = self.portal.acl_users.searchUsers(login=login, exact_match=True)
erp5_login = self.portal.restrictedTraverse(user_data['login_list'][0]['path'])
erp5_login.setPassword('secret')
self.tic()
self._assertUserExists(login, 'secret')
erp5_login.setPassword(None)
self.tic()
self._assertUserDoesNotExists(login, 'secret')
self._assertUserDoesNotExists(login, None)
self._assertUserDoesNotExists(login, 'None')
self._assertUserDoesNotExists(login, '')
def test_PersonWithLoginWithEmptyStringPasswordAreNotUsers(self):
"""Tests a person with a login but no password is not a valid user.""" """Tests a person with a login but no password is not a valid user."""
password = None _, login, _ = self._makePerson(password='')
_, login, _ = self._makePerson(password=password) self._assertUserDoesNotExists(login, '')
self._assertUserDoesNotExists(login, password) self._assertUserDoesNotExists(login, 'None')
password = ''
_, login, self._makePerson(password=password) # check password set to '' after being set
self._assertUserDoesNotExists(login, password) user_data, = self.portal.acl_users.searchUsers(login=login, exact_match=True)
erp5_login = self.portal.restrictedTraverse(user_data['login_list'][0]['path'])
erp5_login.setPassword('secret')
self.tic()
self._assertUserExists(login, 'secret')
erp5_login.setPassword('')
self.tic()
self._assertUserDoesNotExists(login, 'secret')
self._assertUserDoesNotExists(login, None)
self._assertUserDoesNotExists(login, 'None')
self._assertUserDoesNotExists(login, '')
def test_PersonWithLoginWithoutPasswordAreNotUsers(self):
"""Tests a person with a login but no password set is not a valid user."""
# similar to _makePerson, but not passing password= to newContent
login = 'login_%s' % self._login_generator()
new_person = self.portal.person_module.newContent(portal_type='Person')
new_person.newContent(portal_type='Assignment').open()
new_person.newContent(
portal_type='ERP5 Login',
reference=login,
).validate()
self.tic()
self._assertUserDoesNotExists(login, '')
self._assertUserDoesNotExists(login, 'None')
def test_PersonWithEmptyLoginAreNotUsers(self): def test_PersonWithEmptyLoginAreNotUsers(self):
"""Tests a person with empty login & password is not a valid user.""" """Tests a person with empty login & password is not a valid user."""
......
...@@ -1653,6 +1653,29 @@ class Base( ...@@ -1653,6 +1653,29 @@ class Base(
""" """
return self return self
security.declarePrivate('activeInteractionScript')
def activeInteractionScript(
self,
interaction_workflow_path,
script_name,
status,
tdef_id,
):
"""
Call interaction script on current document.
This is defined on the document involved in the interaction so that
CopySupport.unindexObject can find the activities involving this method
and flush them.
"""
self.getPortalObject().unrestrictedTraverse(
interaction_workflow_path,
).callInterationScript(
script_name=script_name,
ob=self,
status=status,
tdef_id=tdef_id,
)
security.declareProtected(Permissions.AccessContentsInformation, security.declareProtected(Permissions.AccessContentsInformation,
'getDocumentInstance') 'getDocumentInstance')
def getDocumentInstance(self): def getDocumentInstance(self):
......
...@@ -285,8 +285,12 @@ class InteractionWorkflow(Workflow): ...@@ -285,8 +285,12 @@ class InteractionWorkflow(Workflow):
# Execute "activity" scripts # Execute "activity" scripts
for script in tdef.getActivateScriptValueList(): for script in tdef.getActivateScriptValueList():
self.activate(activity='SQLQueue').activeScript( ob.activate(activity='SQLQueue').activeInteractionScript(
script.getId(), ob.getRelativeUrl(), status, tdef.getId()) interaction_workflow_path=self.getPhysicalPath(),
script_name=script.getId(),
status=status,
tdef_id=tdef.getId(),
)
def _before_commit(self, sci, script_name, security_manager): def _before_commit(self, sci, script_name, security_manager):
# check the object still exists before calling the script # check the object still exists before calling the script
...@@ -307,11 +311,24 @@ class InteractionWorkflow(Workflow): ...@@ -307,11 +311,24 @@ class InteractionWorkflow(Workflow):
security.declarePrivate('activeScript') security.declarePrivate('activeScript')
def activeScript(self, script_name, ob_url, status, tdef_id): def activeScript(self, script_name, ob_url, status, tdef_id):
ob = self.unrestrictedTraverse(ob_url) # BBB for when an upgrade to callInterationScript still has unexecuted
tdef = self.getTransitionValueByReference(tdef_id) # activeScript activities leftover from the previous code.
sci = StateChangeInfo( self.callInterationScript(
ob, self, status, tdef, None, None, None) script_name=script_name,
self._getOb(script_name)(sci) ob=self.unrestrictedTraverse(ob_url),
status=status,
tdef_id=tdef_id,
)
security.declarePrivate('callInterationScript')
def callInterationScript(self, script_name, ob, status, tdef_id):
self._getOb(script_name)(
StateChangeInfo(
ob, self, status,
self.getTransitionValueByReference(tdef_id),
None, None, None,
),
)
security.declarePrivate('isActionSupported') security.declarePrivate('isActionSupported')
def isActionSupported(self, ob, action, **kw): def isActionSupported(self, ob, action, **kw):
......
...@@ -320,7 +320,13 @@ class FunctionalTestRunner: ...@@ -320,7 +320,13 @@ class FunctionalTestRunner:
password_field.clear() password_field.clear()
password_field.send_keys(self.password) password_field.send_keys(self.password)
login_form_url = browser.current_url login_form_url = browser.current_url
password_field.submit() # Note: password_field.submit() (and in general, x.submit(), even if x is
# an <input type="submit"...>) does not work: it seems to submit only
# fields which have a value on their own. Which means type="submit" fields
# are absent, which breaks the form submission handling locic on Zope side.
password_field.find_element_by_xpath(
'ancestor::fieldset/descendant::input[@type="submit"]',
).click()
WebDriverWait(browser, 10).until(EC.url_changes(login_form_url)) WebDriverWait(browser, 10).until(EC.url_changes(login_form_url))
WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.TAG_NAME, 'body'))) WebDriverWait(browser, 10).until(EC.presence_of_element_located((By.TAG_NAME, 'body')))
......
...@@ -1050,8 +1050,15 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin): ...@@ -1050,8 +1050,15 @@ class ERP5TypeCommandLineTestCase(ERP5TypeTestCaseMixin):
update_business_templates = os.environ.get('update_business_templates') is not None update_business_templates = os.environ.get('update_business_templates') is not None
erp5_load_data_fs = int(os.environ.get('erp5_load_data_fs', 0)) erp5_load_data_fs = int(os.environ.get('erp5_load_data_fs', 0))
if update_business_templates and erp5_load_data_fs: if update_business_templates and erp5_load_data_fs:
template_list[:0] = (erp5_catalog_storage, 'erp5_property_sheets', app = self._app()
'erp5_core', 'erp5_xhtml_style') try:
template_list[:0] = app._getOb(
self.getPortalName(),
).getCoreBusinessTemplateList()
finally:
self.abort()
ZopeTestCase.close(app)
del app
# keep a mapping type info name -> property sheet list, to remove them in # keep a mapping type info name -> property sheet list, to remove them in
# tear down. # tear down.
......
This diff is collapsed.
...@@ -71,6 +71,7 @@ class TestNamingConvention(ERP5TypeTestCase): ...@@ -71,6 +71,7 @@ class TestNamingConvention(ERP5TypeTestCase):
'test_xhtml_style', 'cloudooo_data', 'cloudooo_web', 'erp5_configurator', 'test_xhtml_style', 'cloudooo_data', 'cloudooo_web', 'erp5_configurator',
'erp5_configurator_maxma_demo', 'erp5_configurator_run_my_doc', 'erp5_configurator_standard', 'erp5_configurator_maxma_demo', 'erp5_configurator_run_my_doc', 'erp5_configurator_standard',
'erp5_configurator_standard_solver', 'erp5_configurator_standard_solver',
'erp5_web_service',
# skip l10n templates to save time. # skip l10n templates to save time.
# 'erp5_l10n_fr', 'erp5_l10n_ja', # 'erp5_l10n_fr', 'erp5_l10n_ja',
# 'erp5_l10n_pl_PL', 'erp5_l10n_pt-BR', # 'erp5_l10n_pl_PL', 'erp5_l10n_pt-BR',
......
...@@ -161,7 +161,7 @@ class ERP5(_ERP5): ...@@ -161,7 +161,7 @@ class ERP5(_ERP5):
if search: if search:
group_dict = search.groupdict() group_dict = search.groupdict()
status_dict['failure_count'] = int(group_dict['failures']) \ status_dict['failure_count'] = int(group_dict['failures']) \
+ int(status_dict.get('failure_count', 0)) or int(status_dict.get('failure_count', 0))
status_dict['test_count'] = int(group_dict['total']) status_dict['test_count'] = int(group_dict['total'])
status_dict['skip_count'] = int(group_dict['expected_failure']) status_dict['skip_count'] = int(group_dict['expected_failure'])
return status_dict return status_dict
......
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