Merge pull request #1960 from jygaulier/PHRAS-1192_quarantaine-by-filenames_4.0

PHRAS-1192_quarantaine-by-filenames_4.0
This commit is contained in:
Thibaud Fabre
2016-09-29 14:11:08 +02:00
committed by GitHub
17 changed files with 278 additions and 105 deletions

View File

@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Border\Checker;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\File;
use Alchemy\Phrasea\Model\Entities\LazaretFile;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Translation\TranslatorInterface;
@@ -51,6 +52,26 @@ class Filename extends AbstractChecker
return new Response($boolean, $this);
}
/**
* @param Application $app
* @param LazaretFile $file
* @return \record_adapter[]
*/
public static function listConflicts(Application $app, LazaretFile $file)
{
return \record_adapter::get_records_by_originalname(
$file->getCollection($app)->get_databox(), $file->getOriginalName(), false, 0, 1000
);
}
/**
* {@inheritdoc}
*/
public static function getReason(TranslatorInterface $translator)
{
return $translator->trans('same filename');
}
/**
* {@inheritdoc}
*/

View File

@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Border\Checker;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\File;
use Alchemy\Phrasea\Model\Entities\LazaretFile;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Translation\TranslatorInterface;
@@ -38,6 +39,26 @@ class Sha256 extends AbstractChecker
return new Response($boolean, $this);
}
/**
* @param Application $app
* @param LazaretFile $file
* @return \record_adapter[]
*/
public static function listConflicts(Application $app, LazaretFile $file)
{
$databox = $file->getCollection($app)->get_databox();
return $databox->getRecordRepository()->findBySha256($file->getSha256());
}
/**
* {@inheritdoc}
*/
public static function getReason(TranslatorInterface $translator)
{
return $translator->trans('same checksum');
}
/**
* {@inheritdoc}
*/

View File

@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Border\Checker;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\File;
use Alchemy\Phrasea\Model\Entities\LazaretFile;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Translation\TranslatorInterface;
@@ -37,6 +38,26 @@ class UUID extends AbstractChecker
return new Response($boolean, $this);
}
/**
* @param Application $app
* @param LazaretFile $file
* @return \record_adapter[]
*/
public static function listConflicts(Application $app, LazaretFile $file)
{
$databox = $file->getCollection($app)->get_databox();
return $databox->getRecordRepository()->findByUuid($file->getUUID());
}
/**
* {@inheritdoc}
*/
public static function getReason(TranslatorInterface $translator)
{
return $translator->trans('same UUID');
}
/**
* {@inheritdoc}
*/

View File

@@ -105,7 +105,7 @@ class RecordController extends Controller
'record' => $record,
]),
"pos" => $record->getNumber(),
"title" => str_replace(array('[[em]]', '[[/em]]'), array('<em>', '</em>'), $record->get_title($query, $searchEngine)),
"title" => $record->get_title(),
"databox_name" => $record->getDatabox()->get_dbname(),
"collection_name" => $record->getCollection()->get_name(),
"collection_logo" => $record->getCollection()->getLogo($record->getBaseId(), $this->app),

View File

@@ -10,7 +10,9 @@
namespace Alchemy\Phrasea\Model\Entities;
use Alchemy\Phrasea\Application;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Translation\TranslatorInterface;
/**
* @ORM\Table(name="LazaretChecks")
@@ -91,4 +93,33 @@ class LazaretCheck
{
return $this->lazaretFile;
}
/**
* @param TranslatorInterface $translator
* @return string the reason why a record is in lazaret
*/
public function getReason(TranslatorInterface $translator)
{
$className = $this->getCheckClassname();
if (method_exists($className, "getReason")) {
return $className::getReason($translator);
} else {
return '';
}
}
/**
* @param Application $app
* @return \record_adapter[] the records conflicting with this check
*/
public function listConflicts(Application $app)
{
$className = $this->getCheckClassname();
if (method_exists($className, "listConflicts")) {
return $className::listConflicts($app, $this->lazaretFile);
} else {
return [];
}
}
}

View File

@@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\Model\Entities;
use Alchemy\Phrasea\Application;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use \record_adapter;
/**
* @ORM\Table(name="LazaretFiles")
@@ -421,24 +422,32 @@ class LazaretFile
/**
* Get an array of records that can be substitued by the Lazaret file
*
* @return \record_adapter[]
* @return record_adapter[]
*/
public function getRecordsToSubstitute(Application $app)
public function getRecordsToSubstitute(Application $app, $includeReason = false)
{
$ret = [];
$repository = $this->getCollection($app)->get_databox()->getRecordRepository();
$shaRecords = $repository->findBySha256($this->getSha256());
$uuidRecords = $repository->findByUuid($this->getUuid());
$merged = array_merge($uuidRecords, $shaRecords);
foreach ($merged as $record) {
if ( ! in_array($record, $ret)) {
$ret[] = $record;
$merged = [];
/** @var LazaretCheck $check */
foreach($this->getChecks() as $check) {
/** @var record_adapter $record */
$conflicts = $check->listConflicts($app);
foreach ($conflicts as $record) {
if($includeReason) {
if (!array_key_exists($record->getRecordId(), $merged)) {
$merged[$record->getRecordId()] = [
'record' => $record,
'reasons' => []
];
}
$merged[$record->getRecordId()]['reasons'][] = $check->getReason($app['translator']);
}
else {
$merged[$record->getRecordId()] = $record;
}
}
}
return $ret;
return $merged;
}
}

View File

@@ -32,6 +32,8 @@ class PhraseanetExtension extends \Twig_Extension
return array(
new \Twig_SimpleFunction('user_setting', array($this, 'getUserSetting')),
new \Twig_SimpleFunction('record_thumbnail_url', array($this, 'getThumbnailUrl')),
new \Twig_SimpleFunction('record_subdef_url', array($this, 'getSubdefUrl')),
new \Twig_SimpleFunction('record_subdef_size', array($this, 'getSubdefSize')),
new \Twig_SimpleFunction('record_doctype_icon', array($this, 'getDoctypeIcon'), array(
'is_safe' => array('html')
)),
@@ -292,6 +294,33 @@ class PhraseanetExtension extends \Twig_Extension
return $path;
}
public function getSubdefSize(RecordInterface $record, $subdefName)
{
$ret = null;
if ($record instanceof ElasticsearchRecord) {
$subdefs = $record->getSubdefs();
if (isset($subdefs[$subdefName])) {
$subdef = $subdefs[$subdefName];
if (isset($subdef['width']) && $subdef['width'] !== null && isset($subdef['height']) && $subdef['height'] !== null) {
$ret = [
'width' => $subdef['width'],
'height' => $subdef['height']
];
}
}
} elseif ($record instanceof \record_adapter) {
if (null !== $subdef = $record->get_subdef($subdefName)) {
$ret = [
'width' => $subdef->get_width(),
'height' => $subdef->get_height()
];
}
}
return $ret;
}
public function getUserSetting($setting, $default = null)
{
if (false === ($this->app->getAuthenticatedUser() instanceof User)) {

View File

@@ -160,12 +160,11 @@ class caption_record implements cache_cacheableInterface
}
/**
* @param string $highlight
* @param array $grep_fields
* @param bool $includeBusiness
* @return array
*/
public function get_highlight_fields($highlight = '', array $grep_fields = null, $includeBusiness = false)
public function get_highlight_fields(array $grep_fields = null, $includeBusiness = false)
{
$fields = [];
@@ -177,11 +176,6 @@ class caption_record implements cache_cacheableInterface
'from_thesaurus' => false,
'qjs' => null,
];
if ($highlight) {
$v->highlight_thesaurus();
$values[$metaId]['from_thesaurus'] = $v->isThesaurusValue();
$values[$metaId]['qjs'] = $v->getQjs();
}
}
$fields[$field->get_name()] = [
'values' => $values,

View File

@@ -416,16 +416,14 @@ class media_Permalink_Adapter implements cache_cacheableInterface
$data[] = [
'subdef_id' => $media_subdef->get_subdef_id(),
'token' => $generator->generateString(64, TokenManipulator::LETTERS_AND_NUMBERS),
'label' => $records[$media_subdef->get_record_id()]->get_title(false, null, true),
'label' => $records[$media_subdef->get_record_id()]->get_title(['removeExtension' => true]),
];
}
try {
$databox->get_connection()->transactional(function (Connection $connection) use ($data) {
$sql = <<<'SQL'
INSERT INTO permalinks (subdef_id, token, activated, created_on, last_modified, label)
VALUES (:subdef_id, :token, 1, NOW(), NOW(), :label)
SQL;
$sql = "INSERT INTO permalinks (subdef_id, token, activated, created_on, last_modified, label)\n"
. " VALUES (:subdef_id, :token, 1, NOW(), NOW(), :label)";
$statement = $connection->prepare($sql);

View File

@@ -387,6 +387,14 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
return \collection::getByCollectionId($this->app, $this->getDatabox(), $this->collection_id);
}
/**
* @return string the name of the collection to which the record belongs to.
*/
public function getCollectionName()
{
return $this->getCollection()->get_name();
}
/**
* Returns record_id of the record
*
@@ -795,15 +803,20 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
}
/**
* @param bool $highlight
* @param SearchEngineInterface $searchEngine
* @param null $removeExtension
* @param SearchEngineOptions $options
* get the title (concat "thumbtitle" fields which match locale, with "-")
* fallback to the filename, possibly with extension removed
*
* @param string $locale
* @param $options[]
* 'removeExtension' : boolean
*
* @return string
*/
public function get_title($highlight = false, SearchEngineInterface $searchEngine = null, $removeExtension = null, SearchEngineOptions $options = null)
public function getTitle($locale = null, Array $options = [])
{
$cache = !$highlight && !$searchEngine && !$removeExtension;
$removeExtension = !!igorw\get_in($options, ['removeExtension'], false);
$cache = !$removeExtension;
if ($cache) {
try {
@@ -820,13 +833,13 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
$fields_to_retrieve = [];
foreach ($fields as $field) {
if (in_array($field->get_thumbtitle(), ['1', $this->app['locale']])) {
if (in_array($field->get_thumbtitle(), ['1', $locale])) {
$fields_to_retrieve [] = $field->get_name();
}
}
if (count($fields_to_retrieve) > 0) {
$retrieved_fields = $this->get_caption()->get_highlight_fields($highlight, $fields_to_retrieve);
$retrieved_fields = $this->get_caption()->get_highlight_fields($fields_to_retrieve);
$titles = [];
foreach ($retrieved_fields as $value) {
foreach ($value['values'] as $v) {
@@ -849,6 +862,16 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
return $title;
}
/**
* @param Array $options
*
* @return string
*/
public function get_title(Array $options = [])
{
return $this->getTitle($this->app['locale'], $options);
}
/**
* @return media_subdef
*/
@@ -1524,12 +1547,12 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
* @param int $offset_start
* @param int $how_many
*
* @return array
* @return record_adapter[]
*/
public static function get_records_by_originalname(databox $databox, $original_name, $caseSensitive = false, $offset_start = 0, $how_many = 10)
{
$offset_start = (int)($offset_start < 0 ? 0 : $offset_start);
$how_many = (int)(($how_many > 20 || $how_many < 1) ? 10 : $how_many);
$offset_start = max(0, (int)$offset_start);
$how_many = max(1, (int)$how_many);
$sql = sprintf(
'SELECT record_id FROM record WHERE originalname = :original_name COLLATE %s LIMIT %d, %d',

View File

@@ -252,7 +252,7 @@ class record_preview extends record_adapter
*
* @return String
*/
public function get_title($highlight = false, SearchEngineInterface $searchEngine = null, $removeExtension = null, SearchEngineOptions $options = null)
public function get_title(Array $options = [])
{
if ($this->title) {
return $this->title;
@@ -264,14 +264,14 @@ class record_preview extends record_adapter
case "RESULT":
$this->title .= $this->app->trans('resultat numero %number%', ['%number%' => '<span id="current_result_n">' . ($this->getNumber() + 1) . '</span> : ']);
$this->title .= parent::get_title($highlight, $searchEngine);
$this->title .= parent::get_title($options);
break;
case "BASK":
$this->title .= $this->name . ' - ' . parent::get_title($highlight, $searchEngine)
$this->title .= $this->name . ' - ' . parent::get_title($options)
. ' (' . $this->getNumber() . '/' . $this->total . ') ';
break;
case "REG":
$title = parent::get_title();
$title = parent::get_title($options);
if ($this->getNumber() == 0) {
$this->title .= $title;
} else {
@@ -281,7 +281,7 @@ class record_preview extends record_adapter
}
break;
default:
$this->title .= parent::get_title($highlight, $searchEngine);
$this->title .= parent::get_title($options);
break;
}

View File

@@ -130,7 +130,7 @@ class set_export extends set_abstract
$app,
$child_basrec->getDataboxId(),
$record_id,
$record->get_title(null, null, true) . '_' . $n,
$record->get_title(['removeExtension' => true]) . '_' . $n,
$remain_hd[$base_id]
);
$this->add_element($current_element);
@@ -256,18 +256,17 @@ class set_export extends set_abstract
$types['usr_id'] = PDO::PARAM_INT;
}
$sql = <<<SQL
SELECT Users.id AS usr_id ,Users.login AS usr_login ,Users.email AS usr_mail, FtpCredential.*
FROM (
FtpCredential INNER JOIN Users ON (FtpCredential.active = 1 AND FtpCredential.user_id = Users.id)
INNER JOIN basusr ON (
Users.id=basusr.usr_id
${userFilterSQL}
AND (basusr.base_id IN (:baseIds))
)
)
GROUP BY Users.id
SQL;
$sql = "SELECT Users.id AS usr_id ,Users.login AS usr_login ,Users.email AS usr_mail, FtpCredential.*\n"
. "FROM (\n"
. " FtpCredential INNER JOIN Users ON (FtpCredential.active = 1 AND FtpCredential.user_id = Users.id)\n"
. "INNER JOIN\n"
. " basusr\n"
. "ON (Users.id=basusr.usr_id"
. $userFilterSQL
. " AND (basusr.base_id IN (:baseIds)))\n"
. ")\n"
. "GROUP BY Users.id\n";
$params['baseIds'] = $lst_base_id;
$types['baseIds'] = Connection::PARAM_INT_ARRAY;
@@ -440,7 +439,7 @@ SQL;
substr($files[$id]['original_name'], 0 - strrpos($files[$id]['original_name'], '.'));
if ($rename_title) {
$title = strip_tags($download_element->get_title(null, null, true));
$title = strip_tags($download_element->get_title(['removeExtension' => true]));
$files[$id]['export_name'] = $unicode->remove_nonazAZ09($title, true, true, true);
} else {
$files[$id]["export_name"] = $infos['filename'];
@@ -458,10 +457,15 @@ SQL;
continue;
}
$subdef = $download_element->get_subdef($name);
if (!in_array($name, ['caption', 'caption-yaml']) && !isset($subdef)) {
continue;
$subdef = null;
if (!in_array($name, ['caption', 'caption-yaml'])) {
try {
// get_subdef() can throw a 404
$subdef = $download_element->get_subdef($name);
}
catch(\Exception $e) {
continue;
}
}
set_time_limit(100);
@@ -691,7 +695,7 @@ SQL;
public static function build_zip(Application $app, Token $token, array $list, $zipFile)
{
if (isset($list['complete']) && $list['complete'] === true) {
return;
return $zipFile;
}
$files = $list['files'];
@@ -786,9 +790,7 @@ SQL;
$list_base = array_unique(array_keys($tmplog));
if (!$anonymous && null !== $app->getAuthenticatedUser()) {
$sql = "UPDATE basusr
SET remain_dwnld = :remain_dl
WHERE base_id = :base_id AND usr_id = :usr_id";
$sql = "UPDATE basusr SET remain_dwnld = :remain_dl WHERE base_id = :base_id AND usr_id = :usr_id";
$stmt = $app->getApplicationBox()->get_connection()->prepare($sql);

View File

@@ -103,7 +103,7 @@
{% endmacro %}
{% macro format_caption(record, highlight, search_engine, include_business, bounceable, technical_data) %}
{% for field in record.get_caption().get_highlight_fields(highlight, null, include_business) %}
{% for field in record.get_caption().get_highlight_fields(null, include_business) %}
{% set extra_classes = ['pair'] %}
{% if loop.index is odd %}
{% set extra_classes = ['impair'] %}

View File

@@ -4,13 +4,13 @@
{% set thumb_w = 256 %}
{% set thumb_h = 256 %}
{% set thumbnail = record.subdefs.thumbnail|default(null) %}
{% if thumbnail is not none %}
{% set thumb_w = thumbnail.width %}
{% set thumb_h = thumbnail.height %}
{% set thumbnailSize = record_subdef_size(record, "thumbnail") %}
{% if thumbnailSize is not null %}
{% set thumb_w = thumbnailSize.width %}
{% set thumb_h = thumbnailSize.height %}
{% endif %}
{% set url = record_thumbnail_url(record) %}
{% set url = record_subdef_url(record, "thumbnail") %}
{% set box_w = box_w|round %}
{% set box_h = box_h|default(box_w)|round %}

View File

@@ -5,11 +5,11 @@
sbas="{{ record.databoxId }}"
id="{{ prefix|default('IMGT') }}_{{ record.id }}"
class="IMGT diapo {% if record.story %}grouping{% endif %} type-{{ record.type }}"
onDblClick="openPreview(this, '{{ record.story ? 'REG' : 'RESULT' }}', '{{ record.position|default(0) }}', '{{ record.id }}');">
{% if settings.handle_dblclick %}onDblClick="openPreview(this, '{{ record.story ? 'REG' : 'RESULT' }}', '{{ record.position|default(0) }}', '{{ record.id }}');"{% endif %}>
<div style="padding: 4px;">
<div style="height:40px; position: relative; z-index: 95;margin-bottom:0;border-bottom:none;">
<div class="title" style="max-height:100%" title="{{ record.title(app.locale) }}">
{{ record.title(app.locale)|highlight }}
<div class="title" style="max-height:100%" title="{{ record.getTitle(app.locale) }}">
{{ record.getTitle(app.locale)|highlight }}
</div>
<div class="status">
{% for flag in record_flags(record) %}
@@ -73,7 +73,7 @@
<td style="text-align:right;width:{{l_width}}px;" valign="bottom">
{% if settings.rollover_thumbnail == 'caption' %}
{% if record.subdefs.preview is defined and has_access_subdef(record, 'preview') %}
{% if record_subdef_url(record, 'preview') is not null and has_access_subdef(record, 'preview') %}
<span class="icon-stack previewTips" tooltipsrc="{{ path('prod_tooltip_preview', { 'sbas_id' : record.databoxId, 'record_id' : record.recordId }) }}">
<i class="icon-circle icon-stack-base"></i>
<i class="icon-search icon-light"></i>
@@ -94,6 +94,7 @@
</span>
{% endif %}
{% if settings.show_context_menu %}
<span class="icon-stack contextMenuTrigger" id="contextTrigger_{{record.id}}"
tooltipsrc="{{ path('prod_tooltip_technical_data', { 'sbas_id' : record.databoxId, 'record_id' : record.recordId }) }}">
<i class="icon-circle icon-stack-base"></i>
@@ -143,6 +144,7 @@
</tr>
</tbody>
</table>
{% endif %}
</td>
</tr>
</table>

View File

@@ -28,7 +28,9 @@
'images_size': images_size,
'technical_display': technical_display,
'rollover_thumbnail': rollover_thumbnail,
'doctype_display': doctype_display
'doctype_display': doctype_display,
'handle_dblclick' : true,
'show_context_menu': true
}
} %}
{% endblock %}

View File

@@ -92,13 +92,16 @@
}
}
$(".records-subititution", scope).bind('click', function(){
$(this).closest('.lazaret-proposals').find('.records-subititution').removeClass("thumb-selected");
$(this).closest('.lazaret-proposals').find('.thumbnail').css({'border-color': 'white'})
$(this).find('.thumbnail').css({'border-color': 'blue'});
$(this).addClass("thumb-selected");
});
$(".records-subititution .diapo", scope)
.bind('click', function(e){
$(this).closest('.lazaret-proposals').find('.diapo').removeClass('selected');
$(this).addClass('selected');
}
);
$(".records-subititution .captionTips", scope).tooltip();
$(".records-subititution .infoTips", scope).tooltip();
$(".records-subititution .previewTips", scope).tooltip();
var emptying = false; // true=emptying, set to false to stop
@@ -198,14 +201,14 @@
var html = _.template($("#alert_error_tpl").html(), {
content:data.message
});
that.closest(".thumbnail").append(html);
that.closest(".diapo").append(html);
}
},
error: function(){
var html = _.template($("#alert_error_tpl").html(), {
content:language.errorAjaxRequest
});
that.closest(".thumbnail").append(html);
that.closest(".diapo").append(html);
},
complete: function(){
stopAjax(that);
@@ -233,14 +236,14 @@
var html = _.template($("#alert_error_tpl").html(), {
content:data.message
});
that.closest(".thumbnail").append(html);
that.closest(".diapo").append(html);
}
},
error: function(){
var html = _.template($("#alert_error_tpl").html(), {
content:language.errorAjaxRequest
});
that.closest(".thumbnail").append(html);
that.closest(".diapo").append(html);
},
complete: function(){
stopAjax(that);
@@ -253,14 +256,18 @@
$("button.subtitute-lazaret", scope).bind('click', function(){
var that = $(this);
var lazaretId = getLazaretId(that);
var nbProposals = $('.records-subititution', $(this).closest('.wrapper-item')).length;
var container = $(this).closest('.wrapper-item');
var nbProposals = $('.records-subititution', container).length;
var elements = [];
var nbElement = 0;
if(nbProposals > 1){ // we got more than one proposals
var elements = $(".thumb-selected", $(this).closest('.wrapper-item'));
var nbElement = elements.length;
elements = $(".selected", container);
nbElement = elements.length;
}else if(nbProposals == 1){
var elements = $(this).closest('.wrapper-item').find(".records-subititution");
var nbElement = 1
elements = container.find(".records-subititution");
nbElement = 1
}
else{
return false;
@@ -274,8 +281,7 @@
return false;
}
var recorThumb = elements.first().find('.record-thumb');
var recordId = recorThumb.find('input[name=record_id]').val();
var recordId = elements.first().attr("data-record_id");
$.ajax({
type : 'POST',
@@ -294,14 +300,14 @@
var html = _.template($("#alert_error_tpl").html(), {
content:data.message
});
that.closest(".thumbnail").append(html);
that.closest(".diapo").append(html);
}
},
error: function(){
var html = _.template($("#alert_error_tpl").html(), {
content:language.errorAjaxRequest
});
that.closest(".thumbnail").append(html);
that.closest(".diapo").append(html);
},
complete: function(){
stopAjax(that);
@@ -311,10 +317,15 @@
});
});
</script>
<style>
.lazaret-proposals .diapo {
float:none;
}
</style>
{% macro lazaretElement(app, file) %}
{% import "common/thumbnail.html.twig" as thumb %}
{% set records = file.getRecordsToSubstitute(app) %}
{% set records = file.getRecordsToSubstitute(app, true) %}
<div class="lazaret-file span4">
<h5>{{ "Last uploaded version" | trans }}</h5>
<ul class="thumbnails">
@@ -370,17 +381,26 @@
</h5>
<ul class="thumbnails">
{% for record in records %}
{% set reasons = record['reasons'] %}
{% set record = record['record'] %}
{% if app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), "canaddrecord")
and app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), "candeleterecord") %}
<li class="records-subititution span3">
<div class="thumbnail">
<div class="record-thumb" style="text-align:center;">
{{ thumb.format(record.get_thumbnail(), 169, 180, "", false, false) }}
<input name="record_id" value="{{ record.get_record_id() }}" type="hidden"/>
</div>
<div class="caption">
<p><b>{{ record.get_title() }}</b></p>
</div>
<li class="records-subititution span3" style="width:210px">
{% include 'prod/results/record.html.twig' with {
'record': record,
'settings': {
'images_size': 169,
'technical_display': '1',
'rollover_thumbnail': 'caption',
'doctype_display': '1',
'handle_dblclick' : false,
'show_context_menu': false
}
} %}
<div class="caption">
{% for reason in reasons %}
<p>{{ reason }}</p>
{% endfor %}
</div>
</li>
{% endif %}