Commit 6afe0fc8 authored by Jérome Perrin's avatar Jérome Perrin

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

parents be6c0474 70d11122
......@@ -40,7 +40,7 @@ class CausalityAssignmentMovementGroup(MovementGroup):
portal_type = 'Causality Assignment Movement Group'
def _getPropertyDict(self, movement, **kw):
return self._addCausalityToEdit(movement)
return self._addCausalityToEdit(movement, {})
def _separate(self, movement_list, **kw):
if not movement_list:
......@@ -51,13 +51,17 @@ class CausalityAssignmentMovementGroup(MovementGroup):
return [[movement_list, property_dict]]
def test(self, movement, property_dict, **kw):
# We can always update.
causality_list = movement.getCausalityList()
if causality_list:
property_dict = property_dict.copy()
for causality in property_dict.get('causality_list', ()):
if causality not in causality_list:
causality_list.append(causality)
property_dict['causality_list'] = causality_list
return True, property_dict
def _addCausalityToEdit(self, movement, property_dict=None):
if property_dict is None:
property_dict = {}
causality_list = property_dict.get('causality_list', [])
def _addCausalityToEdit(self, movement, property_dict):
causality_list = property_dict.setdefault('causality_list', [])
root_movement = movement.getRootSimulationMovement()
# 'order' category is deprecated. it is kept for compatibility.
movement_list = root_movement.getOrderList() or \
......@@ -65,5 +69,4 @@ class CausalityAssignmentMovementGroup(MovementGroup):
for delivery_movement in movement_list:
if delivery_movement not in causality_list:
causality_list.append(delivery_movement)
property_dict['causality_list'] = causality_list
return property_dict
......@@ -36,9 +36,7 @@ class DeliveryCausalityAssignmentMovementGroup(CausalityAssignmentMovementGroup)
meta_type = 'ERP5 Delivery Causality Assignment Movement Group'
portal_type = 'Delivery Causality Assignment Movement Group'
def _addCausalityToEdit(self, movement, property_dict=None):
if property_dict is None:
property_dict = {}
def _addCausalityToEdit(self, movement, property_dict):
if movement.getParentValue().isRootAppliedRule():
# Here movement probably comes from invoice rule, in that situation, we
# are not able to go up and find a delivery.
......@@ -51,10 +49,9 @@ class DeliveryCausalityAssignmentMovementGroup(CausalityAssignmentMovementGroup)
delivery_movement = parent.getDeliveryValue()
if delivery_movement is not None:
delivery = delivery_movement.getExplanationValue()
causality = property_dict.get('causality_list', [])
causality = property_dict.setdefault('causality_list', [])
delivery_url = delivery.getRelativeUrl()
if delivery_url not in causality:
causality.append(delivery_url)
property_dict['causality_list'] = causality
return property_dict
......@@ -42,11 +42,8 @@ class OrderMovementGroup(MovementGroup):
return {'causality_list': [self._getOrderRelativeUrl(movement)]}
def test(self, movement, property_dict, **kw):
if set(property_dict['causality_list']).issubset(movement.getCausalityList()):
property_dict['causality_list'] = movement.getCausalityList()
return True, property_dict
else:
return False, property_dict
return set(property_dict['causality_list']
).issubset(movement.getCausalityList()), {}
def _getOrderRelativeUrl(self, movement):
try:
......
......@@ -37,9 +37,17 @@ class IMovementGroup(Interface):
"""
def test(document, property_dict, **kw):
"""Returns a tuple of 2 values.
First one is True if document contains identical values than some
contained property_dict.
Second one is a modified version of property_dict.
First one is True if processed movements can be built to 'document'.
Second one is a dict of properties that are set to 'document' if the
latter is actually chosen: it can be 'property_dict', which was the dict
returned by 'separate' for the considered movements.
'property_dict' shall be treated as immutable recursively. A modified
copy (deeply if necessary) can be returned.
A common implementation is to return a 2-tuple whose first value
is True when properties of 'document' are same as 'property_dict',
then there's usually no property to set and the second value is {}.
TODO:
- take into account the possibility to use Divergence Testers
......
......@@ -323,18 +323,6 @@ class BuilderMixin(XMLObject, Amount, Predicate):
root_group_node.append(movement_list)
return root_group_node
def _test(self, instance, movement_group_node_list,
divergence_list):
result = True
new_property_dict_list = []
for movement_group_node in movement_group_node_list:
tmp_result, tmp_property_dict = movement_group_node.test(
instance, divergence_list)
if not tmp_result:
result = tmp_result
new_property_dict_list.append(tmp_property_dict)
return result, new_property_dict_list
@staticmethod
def _getSortedPropertyDict(property_dict_list):
# Sort the edit keywords according to the order of their movement
......@@ -357,7 +345,6 @@ class BuilderMixin(XMLObject, Amount, Predicate):
def _findUpdatableObject(self, instance_list, movement_group_node_list,
divergence_list):
instance = None
if instance_list:
# we want to check the original delivery first.
# so sort instance_list by that current is exists or not.
......@@ -371,16 +358,19 @@ class BuilderMixin(XMLObject, Amount, Predicate):
current = current.getParentValue()
except AttributeError:
pass
for instance_to_update in instance_list:
result, property_dict_list = self._test(
instance_to_update, movement_group_node_list, divergence_list)
if result:
instance = instance_to_update
break
else:
property_dict_list = [movement_group_node.getGroupEditDict()
for movement_group_node in movement_group_node_list]
return instance, self._getSortedPropertyDict(property_dict_list)
for instance in instance_list:
property_dict_list = []
for movement_group_node in movement_group_node_list:
result, property_dict = movement_group_node.test(
instance, divergence_list)
if not result:
break
property_dict_list.append(property_dict)
else:
return instance, self._getSortedPropertyDict(property_dict_list)
return None, self._getSortedPropertyDict(
movement_group_node.getGroupEditDict()
for movement_group_node in movement_group_node_list)
security.declarePrivate('buildDeliveryList')
@UnrestrictedMethod
......
......@@ -46,6 +46,7 @@ import string
import tempfile
import glob
import sys
from OFS.Image import Pdata
WORKFLOW_TYPE = 'erp5_workflow'
......@@ -7262,8 +7263,14 @@ class TestBusinessTemplate(BusinessTemplateMixin):
self.assertEqual(file_content, expected_file_content)
self.assertEqual(len(file_content), len(expected_file_content))
def stepCheckFileisImportedAsPdata(self, sequence=None, **kw):
self.assertIsInstance(self.portal.portal_templates
.getInstalledBusinessTemplate('erp5_xhtml_style')._skin_item._objects
['portal_skins/erp5_ckeditor/ckeditor/LICENSE.md'].data, Pdata)
def test_text_file_import_export(self):
"""
First Check if file is imported as Pdata, then check the following case:
When importing back ace.js containing a last line with whitespaces only,
the last line was not imported, and thus the file could never been
downloaded completely as its really size was less than the one on the File
......@@ -7271,6 +7278,8 @@ class TestBusinessTemplate(BusinessTemplateMixin):
"""
sequence_list = SequenceList()
sequence_string = """
CheckFileisImportedAsPdata
CreateSkinFolder
CreateTextFile
CheckTextFileContent
......
......@@ -30,7 +30,7 @@ person_mapping = (
('gender', 'gender'),
('default_telephone_text', 'default_telephone_text'),
('default_mobile_telephone_text', 'default_mobile_telephone_text'),
('default_email_text', 'default_email_text'),
('default_email_coordinate_text', 'default_email_coordinate_text'),
('date_of_birth', 'start_date'),
('nationality', 'nationality'),
('skill_list', 'default_career_skill_list'),
......
......@@ -5,7 +5,7 @@ organisation = context.getDestinationDecisionValue(portal_type="Organisation")
#Mapping
organisation_mapping = (
# (subscription, organisation)
('default_email_text', 'default_email_text'),
('default_email_coordinate_text', 'default_email_coordinate_text'),
('default_telephone_text', 'default_telephone_text'),
('default_fax_text', 'default_fax_text'),
('default_address_street_address', 'default_address_street_address'),
......
......@@ -13,7 +13,7 @@ person_mapping = (
('date_of_birth', 'birthday'),
('nationality', 'nationality'),
('language', 'language'),
('default_email_text', 'default_email_text'),
('default_email_coordinate_text', 'default_email_coordinate_text'),
('default_telephone_telephone_country', 'default_telephone_telephone_country'),
('default_telephone_text', 'default_telephone_text'),
('default_fax_text', 'default_fax_text'),
......
......@@ -33,7 +33,7 @@ if default_email_text is not None:
message = "We have sent you an email containing your username(s). Please check your inbox and your junk/spam mail for this email."
if web_site:
document_reference = web_site.getCredentialUsernameRecoveryMessageReference()
createCredentialRecovery(default_email_text=default_email_text,
createCredentialRecovery(default_email_coordinate_text=default_email_text,
destination_decision_value_list=person_list,
document_reference=document_reference,
language=portal.Localizer.get_selected_language())
......
......@@ -23,7 +23,7 @@ credential_request = module.newContent(
default_credential_question_question=default_credential_question_question,
default_credential_question_question_free_text=default_credential_question_question_free_text,
default_credential_question_answer=default_credential_question_answer,
default_email_text=default_email_text,
default_email_coordinate_text=default_email_text,
default_telephone_text=default_telephone_text,
default_mobile_telephone_text=default_mobile_telephone_text,
default_fax_text=default_fax_text,
......
......@@ -403,6 +403,8 @@ class TestERP5Credential(ERP5TypeTestCase):
person = person_result[0].getObject()
self.assertEqual(person.getTitle(), 'Homer Simpson')
self.assertEqual(person.getDefaultEmailText(), 'homer.simpson@fox.com')
# the obsolete email property is not used
self.assertFalse(person.hasDefaultEmailUrlString())
# check homie can log in the system
self._assertUserExists('homie', 'secret')
......@@ -429,7 +431,7 @@ class TestERP5Credential(ERP5TypeTestCase):
last_name='Simpsons', # add a 's' to the end of the last_name
reference='homie',
password='new_password',
default_email_text='homie.simpsons@fox.com',
default_email_coordinate_text='homie.simpsons@fox.com',
destination_decision=homie.getRelativeUrl())
credential_update.submit()
......@@ -456,6 +458,7 @@ class TestERP5Credential(ERP5TypeTestCase):
self.assertEqual(related_person.getLastName(), 'Simpsons')
self.assertEqual(related_person.getDefaultEmailText(),
'homie.simpsons@fox.com')
self.assertFalse(related_person.hasDefaultEmailUrlString())
def stepCreateSubscriptionRequestWithSecurityQuestionCategory(self, sequence=None,
sequence_list=None, **kw):
......@@ -544,7 +547,7 @@ class TestERP5Credential(ERP5TypeTestCase):
person = person_module.newContent(title='Barney',
reference='barney',
start_date=DateTime('1970/01/01'),
default_email_text='barney@duff.com')
default_email_coordinate_text='barney@duff.com')
# create an assignment
assignment = person.newContent(portal_type='Assignment',
function='member')
......@@ -862,6 +865,7 @@ class TestERP5Credential(ERP5TypeTestCase):
self.assertEqual("Homer", person.getFirstName())
self.assertEqual("Simpson", person.getLastName())
self.assertEqual("homer.simpson@fox.com", person.getDefaultEmailText())
self.assertFalse(person.hasDefaultEmailUrlString())
self.assertEqual(DateTime('1970/01/01'), person.getStartDate())
self.logout()
......@@ -878,6 +882,7 @@ class TestERP5Credential(ERP5TypeTestCase):
self.assertEqual("tom", person.getFirstName())
self.assertEqual("Simpson", person.getLastName())
self.assertEqual("tom@host.com", person.getDefaultEmailText())
self.assertFalse(person.hasDefaultEmailUrlString())
self.assertEqual(DateTime('1970/01/01'), person.getStartDate())
def stepCheckPersonWhenCredentialUpdateFail(self, sequence=None,
......@@ -1138,6 +1143,7 @@ class TestERP5Credential(ERP5TypeTestCase):
self.assertEqual(credential_request.getFirstName(), "Barney")
self.assertEqual(credential_request.getDefaultEmailText(),
"barney@duff.com")
self.assertFalse(credential_request.hasDefaultEmailUrlString())
self.assertEqual(credential_request.getRole(), "internal")
self.assertEqual(credential_request.getFunction(), "member")
......
......@@ -27,11 +27,11 @@
#
##############################################################################
import base64
import hashlib
import json
import platform
import random
from base64 import b64encode
from DateTime import DateTime
......@@ -47,8 +47,6 @@ class ShaDirMixin(object):
self.portal = self.getPortal()
self.key = 'mykey' + str(random.random())
self.file_name = 'file.txt'
self.urlmd5 = hashlib.md5(self.key).hexdigest()
self.file_content = 'This is the content.'
self.file_sha512sum = hashlib.sha512(self.file_content).hexdigest()
self.distribution = 'pypi'
......@@ -58,21 +56,20 @@ class ShaDirMixin(object):
libc_version = '%s %s' % (platform.libc_ver()[0], platform.libc_ver()[1])
self.architecture = '%s %s' % (platform.machine(), libc_version)
self.data_list = [json.dumps({'file': self.file_name,
'urlmd5': self.urlmd5,
self.data_list = [json.dumps({
'sha512': self.file_sha512sum,
'creation_date': str(self.creation_date),
'expiration_date': str(self.expiration_date),
'distribution': self.distribution,
'architecture': self.architecture}),
"User SIGNATURE goes here."]
b64encode("User SIGNATURE goes here.")]
self.data = json.dumps(self.data_list)
self.sha512sum = hashlib.sha512(self.data).hexdigest()
self.header_dict = {
'Content-Type': 'application/json',
'Authorization': 'Basic %s' % (base64.encodestring('ERP5TypeTestCase:').strip())
'Authorization': 'Basic ' + b64encode('ERP5TypeTestCase:'),
}
module = self.portal.web_site_module
......
......@@ -27,11 +27,12 @@
#
##############################################################################
import hashlib
import httplib
import urlparse
import json
import random
from base64 import b64encode
from unittest import expectedFailure
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from erp5.component.test.ShaDirMixin import ShaDirMixin
......@@ -214,17 +215,15 @@ class TestShaDir(ShaDirMixin, ERP5TypeTestCase):
self.postInformation()
self.tic()
urlmd5_2 = 'anotherurlmd5' + str(random.random())
sha512_2 = 'anothersha512_2' + str(random.random())
sha512_2 = hashlib.sha512(str(random.random())).hexdigest()
key_2 = 'another_key' + str(random.random())
data_list_2 = [json.dumps({'file': self.file_name,
'urlmd5': urlmd5_2,
data_list_2 = [json.dumps({
'sha512': sha512_2,
'creation_date': str(self.creation_date),
'expiration_date': str(self.expiration_date),
'distribution': self.distribution,
'architecture': self.architecture}),
"User SIGNATURE goes here."]
b64encode("User SIGNATURE goes here.")]
data_2 = json.dumps(data_list_2)
self.postInformation(key_2, data_2)
self.tic()
......
......@@ -146,14 +146,10 @@ class TestShaDirExternal(ShaDirMixin, ShaSecurityMixin, ERP5TypeTestCase):
self.assertEqual(302, result.status)
def test_external_post_with_wrong_data(self):
"""
The data which is sent to the server must follow a JSON schema.
If the data does not follow the schema it must return the error.
"""
# Removing a required property
data = json.loads(self.data)
data[0] = json.loads(data[0])
data[0].pop('file')
del data[0]['sha512']
data[0] = json.dumps(data[0])
data = json.dumps(data)
......@@ -165,7 +161,6 @@ class TestShaDirExternal(ShaDirMixin, ShaSecurityMixin, ERP5TypeTestCase):
data = result.read()
finally:
connection.close()
self.assertTrue("Required field 'file' is missing" in data, data)
self.assertEqual(500, result.status)
self.assertEqual(400, result.status)
self.assertEqual('text/html; charset=utf-8',
result.getheader("content-type"))
......@@ -99,6 +99,7 @@ from ZODB.broken import Broken, BrokenModified
from Products.ERP5.genbt5list import BusinessTemplateRevision, \
item_name_list, item_set
from Products.ERP5Type.mixin.component import ComponentMixin
from OFS.Image import File as OFSFile
CACHE_DATABASE_PATH = None
try:
......@@ -878,6 +879,8 @@ class ObjectTemplateItem(BaseTemplateItem):
# backward-compatibility
elif six.PY3 and is_text:
data = data.decode('utf-8')
if isinstance(obj, OFSFile) and property_name == "data":
data = obj._read_data(data)[0]
try:
setattr(obj, property_name, data)
except BrokenModified:
......
......@@ -164,8 +164,15 @@ class MovementGroupNode:
if not property_list:
return True, {}
# else update anyway (eg. CausalityAssignmentMovementGroup etc.)
return self._movement_group.test(movement, self._property_dict,
property_list=property_list)
result, property_dict = self._movement_group.test(
movement, self._property_dict, property_list=property_list)
# The following check is partial because it does not check mutable values
# recursively.
if property_dict is self._property_dict != property_dict:
raise ValueError(
"Movement Group must not modify the passed 'property_dict':"
" copy it, deeply if necessary, before editing properties")
return result, property_dict
else:
return True, {}
......
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