Merge pull request #1432 from jygaulier/PHRAS-504_CRLF-in-proposals

PHRAS-504
This commit is contained in:
Benoît Burnichon
2015-07-16 11:11:10 +02:00
12 changed files with 133 additions and 105 deletions

View File

@@ -15,6 +15,7 @@ use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Core\Configuration\DisplaySettingService; use Alchemy\Phrasea\Core\Configuration\DisplaySettingService;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
use Alchemy\Phrasea\Utilities\StringHelper;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@@ -32,6 +33,9 @@ class QueryController extends Controller
{ {
$query = (string) $request->request->get('qry'); $query = (string) $request->request->get('qry');
// since the query comes from a submited form, normalize crlf,cr,lf ...
$query = StringHelper::crlfNormalize($query);
$json = []; $json = [];
$options = SearchEngineOptions::fromRequest($this->app, $request); $options = SearchEngineOptions::fromRequest($this->app, $request);

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Form\Login;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Form\Constraint\NewEmail; use Alchemy\Phrasea\Form\Constraint\NewEmail;
use Alchemy\Phrasea\Utilities\String\Camelizer; use Alchemy\Phrasea\Utilities\StringHelper;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
@@ -23,14 +23,12 @@ class PhraseaRegisterForm extends AbstractType
{ {
private $available; private $available;
private $params; private $params;
private $camelizer;
public function __construct(Application $app, array $available, array $params = [], Camelizer $camelizer = null) public function __construct(Application $app, array $available, array $params = [])
{ {
$this->app = $app; $this->app = $app;
$this->available = $available; $this->available = $available;
$this->params = $params; $this->params = $params;
$this->camelizer = $camelizer ?: new Camelizer();
} }
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
@@ -115,7 +113,7 @@ class PhraseaRegisterForm extends AbstractType
$builder->add( $builder->add(
// angular does not support hyphens // angular does not support hyphens
$this->camelizer->camelize($name, '-'), StringHelper::camelize($name, '-'),
$this->getType($name), $this->getType($name),
$options $options
); );

View File

@@ -15,6 +15,7 @@ use Alchemy\Phrasea\SearchEngine\Elastic\Exception\Exception;
use Alchemy\Phrasea\SearchEngine\Elastic\Mapping; use Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper; use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure; use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\Utilities\StringHelper;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Connection as DriverConnection; use Doctrine\DBAL\Driver\Connection as DriverConnection;
use DomainException; use DomainException;
@@ -74,6 +75,7 @@ SQL;
switch ($metadata['type']) { switch ($metadata['type']) {
case 'caption': case 'caption':
// Sanitize fields // Sanitize fields
$value = StringHelper::crlfNormalize($value);
switch ($this->structure->typeOf($key)) { switch ($this->structure->typeOf($key)) {
case Mapping::TYPE_DATE: case Mapping::TYPE_DATE:
$value = $this->helper->sanitizeDate($value); $value = $this->helper->sanitizeDate($value);

View File

@@ -11,20 +11,10 @@
namespace Alchemy\Phrasea\Twig; namespace Alchemy\Phrasea\Twig;
use Alchemy\Phrasea\Utilities\String\Camelizer; use Alchemy\Phrasea\Utilities\StringHelper;
class Camelize extends \Twig_Extension class Camelize extends \Twig_Extension
{ {
/**
* @var Camelizer
*/
private $camelizer;
public function __construct(Camelizer $camelizer = null)
{
$this->camelizer = $camelizer ?: new Camelizer();
}
/** /**
* *
* @return string * @return string
@@ -47,6 +37,6 @@ class Camelize extends \Twig_Extension
public function toCamelCase($str, $separator = '-', $pascalCase = false) public function toCamelCase($str, $separator = '-', $pascalCase = false)
{ {
return $this->camelizer->camelize($str, $separator, $pascalCase); return StringHelper::camelize($str, $separator, $pascalCase);
} }
} }

View File

@@ -1,22 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Utilities\String;
class Camelizer
{
public function camelize($str, $separator = '_', $pascalCase = false)
{
$transformStr = str_replace(' ', '', ucwords(str_replace($separator, ' ', $str)));
return $pascalCase ? $transformStr : lcfirst($transformStr);
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Utilities;
class StringHelper
{
/**
* @param string $str
* @return string
*/
public static function crlfNormalize($str)
{
return str_replace(["\r\n", "\r"], "\n", $str);
}
/**
* @param string $str
* @param string $separator
* @param bool $pascalCase
* @return string
*/
public static function camelize($str, $separator = '_', $pascalCase = false)
{
$transformStr = str_replace(' ', '', ucwords(str_replace($separator, ' ', $str)));
return $pascalCase ? $transformStr : lcfirst($transformStr);
}
}

View File

@@ -10,6 +10,7 @@
*/ */
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Utilities\StringHelper;
use Alchemy\Phrasea\Vocabulary; use Alchemy\Phrasea\Vocabulary;
class caption_Field_Value implements cache_cacheableInterface class caption_Field_Value implements cache_cacheableInterface
@@ -87,15 +88,14 @@ class caption_Field_Value implements cache_cacheableInterface
$connbas = $this->databox_field->get_databox()->get_connection(); $connbas = $this->databox_field->get_databox()->get_connection();
$sql = 'SELECT record_id, value, VocabularyType, VocabularyId $sql = 'SELECT record_id, value, VocabularyType, VocabularyId FROM metadatas WHERE id = :id';
FROM metadatas WHERE id = :id';
$stmt = $connbas->prepare($sql); $stmt = $connbas->prepare($sql);
$stmt->execute([':id' => $this->id]); $stmt->execute([':id' => $this->id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor(); $stmt->closeCursor();
$this->value = $row ? $row['value'] : null; $this->value = $row ? StringHelper::crlfNormalize($row['value']) : null;
try { try {
$this->VocabularyType = $row['VocabularyType'] ? Vocabulary\Controller::get($this->app, $row['VocabularyType']) : null; $this->VocabularyType = $row['VocabularyType'] ? Vocabulary\Controller::get($this->app, $row['VocabularyType']) : null;
@@ -204,9 +204,9 @@ class caption_Field_Value implements cache_cacheableInterface
, ':meta_id' => $this->getId() , ':meta_id' => $this->getId()
]; ];
$sql_up = 'UPDATE metadatas $sql_up = 'UPDATE metadatas'
SET VocabularyType = :VocabType, VocabularyId = :VocabularyId . ' SET VocabularyType = :VocabType, VocabularyId = :VocabularyId'
WHERE id = :meta_id'; . ' WHERE id = :meta_id';
$stmt_up = $connbas->prepare($sql_up); $stmt_up = $connbas->prepare($sql_up);
$stmt_up->execute($params); $stmt_up->execute($params);
$stmt_up->closeCursor(); $stmt_up->closeCursor();
@@ -228,9 +228,9 @@ class caption_Field_Value implements cache_cacheableInterface
, ':meta_id' => $this->getId() , ':meta_id' => $this->getId()
]; ];
$sql_up = 'UPDATE metadatas $sql_up = 'UPDATE metadatas'
SET VocabularyType = :VocabType, VocabularyId = :VocabularyId . ' SET VocabularyType = :VocabType, VocabularyId = :VocabularyId'
WHERE id = :meta_id'; . ' WHERE id = :meta_id';
$stmt_up = $connbas->prepare($sql_up); $stmt_up = $connbas->prepare($sql_up);
$stmt_up->execute($params); $stmt_up->execute($params);
$stmt_up->closeCursor(); $stmt_up->closeCursor();
@@ -302,10 +302,8 @@ class caption_Field_Value implements cache_cacheableInterface
} }
} }
$sql_ins = 'INSERT INTO metadatas $sql_ins = 'INSERT INTO metadatas (id, record_id, meta_struct_id, value, VocabularyType, VocabularyId)'
(id, record_id, meta_struct_id, value, VocabularyType, VocabularyId) . ' VALUES (null, :record_id, :field, :value, :VocabType, :VocabId)';
VALUES
(null, :record_id, :field, :value, :VocabType, :VocabId)';
$params = [ $params = [
':record_id' => $record->get_record_id(), ':record_id' => $record->get_record_id(),

View File

@@ -20,12 +20,12 @@ class caption_field implements cache_cacheableInterface
protected $databox_field; protected $databox_field;
/** /**
* @var string * @var caption_Field_Value[]
*/ */
protected $values; protected $values;
/** /**
* @var record_adapter * @var \record_adapter
*/ */
protected $record; protected $record;
protected $app; protected $app;
@@ -37,7 +37,7 @@ class caption_field implements cache_cacheableInterface
* @param databox_field $databox_field * @param databox_field $databox_field
* @param record_adapter $record * @param record_adapter $record
* *
* @return $this * @return caption_field
*/ */
public function __construct(Application $app, databox_field $databox_field, \record_adapter $record) public function __construct(Application $app, databox_field $databox_field, \record_adapter $record)
{ {
@@ -52,10 +52,12 @@ class caption_field implements cache_cacheableInterface
$this->values[$row['id']] = new caption_Field_Value($this->app, $databox_field, $record, $row['id']); $this->values[$row['id']] = new caption_Field_Value($this->app, $databox_field, $record, $row['id']);
// Inconsistent, should not happen // Inconsistent, should not happen
if (! $databox_field->is_multi()) { if ( ! $databox_field->is_multi()) {
break; break;
} }
} }
return $this;
} }
protected function get_metadatas_ids() protected function get_metadatas_ids()
@@ -71,8 +73,8 @@ class caption_field implements cache_cacheableInterface
$sql = 'SELECT id FROM metadatas WHERE record_id = :record_id AND meta_struct_id = :meta_struct_id'; $sql = 'SELECT id FROM metadatas WHERE record_id = :record_id AND meta_struct_id = :meta_struct_id';
$params = [ $params = [
':record_id' => $this->record->get_record_id(), ':record_id' => $this->record->get_record_id()
':meta_struct_id' => $this->databox_field->get_id(), , ':meta_struct_id' => $this->databox_field->get_id()
]; ];
$stmt = $connbas->prepare($sql); $stmt = $connbas->prepare($sql);
@@ -118,7 +120,7 @@ class caption_field implements cache_cacheableInterface
} }
/** /**
* @return $this * @return caption_field
*/ */
public function delete() public function delete()
{ {
@@ -167,7 +169,7 @@ class caption_field implements cache_cacheableInterface
/** /**
* @param int $meta_id * @param int $meta_id
* @return array * @return \caption_Field_Value
*/ */
public function get_value($meta_id) public function get_value($meta_id)
{ {
@@ -175,8 +177,8 @@ class caption_field implements cache_cacheableInterface
} }
/** /**
* @param bool|string $custom_separator * @param String $custom_separator
* @param bool $highlight * @param Boolean $highlightTheso
* *
* @return mixed * @return mixed
*/ */
@@ -389,7 +391,7 @@ class caption_field implements cache_cacheableInterface
* @param mixed $value * @param mixed $value
* @param string $option * @param string $option
* @param int $duration * @param int $duration
* @return $this * @return caption_field
*/ */
public function set_data_to_cache($value, $option = null, $duration = 360000) public function set_data_to_cache($value, $option = null, $duration = 360000)
{ {
@@ -400,7 +402,7 @@ class caption_field implements cache_cacheableInterface
* Part of the cache_cacheableInterface * Part of the cache_cacheableInterface
* *
* @param string $option * @param string $option
* @return $this * @return caption_field
*/ */
public function delete_data_from_cache($option = null) public function delete_data_from_cache($option = null)
{ {

View File

@@ -4,7 +4,6 @@ namespace Alchemy\Tests\Phrasea\Form\Login;
use Alchemy\Phrasea\Form\Login\PhraseaRegisterForm;; use Alchemy\Phrasea\Form\Login\PhraseaRegisterForm;;
use Alchemy\Tests\Phrasea\Form\FormTestCase; use Alchemy\Tests\Phrasea\Form\FormTestCase;
use Alchemy\Phrasea\Utilities\String\Camelizer;
/** /**
* @group functional * @group functional
@@ -27,7 +26,7 @@ class PhraseaRegisterFormTest extends FormTestCase
] ]
]; ];
return new PhraseaRegisterForm(self::$DI['app'], $available, $params, new Camelizer()); return new PhraseaRegisterForm(self::$DI['app'], $available, $params);
} }
public function testFormDoesRegisterValidFields() public function testFormDoesRegisterValidFields()
@@ -63,7 +62,7 @@ class PhraseaRegisterFormTest extends FormTestCase
$expected[] = 'collections'; $expected[] = 'collections';
} }
$form = new PhraseaRegisterForm(self::$DI['app'], $available, $params, new Camelizer()); $form = new PhraseaRegisterForm(self::$DI['app'], $available, $params);
foreach (array_keys(self::$DI['app']->form($form)->createView()->vars['form']->children) as $name) { foreach (array_keys(self::$DI['app']->form($form)->createView()->vars['form']->children) as $name) {
$this->assertContains($name, $expected); $this->assertContains($name, $expected);
@@ -99,7 +98,7 @@ class PhraseaRegisterFormTest extends FormTestCase
$expected[] = 'collections'; $expected[] = 'collections';
} }
$form = new PhraseaRegisterForm(self::$DI['app'], $available, $params, new Camelizer()); $form = new PhraseaRegisterForm(self::$DI['app'], $available, $params);
foreach (array_keys(self::$DI['app']->form($form)->createView()->vars['form']->children) as $name) { foreach (array_keys(self::$DI['app']->form($form)->createView()->vars['form']->children) as $name) {
$this->assertContains($name, $expected); $this->assertContains($name, $expected);

View File

@@ -1,34 +0,0 @@
<?php
namespace Alchemy\Tests\Phrasea\Utilities\String;
use Alchemy\Phrasea\Utilities\String\Camelizer;
/**
* @group functional
* @group legacy
*/
class CamelizerTest extends \PhraseanetTestCase
{
/**
* @dataProvider provideStrings
* @covers Alchemy\Phrasea\Utilities\String\Camelizer::camelize
*/
public function testCamelize($string, $separator, $expected, $pascalize)
{
$camelizer = new Camelizer();
$result = $camelizer->camelize($string, $separator, $pascalize);
$this->assertEquals($expected, $result);
}
public function provideStrings()
{
return [
['string-test', '-', 'stringTest', false],
['string test', ' ', 'stringTest', false],
['string_test', '_', 'stringTest', false],
['string#test', '#', 'StringTest', true],
];
}
}

View File

@@ -0,0 +1,55 @@
<?php
namespace Alchemy\Tests\Phrasea\Utilities\String;
use Alchemy\Phrasea\Utilities\StringHelper;
/**
* @group unit
*/
class StringHelperTest extends \PhraseanetTestCase
{
/**
* @dataProvider provideStringsForCamelize
* @covers Alchemy\Phrasea\Utilities\StringHelper::camelize
*/
public function testCamelize($string, $separator, $expected, $pascalize)
{
$result = StringHelper::camelize($string, $separator, $pascalize);
$this->assertEquals($expected, $result);
}
public function provideStringsForCamelize()
{
return [
['string-test', '-', 'stringTest', false],
['string test', ' ', 'stringTest', false],
['string_test', '_', 'stringTest', false],
['string#test', '#', 'StringTest', true],
];
}
/**
* @dataProvider provideStringsForCrLfNormalize
* @covers Alchemy\Phrasea\Utilities\StringHelper::crlfNormalize
*/
public function testCrLfNormalize($string, $expected)
{
$result = StringHelper::crlfNormalize($string);
$this->assertEquals($expected, $result);
}
public function provideStringsForCrLfNormalize()
{
return [
["ABC\rDEF", "ABC\nDEF"],
["ABC\nDEF", "ABC\nDEF"],
["ABC\r\nDEF", "ABC\nDEF"],
["ABC\n\rDEF", "ABC\n\nDEF"],
];
}
}

View File

@@ -340,7 +340,7 @@ function newSearch(query) {
p4.Results.Selection.empty(); p4.Results.Selection.empty();
clearAnswers(); clearAnswers();
$('#searchForm input[name="qry"]').val(query); $('#SENT_query').val(query);
var histo = $('#history-queries ul'); var histo = $('#history-queries ul');
histo.prepend('<li onclick="doSpecialSearch(\'' + query.replace(/\'/g, "\\'") + '\')">' + query + '</li>'); histo.prepend('<li onclick="doSpecialSearch(\'' + query.replace(/\'/g, "\\'") + '\')">' + query + '</li>');
@@ -612,9 +612,7 @@ function getFacetsTree() {
} }
function facetCombinedSearch() { function facetCombinedSearch() {
var q = $("#EDIT_query").val(); var q = $("#EDIT_query").val();
console.debug(selectedFacetValues);
var q_facet = ""; var q_facet = "";
_.each(_.values(selectedFacetValues), function(facetValue) { _.each(_.values(selectedFacetValues), function(facetValue) {
q_facet += (q_facet ? " AND " : "") + '(' + facetValue.query + ')'; q_facet += (q_facet ? " AND " : "") + '(' + facetValue.query + ')';