Merge branch '3.8'

Conflicts:
	lib/Alchemy/Phrasea/Controller/Prod/Export.php
	lib/Alchemy/Phrasea/Core/Version.php
	lib/Alchemy/Phrasea/Helper/Prod.php
	lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php
	lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php
	lib/classes/User/Adapter.php
	lib/classes/caption/Field/Value.php
	lib/classes/collection.php
	lib/classes/module/report/filter.php
	lib/classes/task/period/ftp.php
	templates/web/common/dialog_export.html.twig
	templates/web/report/ajax_dashboard_content_child.html.twig
	tests/Alchemy/Tests/Phrasea/Controller/Admin/UsersTest.php
This commit is contained in:
Romain Neutron
2013-12-18 12:12:58 +01:00
44 changed files with 389 additions and 170 deletions

10
composer.lock generated
View File

@@ -2109,16 +2109,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": {
@@ -2174,7 +2174,7 @@
"video",
"video processing"
],
"time": "2013-12-02 13:48:20"
"time": "2013-12-17 16:54:46"
},
{
"name": "php-mp4box/php-mp4box",

View File

@@ -633,10 +633,24 @@ class Application extends SilexApplication
return ConnectedUsers::appName($app['translator'], $value);
}));
$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('<em>', '</em>'), $value));
}
return "<a class=\"bounce\" onclick=\"bounce('" . $value->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('<em>', '</em>'), $value->getValue()))
. "</a>";
}, array('needs_environment' => true, 'is_safe' => array('html'))));
$twig->addFilter(new \Twig_SimpleFilter('escapeDoubleQuote', function ($value) {
return str_replace('"', '\"', $value);
}));

View File

@@ -116,7 +116,7 @@ class Export implements ControllerProviderInterface
{
$download = new \set_exportftp($app, $request->request->get('lst'), $request->request->get('ssttid'));
$mandatoryParameters = ['address', 'login', 'dest_folder', 'prefix_folder', 'obj'];
$mandatoryParameters = ['address', 'login', 'obj'];
foreach ($mandatoryParameters as $parameter) {
if (!$request->request->get($parameter)) {

View File

@@ -29,6 +29,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['acl']->get($this->app['authentication']->getUser())->get_granted_sbas() as $databox) {
$sbas_id = $databox->get_sbas_id();
@@ -41,8 +42,7 @@ class Prod extends Helper
];
foreach ($this->app['acl']->get($this->app['authentication']->getUser())->get_granted_base([], [$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'][] =
[
'selected' => $selected,

View File

@@ -610,6 +610,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) {

View File

@@ -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());
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2013 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Notification\Mail;
use Alchemy\Phrasea\Exception\LogicException;
class MailSuccessFTPReceiver extends AbstractMail
{
/** @var string */
private $server;
/**
* Sets the server related to the FTP export
*
* @param string $server
*/
public function setServer($server)
{
$this->server = $server;
}
/**
* {@inheritdoc}
*/
public function getSubject()
{
if (!$this->server) {
throw new LogicException('You must set server before calling getSubject');
}
return $this->app->trans('task::ftp:Status about your FTP transfert from %application% to %server%', [
'%application%' => $this->getPhraseanetTitle(),
'%server%' => $this->server,
]);
}
/**
* {@inheritdoc}
*/
public function getMessage()
{
return $this->message;
}
/**
* {@inheritdoc}
*/
public function getButtonText()
{
}
/**
* {@inheritdoc}
*/
public function getButtonURL()
{
}
}

View File

@@ -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());
}
}

View File

@@ -639,7 +639,7 @@ class PhraseaEngine implements SearchEngineInterface
if ($sxe && $sxe->description && $sxe->description->$name) {
$val = [];
foreach ($sxe->description->$name as $value) {
$val[] = str_replace(['[[em]]', '[[/em]]'], ['<em>', '</em>'], (string) $value);
$val[] = (string) $value;
}
$separator = $field['separator'] ? $field['separator'][0] : '';
$val = implode(' ' . $separator . ' ', $val);

View File

@@ -552,8 +552,8 @@ class SphinxSearchEngine implements SearchEngineInterface
}
$opts = [
'before_match' => "<em>",
'after_match' => "</em>",
'before_match' => "[[em]]",
'after_match' => "[[/em]]",
];
$fields_to_send = [];

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\TaskManager\Job;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Notification\Mail\MailSuccessFTPReceiver;
use Alchemy\Phrasea\TaskManager\Editor\FtpEditor;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Notification\Mail\MailSuccessFTPSender;
@@ -391,7 +392,7 @@ class FtpJob extends AbstractJob
try {
$receiver = new Receiver(null, $export->getMail());
$mail = MailSuccessFTPSender::create($app, $receiver, null, $receiver_message);
$mail = MailSuccessFTPReceiver::create($app, $receiver, null, $receiver_message);
$mail->setServer($ftp_server);
$app['notification.deliverer']->deliver($mail);
} catch (\Exception $e) {

View File

@@ -76,6 +76,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',
@@ -1037,16 +1038,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([':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')) {
@@ -1068,6 +1059,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([':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;

View File

@@ -315,7 +315,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 = [];

View File

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2013 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class ThesaurusValue
{
/** @var string */
private $value;
/** @var \databox_field */
private $field;
/** @var string */
private $query;
public function __construct($value, \databox_field $field, $query)
{
$this->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;
}
}

View File

@@ -346,73 +346,45 @@ class caption_Field_Value implements cache_cacheableInterface
return $value;
}
$DOM_branchs = $XPATH_thesaurus->query($tbranch);
$fvalue = $value;
$cleanvalue = str_replace(["<em>", "</em>", "'"], ["", "", "&apos;"], $fvalue);
// ---------------- new code ----------------------
$cleanvalue = str_replace(array("[[em]]", "[[/em]]", "'"), array("", "", "&apos;"), $value);
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']) {
// le terme est dans la bonne langue, on le rend cliquable
list($term, $context) = $this->splitTermAndContext($fvalue);
$term = str_replace(["<em>", "</em>"], ["", ""], $term);
$context = str_replace(["<em>", "</em>"], ["", ""], $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'] . "']", $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(["<em>", "</em>"], ["", ""], $term);
$context = str_replace(["<em>", "</em>"], ["", ""], $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(str_replace(array("[[em]]", "[[/em]]"), array("", ""), $value));
$qjs = $term . ($context ? '['.$context.']' : '');
if ($qjs) {
$value = "<a class=\"bounce\" onclick=\"bounce('" . $databox->get_sbas_id() . "','"
. str_replace("'", "\'", $qjs)
. "', '"
. str_replace("'", "\'", $this->databox_field->get_name())
. "');return(false);\">"
. $link
. "</a>";
$value = new ThesaurusValue($bestnode->getAttribute('v'), $this->databox_field, $qjs);
}
return $value;

View File

@@ -560,6 +560,12 @@ class collection implements cache_cacheableInterface
</sugestedValues>
</baseprefs>';
$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, '')";
@@ -574,11 +580,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([':server_coll_id' => $new_id, ':sbas_id' => $sbas_id]);
$stmt->execute([
':server_coll_id' => $new_id,
':sbas_id' => $sbas_id,
':ord' => $ord['ord'] ?: 1,
]);
$stmt->closeCursor();
$new_bas = $conn->lastInsertId();
@@ -633,7 +643,7 @@ class collection implements cache_cacheableInterface
VALUES
(null, 1, :server_coll_id, :sbas_id, '')";
$stmt = $databox->get_appbox()->get_connection()->prepare($sql);
$stmt->execute([':server_coll_id' => $coll_id, ':sbas_id' => $sbas_id]);
$stmt->execute([':server_coll_id' => $coll_id, ':sbas_id' => $databox->get_sbas_id()]);
$stmt->closeCursor();
$new_bas = $databox->get_appbox()->get_connection()->lastInsertId();
@@ -641,7 +651,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());

View File

@@ -228,7 +228,7 @@ class ftpclient
{
$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);
}
@@ -280,7 +280,7 @@ class ftpclient
$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);
}

View File

@@ -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 = [base::APPLICATION_BOX];

View File

@@ -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() %}
<div class="record record_document imgTips" style="width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;">
<div id="preview_{{thumbnail.get_base_id()}}_{{thumbnail.get_record_id()}}_{{random}}" class="PNB" style=""></div>
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
</div>
<script type="text/javascript">
swfobject.embedSWF("/include/FlexPaper_flash/FlexPaperViewer.swf",
@@ -50,20 +54,20 @@
{% set random = thumbnail.get_random() %}
<div class="record record_audio audioTips" style="width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;">
<div id="preview_{{thumbnail.get_base_id()}}_{{thumbnail.get_record_id()}}_{{random}}" class="PNB" style=""></div>
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
</div>
<script type="text/javascript">
swfobject.embedSWF("/include/jslibs/audio-player/player.swf",
"preview_{{thumbnail.get_base_id()}}_{{thumbnail.get_record_id()}}_{{random}}",
"{{thumbnail.get_width()}}", "{{thumbnail.get_height()}}", "9.0.0", false, false,
"{{thumbnail_width}}", "{{thumbnail_height}}", "9.0.0", false, false,
{menu: "false",flashvars: "playerID=2&autostart=yes&noinfo=yes&animation=no&remaining=yes&soundFile={{thumbnail.get_url()}}", movie: "/include/jslibs/audio-player/player.swf", allowFullScreen :"true",wmode: "transparent"}, false);</script>
{% else %}
<img class="record record_image imgTips zoomable thumb" oncontextMenu="return(false);"
style="width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;"
src="{{thumbnail.get_url()}}" ondragstart="return false;">
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
{% endif %}
</div>

View File

@@ -2,6 +2,8 @@
<h1>{{ 'Reorder collections' | trans }}</h1>
</div>
<div id="notification"></div>
<table id="table-order">
<tr>
<td valign="center" align="center">
@@ -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);

View File

@@ -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 = {

View File

@@ -1,6 +1,6 @@
{% macro format_caption(record, highlight, searchEngine, includeBusiness) %}
{% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %}
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{value.value|raw}}</div>
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{ value.value | thesaurus }}</div>
{% endfor %}
{% if app['authentication'].getUser().getPrefs('technical_display') == 'group' %}
<hr/>

View File

@@ -1,5 +1,5 @@
{% macro format_caption(record, highlight, searchEngine, includeBusiness) %}
{% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %}
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{value.value|raw}}</div>
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{ value.value | thesaurus }}</div>
{% endfor %}
{% endmacro %}
{% endmacro %}

View File

@@ -1,9 +1,9 @@
{% macro format_caption(record, highlight, searchEngine, includeBusiness) %}
{% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %}
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{value.value|raw}}</div>
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{ value.value | thesaurus }}</div>
{% endfor %}
{% if app['authentication'].getUser().getPrefs('technical_display') == 'group' %}
<hr/>
{% include 'common/technical_datas.html.twig' %}
{% endif %}
{% endmacro %}
{% endmacro %}

View File

@@ -1,9 +1,9 @@
{% macro format_caption(record, highlight, searchEngine, includeBusiness) %}
{% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %}
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{value.value|raw}}</div>
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{ value.value | thesaurus }}</div>
{% endfor %}
{% if app['authentication'].getUser().getPrefs('technical_display') == 'group' %}
<hr/>
{% include 'common/technical_datas.html.twig' %}
{% endif %}
{% endmacro %}
{% endmacro %}

View File

@@ -1,5 +1,5 @@
{% macro format_caption(record, highlight, searchEngine, includeBusiness) %}
{% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %}
<div><b>{{ value.label }}</b> : {{value.value|raw}}</div>
<div><b>{{ value.label }}</b> : {{ value.value }}</div>
{% endfor %}
{% endmacro %}
{% endmacro %}

View File

@@ -1,5 +1,5 @@
{% macro format_caption(record, highlight, searchEngine, includeBusiness) %}
{% for value in record.get_caption().get_highlight_fields(highlight, null, searchEngine, includeBusiness) %}
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{value.value|raw}}</div>
<div class="desc{% if loop.index is odd %}im{% endif %}pair"><b>{{ value.label }}</b> : {{ value.value | thesaurus }}</div>
{% endfor %}
{% endmacro %}
{% endmacro %}

View File

@@ -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() %}
<div class="record record_video imgTips" style="position:relative;width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;">
<div id="preview{{random}}" class="PNB"></div>
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
</div>
<script type="text/javascript">
flowplayer("preview{{random}}",
@@ -82,8 +86,8 @@
{% set random = thumbnail.get_random() %}
<div class="record record_audio audioTips" style="width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;">
<div id="preview_{{thumbnail.get_sbas_id()}}_{{thumbnail.get_record_id()}}_{{random}}" class="PNB" style=""></div>
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
</div>
<script type="text/javascript">
swfobject.embedSWF("/include/jslibs/audio-player/player.swf",
@@ -94,8 +98,8 @@
<img class="{% if lazyload %}lazyload{% endif %} record record_image imgTips zoomable thumb" oncontextMenu="return(false);"
style="width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;"
src="{% if lazyload %}/skins/grey.gif{% else %}{{ url }}{% endif %}" data-original="{{ url }}" ondragstart="return false;">
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
{% endif %}
{% if wrap %}
</div>
@@ -125,19 +129,23 @@
{% 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%}
{% set d_height = b_height %}
{% set d_width = d_height * thumbnail.get_width() / thumbnail.get_height() %}
{% set d_width = d_height * thumbnail_width / thumbnail_height %}
{% set left = (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 %}
@@ -157,8 +165,8 @@
{% set random = thumbnail.get_random() %}
<div class="record record_video imgTips" style="position:relative;width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;">
<div id="preview{{random}}" class="PNB"></div>
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
</div>
<script type="text/javascript">
flowplayer("preview{{random}}",
@@ -183,8 +191,8 @@
{% set random = thumbnail.get_random() %}
<div class="record record_audio audioTips" style="width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;">
<div id="preview_{{thumbnail.get_sbas_id()}}_{{thumbnail.get_record_id()}}_{{random}}" class="PNB" style=""></div>
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
</div>
<script type="text/javascript">
swfobject.embedSWF("/include/jslibs/audio-player/player.swf",
@@ -195,8 +203,8 @@
<img class="record record_image imgTips zoomable thumb" oncontextMenu="return(false);"
style="width:{{d_width|round}}px;height:{{d_height|round}}px;top:{{top|round}}px;"
src="{{url}}" ondragstart="return false;">
<input type="hidden" name="width" value="{{thumbnail.get_width()}}"/>
<input type="hidden" name="height" value="{{thumbnail.get_height()}}"/>
<input type="hidden" name="width" value="{{thumbnail_width}}"/>
<input type="hidden" name="height" value="{{thumbnail_height}}"/>
{% endif %}
{% if wrap %}
</div>
@@ -204,3 +212,4 @@
{% endmacro %}

View File

@@ -67,10 +67,18 @@
{% set thumbnail = record.get_thumbnail() %}
{% if thumbnail.is_paysage() %}
{% set w = 140 %}
{% set h = (w / (thumbnail.get_width() / thumbnail.get_height()))|round %}
{% if thumbnail.get_height() > 0 and thumbnail.get_width() > 0 %}
{% set h = (w / (thumbnail.get_width() / thumbnail.get_height()))|round %}
{% else %}
{% set h = 140 %}
{% endif %}
{% else %}
{% set h = 105 %}
{% set w = (h * (thumbnail.get_width() / thumbnail.get_height()))|round %}
{% if thumbnail.get_height() > 0 %}
{% set w = (h * (thumbnail.get_width() / thumbnail.get_height()))|round %}
{% else %}
{% set w = 105 %}
{% endif %}
{% endif %}
<img width="{{ w ~ 'px' }}" height="{{ h ~ 'px' }}" src="{{ thumbnail.get_url() }}" />

View File

@@ -802,6 +802,15 @@
<li><a href="#look_box_settings">{{ 'Configuration' | trans }}</a></li>
</ul>
<div id="look_box_screen">
<div class="box">
<div class="" style="float:left; width:100%;margin-top:20px;">
{% set mod = app['authentication'].getUser().getPrefs('advanced_search_reload') %}
<label class="checkbox inline" for="user_settings_advanced_search_reload">
<input onchange="setPref('advanced_search_reload',$(this).attr('checked')?'1' : '0');" name="advanced_search_reload" type="checkbox" style="margin: 3px 0 0 -18px;" class="checkbox" value="1" id="user_settings_advanced_search_reload" {% if mod == '1' %}checked="checked"{% endif %}/>
{{ 'Use latest search settings on Production loading' | trans }}
</label>
</div>
</div>
<div class="box">
<div class="" style="float:left; width:49%;">
<h1>{{ 'Mode de presentation' | trans }}</h1>

View File

@@ -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 %}

View File

@@ -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 %}
@@ -40,4 +44,4 @@
</div>
<div id="PREVIEWTOOL">
{% include 'prod/preview/tools.html.twig' %}
</div>
</div>

View File

@@ -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 @@
</div>
<div id="PREVIEWTOOL">
{% include 'prod/preview/tools.html.twig' %}
</div>
</div>

View File

@@ -74,7 +74,7 @@
<tbody>
<tr>
<td>{{ itemco }}</td>
<td>{{ itemdl }}</td>
<td>{{ itemdl }}</td>
</tr>
</tbody>
<tfoot>

View File

@@ -63,6 +63,8 @@ class ControllerUsersTest extends \PhraseanetAuthenticatedWebTestCase
$user = \User_Adapter::create(self::$DI['app'], $username, "test", $username . "@email.com", false);
$base_id = self::$DI['collection']->get_base_id();
$_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/', [
'users' => $user->get_id(),

View File

@@ -83,4 +83,13 @@ class EmitterTest extends \PhraseanetTestCase
}
}
/**
* @expectedException \Alchemy\Phrasea\Exception\InvalidArgumentException
* @expectedExceptionMessage Invalid e-mail address (romain neutron email)
*/
public function testWrongEmail()
{
new Emitter('romain neutron', 'romain neutron email');
}
}

View File

@@ -83,4 +83,13 @@ class ReceiverTest extends \PhraseanetTestCase
}
}
/**
* @expectedException \Alchemy\Phrasea\Exception\InvalidArgumentException
* @expectedExceptionMessage Invalid e-mail address (romain neutron email)
*/
public function testWrongEmail()
{
new Receiver('romain neutron', 'romain neutron email');
}
}

View File

@@ -754,7 +754,7 @@ abstract class SearchEngineAbstractTest extends \PhraseanetAuthenticatedTestCase
$found = false;
foreach (self::$searchEngine->excerpt($query_string, $fields, $foundRecord) as $field) {
if (strpos($field, '<em>') !== false && strpos($field, '</em>') !== false) {
if (strpos($field, '[[em]]') !== false && strpos($field, '[[/em]]') !== false) {
$found = true;
break;
}

View File

@@ -92,11 +92,14 @@ class userTest extends \PhraseanetTestCase
]);
$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) {
self::$DI['app']['conf']->remove('user-settings');

View File

@@ -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);
});

View File

@@ -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});
});

View File

@@ -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) {

View File

@@ -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());
});
});
});

View File

@@ -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 + '/',