From 8fd1256aa2a46be344c1bf36616e923aa4c74cbd Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 10 Dec 2013 11:01:30 +0100 Subject: [PATCH 01/17] Fix user settings precedence --- lib/classes/User/Adapter.php | 20 ++++++++++---------- tests/classes/userTest.php | 9 ++++++--- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/lib/classes/User/Adapter.php b/lib/classes/User/Adapter.php index d252a7dadd..32c0f58fef 100644 --- a/lib/classes/User/Adapter.php +++ b/lib/classes/User/Adapter.php @@ -1320,16 +1320,6 @@ class User_Adapter implements User_Interface, cache_cacheableInterface return $this; } - $sql = 'SELECT prop, value FROM usr_settings WHERE usr_id= :id'; - $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql); - $stmt->execute(array(':id' => $this->id)); - $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - foreach ($rs as $row) { - $this->_prefs[$row['prop']] = $row['value']; - } - foreach (self::$def_values as $k => $v) { if (!isset($this->_prefs[$k])) { if ($k == 'start_page_query' && $this->app['phraseanet.registry']->get('GV_defaultQuery')) { @@ -1351,6 +1341,16 @@ class User_Adapter implements User_Interface, cache_cacheableInterface ); } + $sql = 'SELECT prop, value FROM usr_settings WHERE usr_id= :id'; + $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql); + $stmt->execute(array(':id' => $this->id)); + $rs = $stmt->fetchAll(PDO::FETCH_ASSOC); + $stmt->closeCursor(); + + foreach ($rs as $row) { + $this->_prefs[$row['prop']] = $row['value']; + } + $this->preferences_loaded = true; return $this; diff --git a/tests/classes/userTest.php b/tests/classes/userTest.php index f831111205..d6d7a433e5 100644 --- a/tests/classes/userTest.php +++ b/tests/classes/userTest.php @@ -92,11 +92,14 @@ class userTest extends PhraseanetPHPUnitAbstract ); $user = $this->get_user(); + $user->setPrefs('images_per_page', 35); + + $user = new \User_Adapter($user->get_id(), self::$DI['app']); $this->assertNull($user->getPrefs('lalala')); - $this->assertSame(666, $user->getPrefs('images_size')); - $this->assertSame(42, $user->getPrefs('images_per_page')); - $this->assertSame(\User_Adapter::$def_values['editing_top_box'], $user->getPrefs('editing_top_box')); + $this->assertEquals(666, $user->getPrefs('images_size')); + $this->assertEquals(35, $user->getPrefs('images_per_page')); + $this->assertEquals(\User_Adapter::$def_values['editing_top_box'], $user->getPrefs('editing_top_box')); if (null === $data) { unset(self::$DI['app']['phraseanet.configuration']['user-settings']); From 2cb9dda244c3987fadbad456eaf974e1bc8498e9 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 10 Dec 2013 11:48:04 +0100 Subject: [PATCH 02/17] Fix #1605 : Add advanced search reset on production load. --- lib/Alchemy/Phrasea/Helper/Prod.php | 4 ++-- lib/classes/User/Adapter.php | 1 + templates/web/prod/index.html.twig | 9 +++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lib/Alchemy/Phrasea/Helper/Prod.php b/lib/Alchemy/Phrasea/Helper/Prod.php index c2af5cde9f..80e0413b11 100644 --- a/lib/Alchemy/Phrasea/Helper/Prod.php +++ b/lib/Alchemy/Phrasea/Helper/Prod.php @@ -34,6 +34,7 @@ class Prod extends Helper } $searchSet = json_decode($this->app['authentication']->getUser()->getPrefs('search'), true); + $saveSettings = $this->app['authentication']->getUser()->getPrefs('advanced_search_reload'); foreach ($this->app['authentication']->getUser()->ACL()->get_granted_sbas() as $databox) { $sbas_id = $databox->get_sbas_id(); @@ -46,8 +47,7 @@ class Prod extends Helper ); foreach ($this->app['authentication']->getUser()->ACL()->get_granted_base(array(), array($databox->get_sbas_id())) as $coll) { - $selected = (isset($searchSet['bases']) && - isset($searchSet['bases'][$sbas_id])) ? (in_array($coll->get_base_id(), $searchSet['bases'][$sbas_id])) : true; + $selected = $saveSettings ? ((isset($searchSet['bases']) && isset($searchSet['bases'][$sbas_id])) ? (in_array($coll->get_base_id(), $searchSet['bases'][$sbas_id])) : true) : true; $bases[$sbas_id]['collections'][] = array( 'selected' => $selected, diff --git a/lib/classes/User/Adapter.php b/lib/classes/User/Adapter.php index d252a7dadd..e1e0438519 100644 --- a/lib/classes/User/Adapter.php +++ b/lib/classes/User/Adapter.php @@ -82,6 +82,7 @@ class User_Adapter implements User_Interface, cache_cacheableInterface 'warning_on_delete_story' => 'true', 'client_basket_status' => '1', 'css' => '000000', + 'advanced_search_reload' => '1', 'start_page_query' => 'last', 'start_page' => 'QUERY', 'rollover_thumbnail' => 'caption', diff --git a/templates/web/prod/index.html.twig b/templates/web/prod/index.html.twig index 3ec6c17538..129a44bd80 100644 --- a/templates/web/prod/index.html.twig +++ b/templates/web/prod/index.html.twig @@ -798,6 +798,15 @@
  • {% trans 'Configuration' %}
  • +
    +
    + {% set mod = app['authentication'].getUser().getPrefs('advanced_search_reload') %} + +
    +

    {% trans 'Mode de presentation' %}

    From 7eb945f77133c1914839e39dac308dad400465a1 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 10 Dec 2013 18:56:54 +0100 Subject: [PATCH 03/17] Fix #1621 : User query per last applied template triggers an error --- lib/classes/User/Query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/classes/User/Query.php b/lib/classes/User/Query.php index ad10d3c752..940ed9deaf 100644 --- a/lib/classes/User/Query.php +++ b/lib/classes/User/Query.php @@ -323,7 +323,7 @@ class User_Query implements User_QueryInterface } if ($this->last_model) { - $sql .= ' AND usr.lastModel = "' . mysql_real_escape_string($this->last_model) . '" '; + $sql .= ' AND usr.lastModel = ' . $this->app['phraseanet.appbox']->get_connection()->quote($this->last_model) . ' '; } $sql_like = array(); From aac9138b184db4ab1885930f2c6881f9582683c4 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Wed, 11 Dec 2013 11:44:29 +0100 Subject: [PATCH 04/17] Fix division by 0 in case a thumbnail has a width or height equal to 0 --- templates/mobile/common/thumbnail.html.twig | 32 ++++++----- .../client/home_inter_pub_basket.html.twig | 8 ++- templates/web/common/thumbnail.html.twig | 57 +++++++++++-------- .../prod/actions/Download/prepare.html.twig | 14 ++++- .../web/prod/preview/basket_train.html.twig | 6 +- .../web/prod/preview/feed_train.html.twig | 8 ++- .../web/prod/preview/reg_train.html.twig | 8 ++- 7 files changed, 86 insertions(+), 47 deletions(-) diff --git a/templates/mobile/common/thumbnail.html.twig b/templates/mobile/common/thumbnail.html.twig index 537e608cef..e3854a2772 100644 --- a/templates/mobile/common/thumbnail.html.twig +++ b/templates/mobile/common/thumbnail.html.twig @@ -3,23 +3,27 @@ {% set b_height = b_h|default(b_w) %} {% set b_ratio = b_width / b_height %} - {% set i_ratio = thumbnail.get_width() / thumbnail.get_height() %} + + {% set thumbnail_height = thumbnail.get_height() > 0 ? thumbnail.get_height() : 120 %} + {% set thumbnail_width = thumbnail.get_width() > 0 ? thumbnail.get_width() : 120 %} + + {% set i_ratio = thumbnail_width / thumbnail_height %} {% if i_ratio > b_ratio%} - {% if b_width > thumbnail.get_width() %} - {% set d_width = thumbnail.get_width() %} + {% if b_width > thumbnail_width %} + {% set d_width = thumbnail_width %} {% else %} {% set d_width = b_width %} {% endif %} - {% set d_height = d_width / thumbnail.get_width() * thumbnail.get_height() %} + {% set d_height = d_width / thumbnail_width * thumbnail_height %} {% set top = (b_height - d_height) / 2 %} {% else %} - {% if b_height > thumbnail.get_height() %} - {% set d_height = thumbnail.get_height() %} + {% if b_height > thumbnail_height %} + {% set d_height = thumbnail_height %} {% else %} {% set d_height = b_height %} {% endif %} - {% set d_width = d_height * thumbnail.get_width() / thumbnail.get_height() %} + {% set d_width = d_height * thumbnail_width / thumbnail_height %} {% set top = ((b_height - d_height) / 2) %} {% endif %} @@ -37,8 +41,8 @@ {% set random = thumbnail.get_random() %}
    - - + +
    {% else %} - - + + {% endif %}
    diff --git a/templates/web/client/home_inter_pub_basket.html.twig b/templates/web/client/home_inter_pub_basket.html.twig index 225a7e7a99..dfc0985325 100644 --- a/templates/web/client/home_inter_pub_basket.html.twig +++ b/templates/web/client/home_inter_pub_basket.html.twig @@ -43,7 +43,13 @@ {% set thumbnail = record.get_thumbnail() %} {% set docType = record.get_type() %} {% set duration = "" %} - {% set ratio = thumbnail.get_width() / thumbnail.get_height() %} + + {% if thumbnail.get_height() > 0 %} + {% set ratio = thumbnail.get_width() / thumbnail.get_height() %} + {% else %} + {% set ratio = 1 %} + {% endif %} + {% set wrapper_size = image_size + 30 %} {% set types = { diff --git a/templates/web/common/thumbnail.html.twig b/templates/web/common/thumbnail.html.twig index b91a64137f..4a5f265e8e 100644 --- a/templates/web/common/thumbnail.html.twig +++ b/templates/web/common/thumbnail.html.twig @@ -18,23 +18,27 @@ {% else %} {% set b_ratio = b_width / b_height %} - {% set i_ratio = thumbnail.get_width() / thumbnail.get_height() %} + + {% set thumbnail_height = thumbnail.get_height() > 0 ? thumbnail.get_height() : 120 %} + {% set thumbnail_width = thumbnail.get_width() > 0 ? thumbnail.get_width() : 120 %} + + {% set i_ratio = thumbnail_width / thumbnail_height %} {% if i_ratio > b_ratio%} - {% if b_width > thumbnail.get_width() %} - {% set d_width = thumbnail.get_width() %} + {% if b_width > thumbnail_width %} + {% set d_width = thumbnail_width %} {% else %} {% set d_width = b_width %} {% endif %} - {% set d_height = d_width / thumbnail.get_width() * thumbnail.get_height() %} + {% set d_height = d_width / thumbnail_width * thumbnail_height %} {% set top = (b_height - d_height) / 2 %} {% else %} - {% if b_height > thumbnail.get_height() %} - {% set d_height = thumbnail.get_height() %} + {% if b_height > thumbnail_height %} + {% set d_height = thumbnail_height %} {% else %} {% set d_height = b_height %} {% endif %} - {% set d_width = d_height * thumbnail.get_width() / thumbnail.get_height() %} + {% set d_width = d_height * thumbnail_width / thumbnail_height %} {% set top = ((b_height - d_height) / 2) %} {% endif %} @@ -54,8 +58,8 @@ {% set random = thumbnail.get_random() %}
    - - + +
    -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/web/prod/preview/basket_train.html.twig b/templates/web/prod/preview/basket_train.html.twig index 5ac250418d..410e42ba34 100644 --- a/templates/web/prod/preview/basket_train.html.twig +++ b/templates/web/prod/preview/basket_train.html.twig @@ -5,7 +5,11 @@ {% set thumbnail = child.getRecord(app).get_thumbnail() %} {% if thumbnail.is_paysage() %} {% set style = 'width:65px;top:' %} - {% set top = ((66 - (65 / (thumbnail.get_width() / thumbnail.get_height()))) / 2)|round %} + {% if thumbnail.get_width() > 0 and thumbnail.get_height() > 0 %} + {% set top = ((66 - (65 / (thumbnail.get_width() / thumbnail.get_height()))) / 2)|round %} + {% else %} + {% set top = 65 %} + {% endif %} {% set style = style ~ top %} {% set style = style ~ 'px;' %} {% else %} diff --git a/templates/web/prod/preview/feed_train.html.twig b/templates/web/prod/preview/feed_train.html.twig index d9d44f0b9a..a91a2ce064 100644 --- a/templates/web/prod/preview/feed_train.html.twig +++ b/templates/web/prod/preview/feed_train.html.twig @@ -5,7 +5,11 @@ {% set thumbnail = child.get_record().get_thumbnail() %} {% if thumbnail.is_paysage() %} {% set style = 'width:65px;top:' %} - {% set top = ((66 - (65 / (thumbnail.get_width() / thumbnail.get_height()))) / 2)|round %} + {% if thumbnail.get_width() > 0 and thumbnail.get_height() > 0 %} + {% set top = ((66 - (65 / (thumbnail.get_width() / thumbnail.get_height()))) / 2)|round %} + {% else %} + {% set top = 65 %} + {% endif %} {% set style = style ~ top %} {% set style = style ~ 'px;' %} {% else %} @@ -40,4 +44,4 @@
    {% include 'prod/preview/tools.html.twig' %} -
    \ No newline at end of file +
    diff --git a/templates/web/prod/preview/reg_train.html.twig b/templates/web/prod/preview/reg_train.html.twig index 7567305393..666f0ee481 100644 --- a/templates/web/prod/preview/reg_train.html.twig +++ b/templates/web/prod/preview/reg_train.html.twig @@ -2,7 +2,11 @@ {% set regroupement = record.get_container() %} {% set thumbnail = regroupement.get_thumbnail() %} - {% set ratio = thumbnail.get_width() / thumbnail.get_height() %} + {% if thumbnail.get_height() > 0 %} + {% set ratio = thumbnail.get_width() / thumbnail.get_height() %} + {% else %} + {% set ratio = 1 %} + {% endif %} {% if thumbnail.is_paysage %} {% set style = 'width:80px;top:' %} {% set top = (8 + (80 - (80 / ratio)) / 2)|round %} @@ -59,4 +63,4 @@
    {% include 'prod/preview/tools.html.twig' %} -
    \ No newline at end of file + From f5f17549adbbe099e87a72a4c8e796744167c3b4 Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Wed, 11 Dec 2013 19:08:47 +0100 Subject: [PATCH 05/17] fix #1612 Conflicts: lib/classes/caption/Field/Value.php --- lib/classes/caption/Field/Value.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/classes/caption/Field/Value.php b/lib/classes/caption/Field/Value.php index d273654b43..ec492ee7bb 100644 --- a/lib/classes/caption/Field/Value.php +++ b/lib/classes/caption/Field/Value.php @@ -353,7 +353,7 @@ class caption_Field_Value implements cache_cacheableInterface return $value; } - $DOM_branchs = $XPATH_thesaurus->query($tbranch); + $cleanvalue = str_replace(array("", "", "'"), array("", "", "'"), $value); $fvalue = $value; From f71fb36377e6d0bff6b1d73ed32358dec46ec7aa Mon Sep 17 00:00:00 2001 From: Jean-Yves Gaulier Date: Wed, 11 Dec 2013 19:00:35 +0100 Subject: [PATCH 06/17] fix #1612 Conflicts: lib/classes/caption/Field/Value.php --- lib/classes/caption/Field/Value.php | 79 +++++++++++------------------ 1 file changed, 31 insertions(+), 48 deletions(-) diff --git a/lib/classes/caption/Field/Value.php b/lib/classes/caption/Field/Value.php index ec492ee7bb..e15826a05d 100644 --- a/lib/classes/caption/Field/Value.php +++ b/lib/classes/caption/Field/Value.php @@ -353,72 +353,55 @@ class caption_Field_Value implements cache_cacheableInterface return $value; } + // ---------------- new code ---------------------- $cleanvalue = str_replace(array("", "", "'"), array("", "", "'"), $value); - $fvalue = $value; - - $cleanvalue = str_replace(array("", "", "'"), array("", "", "'"), $fvalue); - list($term_noacc, $context_noacc) = $this->splitTermAndContext($cleanvalue); $term_noacc = $this->app['unicode']->remove_indexer_chars($term_noacc); $context_noacc = $this->app['unicode']->remove_indexer_chars($context_noacc); + + // find all synonyms in all related branches + $q = "(" . $tbranch . ")//sy[@w='" . $term_noacc . "'"; if ($context_noacc) { - $q = "//sy[@w='" . $term_noacc . "' and @k='" . $context_noacc . "']"; + $q .= " and @k='" . $context_noacc . "']"; } else { - $q = "//sy[@w='" . $term_noacc . "' and not(@k)]"; + $q .= " and not(@k)]"; } - $qjs = $link = ""; + $q .= "/../sy"; - // loop on each linked branch for field - foreach ($DOM_branchs as $DOM_branch) { - $nodes = $XPATH_thesaurus->cache_query($q, $DOM_branch); - $lngfound = false; - foreach ($nodes as $node) { - if ($node->getAttribute("lng") == $this->app['locale.I18n']) { - // le terme est dans la bonne langue, on le rend cliquable - list($term, $context) = $this->splitTermAndContext($fvalue); - $term = str_replace(array("", ""), array("", ""), $term); - $context = str_replace(array("", ""), array("", ""), $context); - $qjs = $term; - if ($context) { - $qjs .= " [" . $context . "]"; - } - $link = $fvalue; + $nodes = $XPATH_thesaurus->query($q); - $lngfound = true; - break; - } - - $synonyms = $XPATH_thesaurus->query("sy[@lng='" . $this->app['locale.I18n'] . "']", $node->parentNode); - foreach ($synonyms as $synonym) { - $k = $synonym->getAttribute("k"); - if ($synonym->getAttribute("w") != $term_noacc || $k != $context_noacc) { - $link = $qjs = $synonym->getAttribute("v"); - $lngfound = true; - break; - } - } - - } - if (! $lngfound) { - list($term, $context) = $this->splitTermAndContext($fvalue); - $term = str_replace(array("", ""), array("", ""), $term); - $context = str_replace(array("", ""), array("", ""), $context); - $qjs = $term; - if ($context) { - $qjs .= " [" . $context . "]"; - } - $link = $fvalue; + // loop on every sy found + $bestnode = null; + $bestnote = 0; + foreach ($nodes as $node) { + $note = 0; + $note += ($node->getAttribute("lng") == $this->app['locale.I18n']) ? 4 : 0; + $note += ($node->getAttribute("w") == $term_noacc) ? 2 : 0; + if($context_noacc != "") + $note += ($node->getAttribute("k") == $context_noacc) ? 1 : 0; + if($note > $bestnote) + { + $bestnote = $note; + $bestnode = $node; } } + if($bestnode) + { + list($term, $context) = $this->splitTermAndContext($value); + $term = str_replace(array("", ""), array("", ""), $term); + $context = str_replace(array("", ""), array("", ""), $context); + $qjs = $term; + if ($context) { + $qjs .= " [" . $context . "]"; + } - if ($qjs) { $value = "get_sbas_id() . "','" . str_replace("'", "\'", $qjs) . "', '" . str_replace("'", "\'", $this->databox_field->get_name()) . "');return(false);\">" - . $link + . $bestnode->getAttribute('v') . ""; } From 2662ead699323fcecfe8361cf74704adaca57105 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Fri, 6 Dec 2013 14:29:43 +0100 Subject: [PATCH 07/17] Fix #1607 Reoder collections is not working Conflicts: lib/classes/collection.php --- lib/Alchemy/Phrasea/Core/Version.php | 2 +- lib/classes/collection.php | 20 ++++++++++++++----- .../patch/{381alpha1a.php => 383alpha3a.php} | 4 ++-- .../web/admin/collection/reorder.html.twig | 4 +++- 4 files changed, 21 insertions(+), 9 deletions(-) rename lib/classes/patch/{381alpha1a.php => 383alpha3a.php} (95%) diff --git a/lib/Alchemy/Phrasea/Core/Version.php b/lib/Alchemy/Phrasea/Core/Version.php index 0de30582bb..c8e1841294 100644 --- a/lib/Alchemy/Phrasea/Core/Version.php +++ b/lib/Alchemy/Phrasea/Core/Version.php @@ -18,7 +18,7 @@ namespace Alchemy\Phrasea\Core; */ class Version { - protected static $number = '3.8.3-alpha.2'; + protected static $number = '3.8.3-alpha.3'; protected static $name = 'Diplodocus'; public static function getNumber() diff --git a/lib/classes/collection.php b/lib/classes/collection.php index 8e5dacc3c7..4fa8e865fc 100644 --- a/lib/classes/collection.php +++ b/lib/classes/collection.php @@ -565,6 +565,12 @@ class collection implements cache_cacheableInterface '; + $sql = "SELECT GREATEST(0, MAX(ord)) + 1 AS ord FROM bas WHERE sbas_id = :sbas_id"; + $stmt = $conn->prepare($sql); + $stmt->execute(array(':sbas_id' => $sbas_id)); + $ord = $stmt->fetch(\PDO::FETCH_ASSOC); + $stmt->closeCursor(); + $sql = "INSERT INTO coll (coll_id, asciiname, prefs, logo) VALUES (null, :name, :prefs, '')"; @@ -579,11 +585,15 @@ class collection implements cache_cacheableInterface $new_id = (int) $connbas->lastInsertId(); - $sql = "INSERT INTO bas (base_id, active, server_coll_id, sbas_id, aliases) + $sql = "INSERT INTO bas (base_id, active, ord, server_coll_id, sbas_id, aliases) VALUES - (null, 1, :server_coll_id, :sbas_id, '')"; + (null, 1, :ord, :server_coll_id, :sbas_id, '')"; $stmt = $conn->prepare($sql); - $stmt->execute(array(':server_coll_id' => $new_id, ':sbas_id' => $sbas_id)); + $stmt->execute(array( + ':server_coll_id' => $new_id, + ':sbas_id' => $sbas_id, + ':ord' => $ord['ord'] ?: 1, + )); $stmt->closeCursor(); $new_bas = $conn->lastInsertId(); @@ -638,7 +648,7 @@ class collection implements cache_cacheableInterface VALUES (null, 1, :server_coll_id, :sbas_id, '')"; $stmt = $databox->get_appbox()->get_connection()->prepare($sql); - $stmt->execute(array(':server_coll_id' => $coll_id, ':sbas_id' => $sbas_id)); + $stmt->execute(array(':server_coll_id' => $coll_id, ':sbas_id' => $databox->get_sbas_id())); $stmt->closeCursor(); $new_bas = $databox->get_appbox()->get_connection()->lastInsertId(); @@ -646,7 +656,7 @@ class collection implements cache_cacheableInterface $databox->delete_data_from_cache(databox::CACHE_COLLECTIONS); - cache_databox::update($app, $sbas_id, 'structure'); + cache_databox::update($app, $databox->get_sbas_id(), 'structure'); phrasea::reset_baseDatas($databox->get_appbox()); diff --git a/lib/classes/patch/381alpha1a.php b/lib/classes/patch/383alpha3a.php similarity index 95% rename from lib/classes/patch/381alpha1a.php rename to lib/classes/patch/383alpha3a.php index c8919b9fc3..7693cc8936 100644 --- a/lib/classes/patch/381alpha1a.php +++ b/lib/classes/patch/383alpha3a.php @@ -11,10 +11,10 @@ use Alchemy\Phrasea\Application; -class patch_381alpha1a implements patchInterface +class patch_383alpha3a implements patchInterface { /** @var string */ - private $release = '3.8.1-alpha.1'; + private $release = '3.8.3-alpha.3'; /** @var array */ private $concern = array(base::APPLICATION_BOX); diff --git a/templates/web/admin/collection/reorder.html.twig b/templates/web/admin/collection/reorder.html.twig index fefbf8401c..f1fd740618 100644 --- a/templates/web/admin/collection/reorder.html.twig +++ b/templates/web/admin/collection/reorder.html.twig @@ -2,6 +2,8 @@

    {% trans 'Reorder collections' %}

    +
    +
    @@ -87,7 +89,7 @@ var html = _.template($("#alert_"+ (datas.success ? "success" : "error") +"_tpl").html(), { content:datas.msg }); - $('#table-order').insertBefore(html); + $('#notification').html(html); }, complete : function() { $this.attr('disabled', false); From 060d6d9fdba98b91eb5de35441ffd00640bcb1c9 Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Mon, 16 Dec 2013 14:10:03 +0100 Subject: [PATCH 08/17] Fix #1623 Can not display empty admin fields list --- www/scripts/apps/admin/fields/views/edit.js | 8 ++++++-- www/scripts/apps/admin/fields/views/list.js | 2 +- www/scripts/apps/admin/fields/views/save.js | 15 +++++++++++++-- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/www/scripts/apps/admin/fields/views/edit.js b/www/scripts/apps/admin/fields/views/edit.js index 2d9f475864..20af5304d9 100644 --- a/www/scripts/apps/admin/fields/views/edit.js +++ b/www/scripts/apps/admin/fields/views/edit.js @@ -189,12 +189,16 @@ define([ // get previous index if exists else next index - 1 as item is being deleted var index = previousIndex ? previousIndex : (nextIndex ? nextIndex - 1 : -1); - modalView.render(); modalView.on("modal:confirm", function () { AdminFieldApp.fieldsToDelete.push(self.model); AdminFieldApp.fieldListView.collection.remove(self.model); - self._selectModelView(index); + // last item is deleted + if (index < 0) { + self.remove(); + } else { + self._selectModelView(index); + } // Enable state button, models is out of sync AdminFieldApp.saveView.updateStateButton(false); }); diff --git a/www/scripts/apps/admin/fields/views/list.js b/www/scripts/apps/admin/fields/views/list.js index 44fc23ea1b..60f011151b 100644 --- a/www/scripts/apps/admin/fields/views/list.js +++ b/www/scripts/apps/admin/fields/views/list.js @@ -28,7 +28,7 @@ define([ this.itemViews = []; // force base 1 indexed - if (this.collection.first().get("sorter") === 0) { + if (this.collection.length > 0 && this.collection.first().get("sorter") === 0) { this.collection.each(function (model) { model.set({'sorter': model.get("sorter") + 1}, {silent: true}); }); diff --git a/www/scripts/apps/admin/fields/views/save.js b/www/scripts/apps/admin/fields/views/save.js index 0f3385bbd6..f03215fb2d 100644 --- a/www/scripts/apps/admin/fields/views/save.js +++ b/www/scripts/apps/admin/fields/views/save.js @@ -85,14 +85,25 @@ define([ return this; }, updateStateButton: function (disable) { - var toDisable = disable || !this._isModelDesync(); + var toDisable = !this._isModelDesync(); + if ("undefined" !== typeof disable) { + toDisable = disable; + } + this._disableSaveButton(toDisable); }, // check whether model has changed or not _isModelDesync: function () { - return "undefined" !== typeof AdminFieldApp.fieldsCollection.find(function (model) { + var fieldToDelete = false; + var fieldToUpdate = false; + + fieldToUpdate = "undefined" !== typeof AdminFieldApp.fieldsCollection.find(function (model) { return !_.isEmpty(model.previousAttributes()); }); + + fieldToDelete = AdminFieldApp.fieldsToDelete.length > 0; + + return fieldToUpdate || fieldToDelete; }, // create a transparent overlay on top of the application _overlay: function (showOrHide) { From 3e574207e2b0e4278dac5fac10918f271750e4ea Mon Sep 17 00:00:00 2001 From: Nicolas Le Goff Date: Mon, 16 Dec 2013 14:35:38 +0100 Subject: [PATCH 09/17] Add tests --- www/scripts/tests/specs/admin/fields.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/www/scripts/tests/specs/admin/fields.js b/www/scripts/tests/specs/admin/fields.js index 129c527881..906dc7fe5b 100644 --- a/www/scripts/tests/specs/admin/fields.js +++ b/www/scripts/tests/specs/admin/fields.js @@ -113,6 +113,24 @@ define([ }); }); + describe("Empty List Item Views", function () { + beforeEach(function () { + this.collection = new FieldCollection([], { + "sbas_id": sbasId + }); + + this.view = new ListItemView({ + collection: this.collection, + el: AdminFieldApp.$leftBlock + }); + }); + + it("should include list items for all models in collection", function () { + this.view.render(); + this.view.$el.find("li").should.have.length(0); + }); + }); + describe("List Item Views", function () { beforeEach(function () { this.collection = new FieldCollection([ @@ -285,6 +303,11 @@ define([ it("should render as a DIV element", function () { this.view.render().el.nodeName.should.equal("DIV"); }); + + it("should tell that model is desync if one model has been deleted", function() { + AdminFieldApp.fieldsToDelete = [{"id": 1, "sbas-id": sbasId, "name": "Categorie", "tag": "XMP:Categorie"}]; + assert.isTrue(this.view._isModelDesync()); + }); }); }); From c0c640aaee5e3ec38f251e4c6b107354e47e0b32 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 17 Dec 2013 11:40:01 +0100 Subject: [PATCH 10/17] Fix #1626 : FTP test displays empty message --- templates/web/common/dialog_export.html.twig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/web/common/dialog_export.html.twig b/templates/web/common/dialog_export.html.twig index 15a9223542..c508595447 100644 --- a/templates/web/common/dialog_export.html.twig +++ b/templates/web/common/dialog_export.html.twig @@ -777,10 +777,10 @@ var options = { size : 'Alert', closeButton: true, - title : '{% trans "Warning !" %}' + title : data.success ? '{% trans "Success !" %}' : '{% trans "Warning !" %}' }; - p4.Dialog.Create(options, 2).setContent(data); + p4.Dialog.Create(options, 2).setContent(data.message); $this.removeAttr('disabled'); From aa643930c11d0b08a43cf1925a5f22514d5f5a86 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 17 Dec 2013 15:56:27 +0100 Subject: [PATCH 11/17] Fix #1625 : Append javascript autocompleter to edit dialog box --- www/skins/prod/jquery.edit.js | 1 + 1 file changed, 1 insertion(+) diff --git a/www/skins/prod/jquery.edit.js b/www/skins/prod/jquery.edit.js index ca285f134d..840c83c43c 100644 --- a/www/skins/prod/jquery.edit.js +++ b/www/skins/prod/jquery.edit.js @@ -201,6 +201,7 @@ function editField(evt, meta_struct_id) { $('#idEditZTextArea, #EditTextMultiValued').autocomplete({ minLength: 2, + appendTo: "#idEditZone", source: function (request, response) { $.ajax({ url: '../prod/records/edit/vocabulary/' + vocabType + '/', From 413e9ae5e69a3e5c135d757593e43a894d2118c7 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 17 Dec 2013 18:01:56 +0100 Subject: [PATCH 12/17] Fix #1629 : Update to PHP-FFmpeg 0.4.4 --- composer.lock | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.lock b/composer.lock index 5ea157f013..8ebcb543fd 100644 --- a/composer.lock +++ b/composer.lock @@ -1887,16 +1887,16 @@ }, { "name": "php-ffmpeg/php-ffmpeg", - "version": "0.4.3", + "version": "0.4.4", "source": { "type": "git", "url": "https://github.com/alchemy-fr/PHP-FFmpeg.git", - "reference": "554cec2bc7b76e222aeef083205ed3bd57327975" + "reference": "8dfaf1815802614352bbd10eac7299a100bf9757" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alchemy-fr/PHP-FFmpeg/zipball/554cec2bc7b76e222aeef083205ed3bd57327975", - "reference": "554cec2bc7b76e222aeef083205ed3bd57327975", + "url": "https://api.github.com/repos/alchemy-fr/PHP-FFmpeg/zipball/8dfaf1815802614352bbd10eac7299a100bf9757", + "reference": "8dfaf1815802614352bbd10eac7299a100bf9757", "shasum": "" }, "require": { @@ -1952,7 +1952,7 @@ "video", "video processing" ], - "time": "2013-12-02 13:48:20" + "time": "2013-12-17 16:54:46" }, { "name": "php-mp4box/php-mp4box", From f0d632073bdad7da90b15592e2a9346a30aee966 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 17 Dec 2013 11:29:30 +0100 Subject: [PATCH 13/17] Fix #1622 : Sanitize captions display --- lib/Alchemy/Phrasea/Application.php | 16 +++++++++++++++- .../SearchEngine/Phrasea/PhraseaEngine.php | 2 +- .../SphinxSearch/SphinxSearchEngine.php | 4 ++-- lib/classes/caption/Field/Value.php | 19 ++++--------------- .../common/caption_templates/answer.html.twig | 2 +- .../basket_element.html.twig | 4 ++-- .../internal_publi.html.twig | 4 ++-- .../caption_templates/lazaret.html.twig | 4 ++-- .../caption_templates/overview.html.twig | 4 ++-- .../caption_templates/preview.html.twig | 4 ++-- .../SearchEngine/SearchEngineAbstractTest.php | 2 +- 11 files changed, 34 insertions(+), 31 deletions(-) diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 3f63f12ecd..e7ad5c7c15 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -611,10 +611,24 @@ class Application extends SilexApplication $twig->addFilter('base_from_coll', new \Twig_Filter_Function('phrasea::baseFromColl')); $twig->addFilter('AppName', new \Twig_Filter_Function('Alchemy\Phrasea\Controller\Admin\ConnectedUsers::appName')); $twig->addFilter(new \Twig_SimpleFilter('escapeSimpleQuote', function ($value) { - $ret = str_replace("'", "\'", $value); + $ret = str_replace("'", "\\'", $value); return $ret; })); + $twig->addFilter(new \Twig_SimpleFilter('thesaurus', function (\Twig_Environment $twig, $value) { + if (!$value instanceof \ThesaurusValue) { + return twig_escape_filter($twig, str_replace(array('[[em]]', '[[/em]]'), array('', ''), $value)); + } + + return "getField()->get_databox()->get_sbas_id() . "','" + . str_replace("'", "\\'", $value->getQuery()) + . "', '" + . str_replace("'", "\\'", $value->getField()->get_name()) + . "');return(false);\">" + . twig_escape_filter($twig, str_replace(array('[[em]]', '[[/em]]'), array('', ''), $value->getValue())) + . ""; + }, array('needs_environment' => true, 'is_safe' => array('html')))); + $twig->addFilter(new \Twig_SimpleFilter('escapeDoubleQuote', function ($value) { return str_replace('"', '\"', $value); })); diff --git a/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php index c846f67c35..9847d1da4b 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php @@ -641,7 +641,7 @@ class PhraseaEngine implements SearchEngineInterface if ($sxe && $sxe->description && $sxe->description->$name) { $val = array(); foreach ($sxe->description->$name as $value) { - $val[] = str_replace(array('[[em]]', '[[/em]]'), array('', ''), (string) $value); + $val[] = (string) $value; } $separator = $field['separator'] ? $field['separator'][0] : ''; $val = implode(' ' . $separator . ' ', $val); diff --git a/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php index 5bbaa21f23..205c4bf792 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php @@ -552,8 +552,8 @@ class SphinxSearchEngine implements SearchEngineInterface } $opts = array( - 'before_match' => "", - 'after_match' => "", + 'before_match' => "[[em]]", + 'after_match' => "[[/em]]", ); $fields_to_send = array(); diff --git a/lib/classes/caption/Field/Value.php b/lib/classes/caption/Field/Value.php index e15826a05d..33d338c476 100644 --- a/lib/classes/caption/Field/Value.php +++ b/lib/classes/caption/Field/Value.php @@ -354,7 +354,7 @@ class caption_Field_Value implements cache_cacheableInterface } // ---------------- new code ---------------------- - $cleanvalue = str_replace(array("", "", "'"), array("", "", "'"), $value); + $cleanvalue = str_replace(array("[[em]]", "[[/em]]", "'"), array("", "", "'"), $value); list($term_noacc, $context_noacc) = $this->splitTermAndContext($cleanvalue); $term_noacc = $this->app['unicode']->remove_indexer_chars($term_noacc); @@ -388,21 +388,10 @@ class caption_Field_Value implements cache_cacheableInterface } if($bestnode) { - list($term, $context) = $this->splitTermAndContext($value); - $term = str_replace(array("", ""), array("", ""), $term); - $context = str_replace(array("", ""), array("", ""), $context); - $qjs = $term; - if ($context) { - $qjs .= " [" . $context . "]"; - } + list($term, $context) = $this->splitTermAndContext(str_replace(array("[[em]]", "[[/em]]"), array("", ""), $value)); + $qjs = $term . ($context ? '['.$context.']' : ''); - $value = "get_sbas_id() . "','" - . str_replace("'", "\'", $qjs) - . "', '" - . str_replace("'", "\'", $this->databox_field->get_name()) - . "');return(false);\">" - . $bestnode->getAttribute('v') - . ""; + $value = new ThesaurusValue($bestnode->getAttribute('v'), $this->databox_field, $qjs); } return $value; diff --git a/templates/web/common/caption_templates/answer.html.twig b/templates/web/common/caption_templates/answer.html.twig index 8d6875320a..ebb65f00bf 100644 --- a/templates/web/common/caption_templates/answer.html.twig +++ b/templates/web/common/caption_templates/answer.html.twig @@ -1,6 +1,6 @@ {% macro format_caption(record, highlight, searchEngine, includeBusiness) %} {% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %} -
    {{ value.label }} : {{value.value|raw}}
    +
    {{ value.label }} : {{ value.value | thesaurus }}
    {% endfor %} {% if app['authentication'].getUser().getPrefs('technical_display') == 'group' %}
    diff --git a/templates/web/common/caption_templates/basket_element.html.twig b/templates/web/common/caption_templates/basket_element.html.twig index 58de726519..4896301eb8 100644 --- a/templates/web/common/caption_templates/basket_element.html.twig +++ b/templates/web/common/caption_templates/basket_element.html.twig @@ -1,5 +1,5 @@ {% macro format_caption(record, highlight, searchEngine, includeBusiness) %} {% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %} -
    {{ value.label }} : {{value.value|raw}}
    +
    {{ value.label }} : {{ value.value | thesaurus }}
    {% endfor %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/templates/web/common/caption_templates/internal_publi.html.twig b/templates/web/common/caption_templates/internal_publi.html.twig index e08a58bfc5..ebb65f00bf 100644 --- a/templates/web/common/caption_templates/internal_publi.html.twig +++ b/templates/web/common/caption_templates/internal_publi.html.twig @@ -1,9 +1,9 @@ {% macro format_caption(record, highlight, searchEngine, includeBusiness) %} {% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %} -
    {{ value.label }} : {{value.value|raw}}
    +
    {{ value.label }} : {{ value.value | thesaurus }}
    {% endfor %} {% if app['authentication'].getUser().getPrefs('technical_display') == 'group' %}
    {% include 'common/technical_datas.html.twig' %} {% endif %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/templates/web/common/caption_templates/lazaret.html.twig b/templates/web/common/caption_templates/lazaret.html.twig index e08a58bfc5..ebb65f00bf 100644 --- a/templates/web/common/caption_templates/lazaret.html.twig +++ b/templates/web/common/caption_templates/lazaret.html.twig @@ -1,9 +1,9 @@ {% macro format_caption(record, highlight, searchEngine, includeBusiness) %} {% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %} -
    {{ value.label }} : {{value.value|raw}}
    +
    {{ value.label }} : {{ value.value | thesaurus }}
    {% endfor %} {% if app['authentication'].getUser().getPrefs('technical_display') == 'group' %}
    {% include 'common/technical_datas.html.twig' %} {% endif %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/templates/web/common/caption_templates/overview.html.twig b/templates/web/common/caption_templates/overview.html.twig index 4298a51bca..78e01030f8 100644 --- a/templates/web/common/caption_templates/overview.html.twig +++ b/templates/web/common/caption_templates/overview.html.twig @@ -1,5 +1,5 @@ {% macro format_caption(record, highlight, searchEngine, includeBusiness) %} {% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %} -
    {{ value.label }} : {{value.value|raw}}
    +
    {{ value.label }} : {{ value.value }}
    {% endfor %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/templates/web/common/caption_templates/preview.html.twig b/templates/web/common/caption_templates/preview.html.twig index 58de726519..4896301eb8 100644 --- a/templates/web/common/caption_templates/preview.html.twig +++ b/templates/web/common/caption_templates/preview.html.twig @@ -1,5 +1,5 @@ {% macro format_caption(record, highlight, searchEngine, includeBusiness) %} {% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %} -
    {{ value.label }} : {{value.value|raw}}
    +
    {{ value.label }} : {{ value.value | thesaurus }}
    {% endfor %} -{% endmacro %} \ No newline at end of file +{% endmacro %} diff --git a/tests/Alchemy/Tests/Phrasea/SearchEngine/SearchEngineAbstractTest.php b/tests/Alchemy/Tests/Phrasea/SearchEngine/SearchEngineAbstractTest.php index 5f2d48fdcf..7a83858c22 100644 --- a/tests/Alchemy/Tests/Phrasea/SearchEngine/SearchEngineAbstractTest.php +++ b/tests/Alchemy/Tests/Phrasea/SearchEngine/SearchEngineAbstractTest.php @@ -754,7 +754,7 @@ abstract class SearchEngineAbstractTest extends \PhraseanetPHPUnitAuthenticatedA $found = false; foreach (self::$searchEngine->excerpt($query_string, $fields, $foundRecord) as $field) { - if (strpos($field, '') !== false && strpos($field, '') !== false) { + if (strpos($field, '[[em]]') !== false && strpos($field, '[[/em]]') !== false) { $found = true; break; } From 1cc388565645d25af9410124f3ef8e1aaebe248d Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 17 Dec 2013 18:22:03 +0100 Subject: [PATCH 14/17] Fix #1624 : Some report locales might be broken --- lib/classes/module/report/filter.php | 35 ++++++----- .../ajax_dashboard_content_child.html.twig | 63 ++++++++++++++----- .../web/report/dashboard_macro.html.twig | 22 +++---- 3 files changed, 78 insertions(+), 42 deletions(-) diff --git a/lib/classes/module/report/filter.php b/lib/classes/module/report/filter.php index 9804458ec6..1d1bf44faa 100644 --- a/lib/classes/module/report/filter.php +++ b/lib/classes/module/report/filter.php @@ -17,21 +17,6 @@ class module_report_filter private $posting_filter = array(); private $cor_query = array(); private $active_column = array(); - private $trans = array( - 'user' => 'phraseanet::utilisateurs', - 'ddate' => 'report:: date', - 'ip' => 'report:: IP', - 'appli' => 'report:: modules', - 'fonction' => 'report::fonction', - 'activite' => 'report::activite', - 'pays' => 'report::pays', - 'societe' => 'report::societe', - 'record_id' => 'report:: record id', - 'final' => 'phraseanet:: sous definition', - 'coll_id' => 'report:: collections', - 'comment' => 'report:: commentaire', - 'search' => 'report:: question', - ); public function __construct(Application $app, $current_filter, $correspondance) { @@ -69,6 +54,22 @@ class module_report_filter public function getPostingFilter() { + $trans = array( + 'user' => _('phraseanet::utilisateurs'), + 'ddate' => _('report:: date'), + 'ip' => _('report:: IP'), + 'appli' => _('report:: modules'), + 'fonction' => _('report::fonction'), + 'activite' => _('report::activite'), + 'pays' => _('report::pays'), + 'societe' => _('report::societe'), + 'record_id' => _('report:: record id'), + 'final' => _('phraseanet:: sous definition'), + 'coll_id' => _('report:: collections'), + 'comment' => _('report:: commentaire'), + 'search' => _('report:: question'), + ); + if (sizeof($this->tab_filter) > 0) { foreach ($this->tab_filter as $key => $filter) { if (empty($filter['v'])) @@ -76,8 +77,8 @@ class module_report_filter else $value = $filter['v']; - if (array_key_exists($filter['f'], $this->trans)) - $field = _($this->trans[$filter['f']]); + if (array_key_exists($filter['f'], $trans)) + $field = _($trans[$filter['f']]); else $field = $filter['f']; diff --git a/templates/web/report/ajax_dashboard_content_child.html.twig b/templates/web/report/ajax_dashboard_content_child.html.twig index cd6ec340ba..29e49596ba 100644 --- a/templates/web/report/ajax_dashboard_content_child.html.twig +++ b/templates/web/report/ajax_dashboard_content_child.html.twig @@ -9,46 +9,81 @@ {% if "activity"|key_exists(item) %} - {{ dash.table_activity("mytablehour", "report:: activite par heure", "report:: Connexion", item.activity)}} + {% set title1 = "report:: activite par heure" | trans %} + {% set title2 = "report:: Connexion" | trans %} + {{ dash.table_activity("mytablehour", title1, title2, item.activity)}} {% endif %} {% if "activity_day"|key_exists(item) %} - {{dash.table_activity("mytabledaytotal", "report:: activite par jour" , "report:: Connexion", item.activity_day)}} + {% set title1 = "report:: activite par jour" | trans %} + {% set title2 = "report:: Connexion" | trans %} + {{dash.table_activity("mytabledaytotal", title1, title2, item.activity_day)}} {%endif%} {% if "activity_added"|key_exists(item) %} - {{ dash.table_activity("mytableadded", "report:: activite document ajoute" , "", item.activity_added)}} + {% set title1 = "report:: activite document ajoute" | trans %} + {{ dash.table_activity("mytableadded", title1 , "", item.activity_added)}} {%endif %} {% if "activity_edited"|key_exists(item) %} - {{ dash.table_activity("mytableedited", "report:: activite document edite" , "", item.activity_edited)}} + {% set title1 = "report:: activite document edite" | trans %} + {{ dash.table_activity("mytableedited", title1 , "", item.activity_edited)}} {% endif %} {% if "nb_conn"|key_exists(item) and "nb_dl"|key_exists(item)%} - {{ dash.connexion_download("report:: Cumul telechargements & connexions", "report:: telechargements", "report::Connexion", item.nb_dl, item.nb_conn, dashboard.getTitleDate('dmin'),dashboard.getTitleDate('dmax'))}} + {% set title1 = "report:: Cumul telechargements & connexions" | trans %} + {% set title2 = "report:: telechargements" | trans %} + {% set title3 = "report::Connexion" | trans %} + {{ dash.connexion_download(title1, title2, title3, item.nb_dl, item.nb_conn, dashboard.getTitleDate('dmin'),dashboard.getTitleDate('dmax'))}} {% endif %} {% if "top_ten_user_doc"|key_exists(item)%} - {{ dash.table('report:: Utilisateurs les plus actifs' , 'report:: utilisateurs' , 'report:: telechargements document', item.top_ten_user_doc, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} + {% set title1 = "report:: Utilisateurs les plus actifs" | trans %} + {% set title2 = "report:: utilisateurs" | trans %} + {% set title3 = "report:: telechargements document" | trans %} + {{ dash.table(title1 , title2, title3, item.top_ten_user_doc, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} {% endif %} {% if "top_ten_user_prev"|key_exists(item) %} - {{ dash.table('report:: Utilisateurs les plus actifs' , 'report:: utilisateurs' , 'report:: telechargements preview', item.top_ten_user_prev, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} + {% set title1 = "report:: Utilisateurs les plus actifs" | trans %} + {% set title2 = "report:: utilisateurs" | trans %} + {% set title3 = "report:: telechargements preview" | trans %} + {{ dash.table(title1 , title2, title3, item.top_ten_user_prev, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} {%endif %} {% if "top_ten_user_poiddoc"|key_exists(item) %} - {{ dash.table('report:: Utilisateurs les plus actifs' , 'report:: utilisateurs' , 'report:: poids document', item.top_ten_user_poiddoc, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "true", "false") }} + {% set title1 = "report:: Utilisateurs les plus actifs" | trans %} + {% set title2 = "report:: utilisateurs" | trans %} + {% set title3 = "report:: poids document" | trans %} + {{ dash.table(title1 , title2, title3, item.top_ten_user_poiddoc, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "true", "false") }} {%endif %} {% if "top_ten_user_poidprev"|key_exists(item) %} - {{ dash.table('report:: Utilisateurs les plus actifs' , 'report:: utilisateurs' , 'report:: poids preview', item.top_ten_user_poidprev, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "true", "false") }} + {% set title1 = "report:: Utilisateurs les plus actifs" | trans %} + {% set title2 = "report:: utilisateurs" | trans %} + {% set title3 = "report:: poids preview" | trans %} + {{ dash.table(title1, title2, title3, item.top_ten_user_poidprev, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "true", "false") }} {%endif %} {% if "top_dl_doc"|key_exists(item) %} - {{ dash.table('report:: documents les plus telecharges' , 'report:: document' , 'report:: telechargements', item.top_dl_doc, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "true") }} + {% set title1 = "report:: documents les plus telecharges" | trans %} + {% set title2 = "report:: document" | trans %} + {% set title3 = "report:: telechargements" | trans %} + {{ dash.table(title1, title2, title3, item.top_dl_doc, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "true") }} {%endif %} {% if "top_dl_preview"|key_exists(item) %} - {{ dash.table('report:: preview les plus telecharges' , 'report:: preview' , 'report:: telechargements', item.top_dl_preview, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "true") }} + {% set title1 = "report:: preview les plus telecharges" | trans %} + {% set title2 = "report:: preview" | trans %} + {% set title3 = "report:: telechargements" | trans %} + {{ dash.table(title1, title2, title3, item.top_dl_preview, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "true") }} {%endif %} {% if "ask"|key_exists(item) %} - {{ dash.table('report:: Les questions les plus posees' , 'report:: utilisateurs' , 'report:: question', item.ask, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} + {% set title1 = "report:: Les questions les plus posees" | trans %} + {% set title2 = "report:: utilisateurs" | trans %} + {% set title3 = "report:: question" | trans %} + {{ dash.table(title1, title2, title3, item.ask, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} {%endif %} {% if "top_ten_question"|key_exists(item) %} - {{dash.top_ten_question(app['phraseanet.registry'].get('GV_homeTitle'), "report:: question", "report:: poids preview" , item.top_ten_question,dashboard.getTitleDate('dmin') , dashboard.getTitleDate('dmax')) }} + {% set title1 = "report:: question" | trans %} + {% set title2 = "report:: poids preview" | trans %} + {{dash.top_ten_question(app['phraseanet.registry'].get('GV_homeTitle'), title1, title2, item.top_ten_question,dashboard.getTitleDate('dmin') , dashboard.getTitleDate('dmax')) }} {%endif %} {% if "top_ten_site"|key_exists(item) %} - {{ dash.table('report:: site d\'ou les photo sont les plus consultees' , 'report:: site' , 'report:: nombre de vue', item.top_ten_site, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} + {% set title1 = "report:: site d\'ou les photo sont les plus consultees" | trans %} + {% set title2 = "report:: site" | trans %} + {% set title3 = "report:: nombre de vue" | trans %} + {{ dash.table(title1, title2, title3, item.top_ten_site, dashboard.getTitleDate('dmin'), dashboard.getTitleDate('dmax'), "false", "false") }} {%endif %} {%endblock currentDashboard %} diff --git a/templates/web/report/dashboard_macro.html.twig b/templates/web/report/dashboard_macro.html.twig index 619fe128fd..b32a8bf2c2 100644 --- a/templates/web/report/dashboard_macro.html.twig +++ b/templates/web/report/dashboard_macro.html.twig @@ -2,11 +2,11 @@ {% macro table(title, titleLeft, titleRight, object, dmin, dmax, unite, sbasid) %} {% if object|length > 0 %} - + - - + + @@ -41,8 +41,8 @@ - - + + @@ -64,17 +64,17 @@ {% macro connexion_download(title, title_left, title_right, itemco, itemdl, dmin, dmax ) %}
    {% trans title %}{{ title }}
    {% trans titleLeft %}{% trans titleRight %}{{ titleLeft }}{{ titleRight }}
    {% trans %} report:: Volumetrie des questions posees sur {{home_title}} {% endtrans %}
    {% trans title_left %}{% trans title_right %}{{ title_left }}{{ title_right }}
    - + - - + + - + @@ -88,7 +88,7 @@ {% macro table_activity( id, title, title_abscisse, item) %} {% if item|length > 0 %}
    {% trans title %}{{ title }}
    {% trans title_left %}{% trans title_right %}{{ title_left }}{{ title_right }}
    {{ itemco }}{{ itemdl }}{{ itemdl }}
    - + @@ -101,7 +101,7 @@ {% for value in item %} From a165907b95317beb6f58783e4b61033cb8f5705d Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 17 Dec 2013 13:00:33 +0100 Subject: [PATCH 15/17] Fix #1627 : FTP receiver does not get its email --- .../Phrasea/Controller/Prod/Export.php | 2 +- lib/Alchemy/Phrasea/Notification/Emitter.php | 11 +++---- lib/Alchemy/Phrasea/Notification/Receiver.php | 11 +++---- lib/classes/ftpclient.php | 8 ++--- lib/classes/task/period/ftp.php | 31 ++++++++++--------- .../Phrasea/Notification/EmitterTest.php | 9 ++++++ .../Phrasea/Notification/ReceiverTest.php | 9 ++++++ 7 files changed, 47 insertions(+), 34 deletions(-) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Export.php b/lib/Alchemy/Phrasea/Controller/Prod/Export.php index 86c3cfdf94..ad560beb19 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Export.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Export.php @@ -168,7 +168,7 @@ class Export implements ControllerProviderInterface { $download = new \set_exportftp($app, $request->request->get('lst'), $request->request->get('ssttid')); - $mandatoryParameters = array('addr', 'login', 'destfolder', 'NAMMKDFOLD', 'obj'); + $mandatoryParameters = array('addr', 'login', 'obj'); foreach ($mandatoryParameters as $parameter) { if (!$request->request->get($parameter)) { diff --git a/lib/Alchemy/Phrasea/Notification/Emitter.php b/lib/Alchemy/Phrasea/Notification/Emitter.php index 5a4073c258..ec1d497cef 100644 --- a/lib/Alchemy/Phrasea/Notification/Emitter.php +++ b/lib/Alchemy/Phrasea/Notification/Emitter.php @@ -20,6 +20,10 @@ class Emitter implements EmitterInterface public function __construct($name, $email) { + if (!\Swift_Validate::email($email)) { + throw new InvalidArgumentException(sprintf('Invalid e-mail address (%s)', $email)); + } + $this->name = $name; $this->email = $email; } @@ -51,13 +55,6 @@ class Emitter implements EmitterInterface */ public static function fromUser(\User_Adapter $user) { - if (!\Swift_Validate::email($user->get_email())) { - throw new InvalidArgumentException(sprintf( - 'User provided does not have a valid e-mail address (%s)', - $user->get_email() - )); - } - return new static($user->get_display_name(), $user->get_email()); } } diff --git a/lib/Alchemy/Phrasea/Notification/Receiver.php b/lib/Alchemy/Phrasea/Notification/Receiver.php index 466efa547e..2d1e41b16b 100644 --- a/lib/Alchemy/Phrasea/Notification/Receiver.php +++ b/lib/Alchemy/Phrasea/Notification/Receiver.php @@ -20,6 +20,10 @@ class Receiver implements ReceiverInterface public function __construct($name, $email) { + if (!\Swift_Validate::email($email)) { + throw new InvalidArgumentException(sprintf('Invalid e-mail address (%s)', $email)); + } + $this->name = $name; $this->email = $email; } @@ -51,13 +55,6 @@ class Receiver implements ReceiverInterface */ public static function fromUser(\User_Adapter $user) { - if (!\Swift_Validate::email($user->get_email())) { - throw new InvalidArgumentException(sprintf( - 'User provided does not have a valid e-mail address (%s)', - $user->get_email() - )); - } - return new static($user->get_display_name(), $user->get_email()); } } diff --git a/lib/classes/ftpclient.php b/lib/classes/ftpclient.php index 26464e03a1..13dd95d1e9 100644 --- a/lib/classes/ftpclient.php +++ b/lib/classes/ftpclient.php @@ -217,9 +217,9 @@ class ftpclient protected function nb_put($remotefile, $localfile, $start = FTP_AUTORESUME) { - $ret = ftp_nb_put($this->connexion, $remotefile, $localfile, FTP_BINARY, $start); + $ret = @ftp_nb_put($this->connexion, $remotefile, $localfile, FTP_BINARY, $start); - while ($ret == FTP_MOREDATA) { + while ($ret === FTP_MOREDATA) { set_time_limit(20); $ret = ftp_nb_continue($this->connexion); } @@ -272,9 +272,9 @@ class ftpclient if ( ! file_exists($localfile)) $start = 0; - $ret = ftp_nb_get($this->connexion, $localfile, $remotefile, FTP_BINARY, $start); + $ret = @ftp_nb_get($this->connexion, $localfile, $remotefile, FTP_BINARY, $start); - while ($ret == FTP_MOREDATA) { + while ($ret === FTP_MOREDATA) { set_time_limit(20); $ret = ftp_nb_continue($this->connexion); } diff --git a/lib/classes/task/period/ftp.php b/lib/classes/task/period/ftp.php index 67ff22e84f..a6ed58bea9 100644 --- a/lib/classes/task/period/ftp.php +++ b/lib/classes/task/period/ftp.php @@ -11,6 +11,7 @@ use Alchemy\Phrasea\Core\Configuration\Configuration; use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Notification\Mail\MailSuccessFTPSender; +use Alchemy\Phrasea\Notification\Mail\MailSuccessFTPReceiver; use Alchemy\Phrasea\Notification\Receiver; class task_period_ftp extends task_appboxAbstract @@ -414,19 +415,19 @@ class task_period_ftp extends task_appboxAbstract $sbas_id = phrasea::sbasFromBas($this->dependencyContainer, $base_id); $record = new record_adapter($this->dependencyContainer, $sbas_id, $record_id); - $sdcaption = $record->get_caption()->serialize(caption_record::SERIALIZE_XML, $ftp_export["businessfields"]); + $sdcaption = $record->get_caption()->serialize(caption_record::SERIALIZE_XML, $file["businessfields"]); $remotefile = $file["filename"]; if ($subdef == 'caption') { - $desc = $record->get_caption()->serialize(\caption_record::SERIALIZE_XML, $ftp_export["businessfields"]); + $desc = $record->get_caption()->serialize(\caption_record::SERIALIZE_XML, $file["businessfields"]); $localfile = $this->dependencyContainer['root.path'] . '/tmp/' . md5($desc . time() . mt_rand()); if (file_put_contents($localfile, $desc) === false) { throw new Exception('Impossible de creer un fichier temporaire'); } } elseif ($subdef == 'caption-yaml') { - $desc = $record->get_caption()->serialize(\caption_record::SERIALIZE_YAML, $ftp_export["businessfields"]); + $desc = $record->get_caption()->serialize(\caption_record::SERIALIZE_YAML, $file["businessfields"]); $localfile = $this->dependencyContainer['root.path'] . '/tmp/' . md5($desc . time() . mt_rand()); if (file_put_contents($localfile, $desc) === false) { @@ -623,16 +624,16 @@ class task_period_ftp extends task_appboxAbstract foreach ($rs as $row) { if ($row['error'] == '0' && $row['done'] == '1') { $transferts[] = - '
  • ' . sprintf(_('task::ftp:Record %1$s - %2$s de la base (%3$s - %4$s) - %5$s') + ' - ' . sprintf(_('task::ftp:Record %1$s - %2$s de la base (%3$s - %4$s) - %5$s') , $row["record_id"], $row["filename"] , phrasea::sbas_labels(phrasea::sbasFromBas($this->dependencyContainer, $row["base_id"]), $this->dependencyContainer) - , phrasea::bas_labels($row['base_id'], $this->dependencyContainer), $row['subdef']) . ' : ' . _('Transfert OK') . '
  • '; + , phrasea::bas_labels($row['base_id'], $this->dependencyContainer), $row['subdef']) . ' : ' . _('Transfert OK'); } else { $transferts[] = - '
  • ' . sprintf(_('task::ftp:Record %1$s - %2$s de la base (%3$s - %4$s) - %5$s') + ' - ' . sprintf(_('task::ftp:Record %1$s - %2$s de la base (%3$s - %4$s) - %5$s') , $row["record_id"], $row["filename"] , phrasea::sbas_labels(phrasea::sbasFromBas($this->dependencyContainer, $row["base_id"]), $this->dependencyContainer), phrasea::bas_labels($row['base_id'], $this->dependencyContainer) - , $row['subdef']) . ' : ' . _('Transfert Annule') . '
  • '; + , $row['subdef']) . ' : ' . _('Transfert Annule'); $transfert_status = _('task::ftp:Certains documents n\'ont pas pu etre tranferes'); } } @@ -654,7 +655,7 @@ class task_period_ftp extends task_appboxAbstract $text_mail_sender = $row['text_mail_sender']; $text_mail_receiver = $row['text_mail_receiver']; - $mail = $row['mail']; + $receveirmail = $row['mail']; $sendermail = $row['sendermail']; $ftp_server = $row['addr']; } @@ -669,28 +670,28 @@ class task_period_ftp extends task_appboxAbstract $sender_message = $text_mail_sender . $message; $receiver_message = $text_mail_receiver . $message; - $receiver = null; + $sender = null; try { - $receiver = new Receiver(null, $sendermail); + $sender = new Receiver(null, $sendermail); } catch (InvalidArgumentException $e) { } - if ($receiver) { - $mail = MailSuccessFTPSender::create($this->dependencyContainer, $receiver, null, $sender_message); + if ($sender) { + $mail = MailSuccessFTPSender::create($this->dependencyContainer, $sender, null, $sender_message); $mail->setServer($ftp_server); $this->dependencyContainer['notification.deliverer']->deliver($mail); } $receiver = null; try { - $receiver = new Receiver(null, $mail); + $receiver = new Receiver(null, $receveirmail); } catch (InvalidArgumentException $e) { } if ($receiver) { - $mail = MailSuccessFTP::create($this->dependencyContainer, $receiver, null, $receiver_message); + $mail = MailSuccessFTPReceiver::create($this->dependencyContainer, $receiver, null, $receiver_message); $mail->setServer($ftp_server); $this->dependencyContainer['notification.deliverer']->deliver($mail); } @@ -699,7 +700,7 @@ class task_period_ftp extends task_appboxAbstract public function logexport(record_adapter $record, $obj, $ftpLog) { foreach ($obj as $oneObj) { - $this->app['phraseanet.logger']($record->get_databox()) + $this->dependencyContainer['phraseanet.logger']($record->get_databox()) ->log($record, Session_Logger::EVENT_EXPORTFTP, $ftpLog, ''); } diff --git a/tests/Alchemy/Tests/Phrasea/Notification/EmitterTest.php b/tests/Alchemy/Tests/Phrasea/Notification/EmitterTest.php index bc46c8a82b..034e7be972 100644 --- a/tests/Alchemy/Tests/Phrasea/Notification/EmitterTest.php +++ b/tests/Alchemy/Tests/Phrasea/Notification/EmitterTest.php @@ -83,4 +83,13 @@ class EmitterTest extends \PHPUnit_Framework_TestCase } } + + /** + * @expectedException \Alchemy\Phrasea\Exception\InvalidArgumentException + * @expectedExceptionMessage Invalid e-mail address (romain neutron email) + */ + public function testWrongEmail() + { + new Emitter('romain neutron', 'romain neutron email'); + } } diff --git a/tests/Alchemy/Tests/Phrasea/Notification/ReceiverTest.php b/tests/Alchemy/Tests/Phrasea/Notification/ReceiverTest.php index 0a1c4b91f8..dfaf08e340 100644 --- a/tests/Alchemy/Tests/Phrasea/Notification/ReceiverTest.php +++ b/tests/Alchemy/Tests/Phrasea/Notification/ReceiverTest.php @@ -83,4 +83,13 @@ class ReceiverTest extends \PHPUnit_Framework_TestCase } } + + /** + * @expectedException \Alchemy\Phrasea\Exception\InvalidArgumentException + * @expectedExceptionMessage Invalid e-mail address (romain neutron email) + */ + public function testWrongEmail() + { + new Receiver('romain neutron', 'romain neutron email'); + } } From 1f8843591063a911c50cb3b73603073c0d3ba4aa Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 17 Dec 2013 18:41:24 +0100 Subject: [PATCH 16/17] Fix tests --- lib/Alchemy/Phrasea/Helper/User/Edit.php | 1 + tests/Alchemy/Tests/Phrasea/Controller/Admin/UsersTest.php | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Alchemy/Phrasea/Helper/User/Edit.php b/lib/Alchemy/Phrasea/Helper/User/Edit.php index 02c1b53a28..4a017f0874 100644 --- a/lib/Alchemy/Phrasea/Helper/User/Edit.php +++ b/lib/Alchemy/Phrasea/Helper/User/Edit.php @@ -617,6 +617,7 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper $new_email = $user->get_email(); if ($old_email != $new_email) { + $oldReceiver = $newReceiver = null; try { $oldReceiver = new Receiver(null, $old_email); } catch (InvalidArgumentException $e) { diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/UsersTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/UsersTest.php index 6c7156ded2..5b4ea7abfc 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/UsersTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/UsersTest.php @@ -63,8 +63,8 @@ class ControllerUsersTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $user = \User_Adapter::create(self::$DI['app'], $username, "test", $username . "@email.com", false); $base_id = self::$DI['collection']->get_base_id(); - $_GET['values'] = 'canreport_' . $base_id . '=1&manage_' . self::$DI['collection']->get_base_id() . '=1&canpush_' . self::$DI['collection']->get_base_id() . '=1'; - $_GET['user_infos'] = "user_infos[email]=" . $user->get_email(); + $_POST['values'] = 'canreport_' . $base_id . '=1&manage_' . self::$DI['collection']->get_base_id() . '=1&canpush_' . self::$DI['collection']->get_base_id() . '=1'; + $_POST['user_infos'] = "email=" .$username . "-lambda@email.com"; self::$DI['client']->request('POST', '/admin/users/rights/apply/', array('users' => $user->get_id())); $response = self::$DI['client']->getResponse(); From 33f709e985f9aea519089bc602fef3996b96aaa8 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Wed, 18 Dec 2013 11:58:26 +0100 Subject: [PATCH 17/17] Add missing files --- .../Mail/MailSuccessFTPReceiver.php | 67 +++++++++++++++++++ lib/classes/caption/Field/ThesaurusValue.php | 47 +++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 lib/Alchemy/Phrasea/Notification/Mail/MailSuccessFTPReceiver.php create mode 100644 lib/classes/caption/Field/ThesaurusValue.php diff --git a/lib/Alchemy/Phrasea/Notification/Mail/MailSuccessFTPReceiver.php b/lib/Alchemy/Phrasea/Notification/Mail/MailSuccessFTPReceiver.php new file mode 100644 index 0000000000..5c391f86e9 --- /dev/null +++ b/lib/Alchemy/Phrasea/Notification/Mail/MailSuccessFTPReceiver.php @@ -0,0 +1,67 @@ +server = $server; + } + + /** + * {@inheritdoc} + */ + public function getSubject() + { + if (!$this->server) { + throw new LogicException('You must set server before calling getSubject'); + } + + return sprintf( + _('You just received some documents from %s on %s'), + $this->getPhraseanetTitle(), $this->server + ); + } + + /** + * {@inheritdoc} + */ + public function getMessage() + { + return $this->message; + } + + /** + * {@inheritdoc} + */ + public function getButtonText() + { + } + + /** + * {@inheritdoc} + */ + public function getButtonURL() + { + } +} diff --git a/lib/classes/caption/Field/ThesaurusValue.php b/lib/classes/caption/Field/ThesaurusValue.php new file mode 100644 index 0000000000..d62aa46d79 --- /dev/null +++ b/lib/classes/caption/Field/ThesaurusValue.php @@ -0,0 +1,47 @@ +value = $value; + $this->field = $field; + $this->query = $query; + } + + public function getValue() + { + return $this->value; + } + + public function getField() + { + return $this->field; + } + + public function getQuery() + { + return $this->query; + } + + public function __toString() + { + return $this->value; + } +}
    {% trans title %}{{ title }}
    {% if title_abscisse|length > 0 %} - {% trans title_abscisse%} + {{ title_abscisse }} {% endif %}