From b6f895ed1b790039f623d1476c8ffaecc6961080 Mon Sep 17 00:00:00 2001 From: Damien Pobel Date: Mon, 17 Mar 2014 16:06:13 +0100 Subject: [PATCH] Fix EZP-22480: Object creation does not respect attribute constraints in ezoe --- .../ezoe/upload/common_attributes.tpl | 5 +- .../standard/templates/ezoe/upload_files.tpl | 2 +- .../standard/templates/ezoe/upload_images.tpl | 2 +- .../templates/ezoe/upload_objects.tpl | 2 +- extension/ezoe/modules/ezoe/upload.php | 131 +++++++++------- .../classes/datatypes/ezfloat/ezfloattype.php | 143 ++++++++++++------ .../datatypes/ezinteger/ezintegertype.php | 12 +- .../datatypes/ezstring/ezstringtype.php | 12 +- kernel/classes/ezcontentupload.php | 53 +++++-- 9 files changed, 238 insertions(+), 124 deletions(-) diff --git a/extension/ezoe/design/standard/templates/ezoe/upload/common_attributes.tpl b/extension/ezoe/design/standard/templates/ezoe/upload/common_attributes.tpl index 61d81983606..7150d08f90e 100644 --- a/extension/ezoe/design/standard/templates/ezoe/upload/common_attributes.tpl +++ b/extension/ezoe/design/standard/templates/ezoe/upload/common_attributes.tpl @@ -1,9 +1,12 @@ {if is_unset( $file_name_attribute )} {def $file_name_attribute = ''} {/if} +{if is_unset( $objectname_input_name )} + {def $objectname_input_name = 'objectName'} +{/if} - + diff --git a/extension/ezoe/design/standard/templates/ezoe/upload_files.tpl b/extension/ezoe/design/standard/templates/ezoe/upload_files.tpl index d9fdf3e2937..14473055f53 100644 --- a/extension/ezoe/design/standard/templates/ezoe/upload_files.tpl +++ b/extension/ezoe/design/standard/templates/ezoe/upload_files.tpl @@ -52,7 +52,7 @@ tinyMCEPopup.onInit.add( function(){
- {include uri="design:ezoe/upload/common_attributes.tpl"} + {include uri="design:ezoe/upload/common_attributes.tpl" objectname_input_name='ContentObjectAttribute_name'} diff --git a/extension/ezoe/design/standard/templates/ezoe/upload_images.tpl b/extension/ezoe/design/standard/templates/ezoe/upload_images.tpl index 2c6b23ea57b..e23478b0a08 100644 --- a/extension/ezoe/design/standard/templates/ezoe/upload_images.tpl +++ b/extension/ezoe/design/standard/templates/ezoe/upload_images.tpl @@ -61,7 +61,7 @@ eZOEPopupUtils.settings.browseClassGenerator = function( n, hasImage ){
- {include uri="design:ezoe/upload/common_attributes.tpl" file_name_attribute='accept="image/*"'} + {include uri="design:ezoe/upload/common_attributes.tpl" objectname_input_name='ContentObjectAttribute_name' file_name_attribute='accept="image/*"'} diff --git a/extension/ezoe/design/standard/templates/ezoe/upload_objects.tpl b/extension/ezoe/design/standard/templates/ezoe/upload_objects.tpl index 44d372251a9..6dcacd57045 100755 --- a/extension/ezoe/design/standard/templates/ezoe/upload_objects.tpl +++ b/extension/ezoe/design/standard/templates/ezoe/upload_objects.tpl @@ -52,7 +52,7 @@ tinyMCEPopup.onInit.add( function(){
- {include uri="design:ezoe/upload/common_attributes.tpl"} + {include uri="design:ezoe/upload/common_attributes.tpl" objectname_input_name='ContentObjectAttribute_name'} diff --git a/extension/ezoe/modules/ezoe/upload.php b/extension/ezoe/modules/ezoe/upload.php index eb5524da8f8..db5cf8505c3 100755 --- a/extension/ezoe/modules/ezoe/upload.php +++ b/extension/ezoe/modules/ezoe/upload.php @@ -104,93 +104,122 @@ $objectName = trim( $http->postVariable( 'objectName' ) ); } - $uploadedOk = $upload->handleUpload( - $result, - 'fileName', - $location, - false, - $objectName, - $version->attribute( 'initial_language' )->attribute( 'locale' ) - ); - - - if ( $uploadedOk ) + try { - $newObject = $result['contentobject']; - $newObjectID = $newObject->attribute( 'id' ); - $newObjectName = $newObject->attribute( 'name' ); - $newObjectNodeID = (int) $newObject->attribute( 'main_node_id' ); // this will be empty if object is stopped by approve workflow - - // set parent section for new object - if ( isset( $newObjectNodeID ) && $newObjectNodeID ) + $uploadedOk = $upload->handleUpload( + $result, + 'fileName', + $location, + false, + $objectName, + $version->attribute( 'initial_language' )->attribute( 'locale' ), + false + ); + if ( !$uploadedOk ) { - $newObjectParentNodeObject = $newObject->attribute( 'main_node' )->attribute( 'parent' )->attribute( 'object' ); - $newObject->setAttribute( 'section_id', $newObjectParentNodeObject->attribute( 'section_id' ) ); - $newObject->store(); + throw new RuntimeException( "Upload failed" ); } - // edit attributes - $newVersionObject = $newObject->attribute( 'current' ); - $newObjectDataMap = $newVersionObject->attribute('data_map'); + $uploadVersion = $uploadedOk['contentobject']->currentVersion(); + $newObjectID = $uploadedOk['contentobject']->attribute( 'id' ); - foreach ( array_keys( $newObjectDataMap ) as $key ) + foreach ( $uploadVersion->dataMap() as $key => $attr ) { //post pattern: ContentObjectAttribute_attribute-identifier $base = 'ContentObjectAttribute_'. $key; - if ( $http->hasPostVariable( $base ) && $http->postVariable( $base ) !== '' ) + $postVar = trim( $http->postVariable( $base, '' ) ); + if ( $postVar !== '' ) { - switch ( $newObjectDataMap[$key]->attribute( 'data_type_string' ) ) + switch ( $attr->attribute( 'data_type_string' ) ) { - case 'eztext': case 'ezstring': - // TODO: Validate input ( max length ) - $newObjectDataMap[$key]->setAttribute('data_text', trim( $http->postVariable( $base ) ) ); - $newObjectDataMap[$key]->store(); + $classAttr = $attr->attribute( 'contentclass_attribute' ); + $dataType = $classAttr->attribute( 'data_type' ); + if ( $dataType->validateStringHTTPInput( $postVar, $attr, $classAttr ) !== eZInputValidator::STATE_ACCEPTED ) + { + throw new InvalidArgumentException( $attr->validationError() ); + } + case 'eztext': + case 'ezkeyword': + $attr->fromString( $postVar ); + $attr->store(); break; case 'ezfloat': - // TODO: Validate input ( max / min values ) - $newObjectDataMap[$key]->setAttribute('data_float', (float) str_replace(',', '.', $http->postVariable( $base ) ) ); - $newObjectDataMap[$key]->store(); + $floatValue = (float)str_replace( ',', '.', $postVar ); + $classAttr = $attr->attribute( 'contentclass_attribute' ); + $dataType = $classAttr->attribute( 'data_type' ); + if ( $dataType->validateFloatHTTPInput( $floatValue, $attr, $classAttr ) !== eZInputValidator::STATE_ACCEPTED ) + { + throw new InvalidArgumentException( $attr->validationError() ); + } + $attr->setAttribute( 'data_float', $floatValue ); + $attr->store(); break; case 'ezinteger': - // TODO: Validate input ( max / min values ) + $classAttr = $attr->attribute( 'contentclass_attribute' ); + $dataType = $classAttr->attribute( 'data_type' ); + if ( $dataType->validateIntegerHTTPInput( $postVar, $attr, $classAttr ) !== eZInputValidator::STATE_ACCEPTED ) + { + throw new InvalidArgumentException( $attr->validationError() ); + } case 'ezboolean': - $newObjectDataMap[$key]->setAttribute('data_int', (int) $http->postVariable( $base ) ); - $newObjectDataMap[$key]->store(); + $attr->setAttribute( 'data_int', (int)$postVar ); + $attr->store(); break; case 'ezimage': - $content = $newObjectDataMap[$key]->attribute('content'); - $content->setAttribute( 'alternative_text', trim( $http->postVariable( $base ) ) ); - $content->store( $newObjectDataMap[$key] ); - break; - case 'ezkeyword': - $newObjectDataMap[$key]->fromString( $http->postVariable( $base ) ); - $newObjectDataMap[$key]->store(); + // validation has been done by eZContentUpload + $content = $attr->attribute( 'content' ); + $content->setAttribute( 'alternative_text', $postVar ); + $content->store( $attr ); break; case 'ezxmltext': - $text = trim( $http->postVariable( $base ) ); $parser = new eZOEInputParser(); - $document = $parser->process( $text ); + $document = $parser->process( $postVar ); $xmlString = eZXMLTextType::domString( $document ); - $newObjectDataMap[$key]->setAttribute( 'data_text', $xmlString ); - $newObjectDataMap[$key]->store(); + $attr->setAttribute( 'data_text', $xmlString ); + $attr->store(); break; } } } - $object->addContentObjectRelation( $newObjectID, $objectVersion, 0, eZContentObject::RELATION_EMBED ); + $operationResult = eZOperationHandler::execute( + 'content', 'publish', + array( + 'object_id' => $newObjectID, + 'version' => $uploadVersion->attribute( 'version' ) + ) + ); + $newObject = eZContentObject::fetch( $newObjectID ); + $newObjectName = $newObject->attribute( 'name' ); + $newObjectNodeID = (int)$newObject->attribute( 'main_node_id' ); + + $object->addContentObjectRelation( + $newObjectID, + $uploadVersion->attribute( 'version' ), + 0, + eZContentObject::RELATION_EMBED + ); echo 'HiddenUploadFrame'; } - else + catch ( InvalidArgumentException $e ) + { + $uploadedOk['contentobject']->purge(); + echo 'HiddenUploadFrame
'; + echo '

' . htmlspecialchars( $e->getMessage() ) . '

'; + echo '
'; + } + catch ( RuntimeException $e ) { echo 'HiddenUploadFrame
'; foreach( $result['errors'] as $err ) - echo '

' . $err['description'] . '

'; + echo '

' . htmlspecialchars( $err['description'] ) . '

'; echo '
'; } eZDB::checkTransactionCounter(); diff --git a/kernel/classes/datatypes/ezfloat/ezfloattype.php b/kernel/classes/datatypes/ezfloat/ezfloattype.php index dc409f40138..7961ad36cf1 100644 --- a/kernel/classes/datatypes/ezfloat/ezfloattype.php +++ b/kernel/classes/datatypes/ezfloat/ezfloattype.php @@ -83,6 +83,96 @@ function fetchObjectAttributeHTTPInput( $http, $base, $contentObjectAttribute ) return false; } + /** + * Validates $data with the constraints defined on the class attribute + * + * @param $data + * @param eZContentObjectAttribute $contentObjectAttribute + * @param eZContentClassAttribute $classAttribute + * + * @return int + */ + function validateFloatHTTPInput( $data, $contentObjectAttribute, $classAttribute ) + { + $min = $classAttribute->attribute( self::MIN_FIELD ); + $max = $classAttribute->attribute( self::MAX_FIELD ); + $inputState = $classAttribute->attribute( self::INPUT_STATE_FIELD ); + switch( $inputState ) + { + case self::NO_MIN_MAX_VALUE: + $state = $this->FloatValidator->validate( $data ); + if ( $state === eZInputValidator::STATE_ACCEPTED ) + { + return eZInputValidator::STATE_ACCEPTED; + } + else + { + $contentObjectAttribute->setValidationError( + ezpI18n::tr( + 'kernel/classes/datatypes', + 'The given input is not a floating point number.' + ) + ); + } + break; + case self::HAS_MIN_VALUE: + $this->FloatValidator->setRange( $min, false ); + $state = $this->FloatValidator->validate( $data ); + if ( $state === eZInputValidator::STATE_ACCEPTED ) + { + return eZInputValidator::STATE_ACCEPTED; + } + else + { + $contentObjectAttribute->setValidationError( + ezpI18n::tr( + 'kernel/classes/datatypes', + 'The input must be greater than %1' + ), + $min + ); + } + break; + case self::HAS_MAX_VALUE: + $this->FloatValidator->setRange( false, $max ); + $state = $this->FloatValidator->validate( $data ); + if ( $state === eZInputValidator::STATE_ACCEPTED ) + { + return eZInputValidator::STATE_ACCEPTED; + } + else + { + $contentObjectAttribute->setValidationError( + ezpI18n::tr( + 'kernel/classes/datatypes', + 'The input must be less than %1' + ), + $max + ); + } + break; + case self::HAS_MIN_MAX_VALUE: + $this->FloatValidator->setRange( $min, $max ); + $state = $this->FloatValidator->validate( $data ); + if ( $state === eZInputValidator::STATE_ACCEPTED ) + { + return eZInputValidator::STATE_ACCEPTED; + } + else + { + $contentObjectAttribute->setValidationError( + ezpI18n::tr( + 'kernel/classes/datatypes', + 'The input is not in defined range %1 - %2' + ), + $min, $max + ); + } + break; + } + return eZInputValidator::STATE_INVALID; + } + /*! Validates the input and returns true if the input was valid for this datatype. @@ -93,10 +183,6 @@ function validateObjectAttributeHTTPInput( $http, $base, $contentObjectAttribute { $data = $http->postVariable( $base . "_data_float_" . $contentObjectAttribute->attribute( "id" ) ); $data = str_replace(" ", "", $data ); - $classAttribute = $contentObjectAttribute->contentClassAttribute(); - $min = $classAttribute->attribute( self::MIN_FIELD ); - $max = $classAttribute->attribute( self::MAX_FIELD ); - $input_state = $classAttribute->attribute( self::INPUT_STATE_FIELD ); if ( !$contentObjectAttribute->validateIsRequired() && ( $data == "" ) ) { @@ -106,51 +192,10 @@ function validateObjectAttributeHTTPInput( $http, $base, $contentObjectAttribute $locale = eZLocale::instance(); $data = $locale->internalNumber( $data ); - switch( $input_state ) - { - case self::NO_MIN_MAX_VALUE: - { - $state = $this->FloatValidator->validate( $data ); - if( $state===1 ) - return eZInputValidator::STATE_ACCEPTED; - else - $contentObjectAttribute->setValidationError( ezpI18n::tr( 'kernel/classes/datatypes', - 'The given input is not a floating point number.' ) ); - } break; - case self::HAS_MIN_VALUE: - { - $this->FloatValidator->setRange( $min, false ); - $state = $this->FloatValidator->validate( $data ); - if( $state===1 ) - return eZInputValidator::STATE_ACCEPTED; - else - $contentObjectAttribute->setValidationError( ezpI18n::tr( 'kernel/classes/datatypes', - 'The input must be greater than %1' ), - $min ); - } break; - case self::HAS_MAX_VALUE: - { - $this->FloatValidator->setRange( false, $max ); - $state = $this->FloatValidator->validate( $data ); - if( $state===1 ) - return eZInputValidator::STATE_ACCEPTED; - else - $contentObjectAttribute->setValidationError( ezpI18n::tr( 'kernel/classes/datatypes', - 'The input must be less than %1' ), - $max ); - } break; - case self::HAS_MIN_MAX_VALUE: - { - $this->FloatValidator->setRange( $min, $max ); - $state = $this->FloatValidator->validate( $data ); - if( $state===1 ) - return eZInputValidator::STATE_ACCEPTED; - else - $contentObjectAttribute->setValidationError( ezpI18n::tr( 'kernel/classes/datatypes', - 'The input is not in defined range %1 - %2' ), - $min, $max ); - } break; - } + return $this->validateFloatHTTPInput( + $data, $contentObjectAttribute, + $contentObjectAttribute->contentClassAttribute() + ); } return eZInputValidator::STATE_INVALID; } diff --git a/kernel/classes/datatypes/ezinteger/ezintegertype.php b/kernel/classes/datatypes/ezinteger/ezintegertype.php index ba50d15da0e..7e6959c8e6b 100644 --- a/kernel/classes/datatypes/ezinteger/ezintegertype.php +++ b/kernel/classes/datatypes/ezinteger/ezintegertype.php @@ -43,9 +43,15 @@ function eZIntegerType() $this->IntegerValidator = new eZIntegerValidator(); } - /*! - Private method, only for using inside this class. - */ + /** + * Validates $data with the constraints defined on the class attribute + * + * @param $data + * @param eZContentObjectAttribute $contentObjectAttribute + * @param eZContentClassAttribute $classAttribute + * + * @return int + */ function validateIntegerHTTPInput( $data, $contentObjectAttribute, $classAttribute ) { $min = $classAttribute->attribute( self::MIN_VALUE_FIELD ); diff --git a/kernel/classes/datatypes/ezstring/ezstringtype.php b/kernel/classes/datatypes/ezstring/ezstringtype.php index 6f5fb6ea14d..14f80bbe02d 100644 --- a/kernel/classes/datatypes/ezstring/ezstringtype.php +++ b/kernel/classes/datatypes/ezstring/ezstringtype.php @@ -66,9 +66,15 @@ function initializeObjectAttribute( $contentObjectAttribute, $currentVersion, $o } } - /* - Private method, only for using inside this class. - */ + /** + * Validates $data with the constraints defined on the class attribute + * + * @param $data + * @param eZContentObjectAttribute $contentObjectAttribute + * @param eZContentClassAttribute $classAttribute + * + * @return int + */ function validateStringHTTPInput( $data, $contentObjectAttribute, $classAttribute ) { $maxLen = $classAttribute->attribute( self::MAX_LEN_FIELD ); diff --git a/kernel/classes/ezcontentupload.php b/kernel/classes/ezcontentupload.php index 011deccdc81..2bcfb512dca 100644 --- a/kernel/classes/ezcontentupload.php +++ b/kernel/classes/ezcontentupload.php @@ -451,10 +451,11 @@ function handleLocalFile( &$result, $filePath, $location, $existingNode, $nameSt * @param string|false $localeCode * Locale code (eg eng-GB, fre-FR, ...) to use when creating the * object or the version. + * @param boolean $publish whether to publish the new created content object * * @return boolean */ - function handleUpload( &$result, $httpFileIdentifier, $location, $existingNode, $nameString = '', $localeCode = false ) + function handleUpload( &$result, $httpFileIdentifier, $location, $existingNode, $nameString = '', $localeCode = false, $publish = true ) { $result = array( 'errors' => array(), 'notices' => array(), @@ -696,8 +697,43 @@ function handleUpload( &$result, $httpFileIdentifier, $location, $existingNode, if ( $storeResult['require_storage'] ) $dataMap[$nameAttribute]->store(); - $tmpresult = $this->publishObject( $result, $result['errors'], $result['notices'], - $object, $publishVersion, $class, $parentNodes, $parentMainNode ); + if ( is_array( $parentNodes ) ) + { + foreach ( $parentNodes as $key => $parentNode ) + { + $object->createNodeAssignment( + $parentNode, + $parentNode == $parentMainNode + ); + } + } + + $object->setName( $class->contentObjectName( $object ) ); + $object->store(); + + if ( $publish ) + { + $tmpresult = $this->publishObject( + $result, $result['errors'], $result['notices'], + $object, $publishVersion, $class, $parentNodes, $parentMainNode + ); + } + else + { + $tmpresult = $result; + $tmpresult['contentobject'] = $object; + $tmpresult['contentobject_id'] = $object->attribute( 'id' ); + $tmpresult['contentobject_version'] = $publishVersion; + $tmpresult['contentobject_main_node'] = false; + $tmpresult['contentobject_main_node_id'] = false; + $this->setResult( + array( + 'node_id' => 0, + 'object_id' => $object->attribute( 'id' ), + 'object_version' => $publishVersion + ) + ); + } $db->commit(); return $tmpresult; @@ -712,17 +748,6 @@ function handleUpload( &$result, $httpFileIdentifier, $location, $existingNode, function publishObject( &$result, &$errors, &$notices, $object, $publishVersion, $class, $parentNodes, $parentMainNode ) { - if ( is_array( $parentNodes ) ) - { - foreach ( $parentNodes as $key => $parentNode ) - { - $object->createNodeAssignment( $parentNode, $parentNode == $parentMainNode ); - } - } - - $object->setName( $class->contentObjectName( $object ) ); - $object->store(); - $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $object->attribute( 'id' ), 'version' => $publishVersion ) );