mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-23 18:03:17 +00:00
Merge branch 'master' of https://github.com/alchemy-fr/Phraseanet into PHRAS-859_validation_special_characters_status
This commit is contained in:
@@ -127,6 +127,23 @@ class TwigServiceProvider implements ServiceProviderInterface
|
||||
);
|
||||
}, ['needs_environment' => true, 'is_safe' => ['html']]));
|
||||
|
||||
$twig->addFilter(new \Twig_SimpleFilter('parseColor', function (\Twig_Environment $twig, $string) use ($app) {
|
||||
$re = '/^(.*)\[#([0-9a-fA-F]{6})]$/m';
|
||||
$stringArr = explode(';', $string);
|
||||
|
||||
foreach ($stringArr as $key => $value) {
|
||||
preg_match_all($re, trim($value), $matches);
|
||||
if ($matches && $matches[1] != null && $matches[2] != null) {
|
||||
$colorCode = '#' . $matches[2][0];
|
||||
$colorName = $matches[1][0];
|
||||
|
||||
$stringArr[$key] = '<span style="white-space: nowrap;"><span class="color-dot" style="margin-right: 4px; background-color: ' . $colorCode . '"></span>' . $colorName . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
return implode('; ', $stringArr);
|
||||
}, ['needs_environment' => true, 'is_safe' => ['html']]));
|
||||
|
||||
$twig->addFilter(new \Twig_SimpleFilter('bounce',
|
||||
function (\Twig_Environment $twig, $fieldValue, $fieldName, $searchRequest, $sbasId) {
|
||||
// bounce value if it is present in thesaurus as well
|
||||
|
@@ -25,6 +25,7 @@ class PDF
|
||||
const LAYOUT_PREVIEWCAPTIONTDM = 'previewCaptionTdm';
|
||||
const LAYOUT_THUMBNAILLIST = 'thumbnailList';
|
||||
const LAYOUT_THUMBNAILGRID = 'thumbnailGrid';
|
||||
const LAYOUT_CAPTION = 'caption';
|
||||
|
||||
public function __construct(Application $app, array $records, $layout)
|
||||
{
|
||||
@@ -73,6 +74,8 @@ class PDF
|
||||
continue 2;
|
||||
}
|
||||
break;
|
||||
case self::LAYOUT_CAPTION:
|
||||
break;
|
||||
}
|
||||
|
||||
$record->setNumber(count($list) + 1);
|
||||
@@ -106,6 +109,9 @@ class PDF
|
||||
case self::LAYOUT_THUMBNAILGRID:
|
||||
$this->print_thumbnailGrid();
|
||||
break;
|
||||
case self::LAYOUT_CAPTION:
|
||||
$this->print_caption();
|
||||
break;
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -315,6 +321,67 @@ class PDF
|
||||
$this->pdf->SetLeftMargin($lmargin);
|
||||
}
|
||||
|
||||
protected function print_caption()
|
||||
{
|
||||
$this->pdf->AddPage();
|
||||
$oldMargins = $this->pdf->getMargins();
|
||||
|
||||
$lmargin = $oldMargins['left'];
|
||||
$rmargin = $oldMargins['right'];
|
||||
|
||||
foreach ($this->records as $rec) {
|
||||
$title = "record : " . $rec->get_title();
|
||||
|
||||
$y = $this->pdf->GetY();
|
||||
if($this->pdf->getPageHeight() - $y < 20){ // height of the footer is 15
|
||||
$this->pdf->AddPage();
|
||||
$y = $oldMargins['top'];
|
||||
}
|
||||
|
||||
$t = \phrasea::bas_labels($rec->getBaseId(), $this->app);
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, '', 10);
|
||||
$this->pdf->SetFillColor(220, 220, 220);
|
||||
$this->pdf->SetLeftMargin($lmargin);
|
||||
$this->pdf->SetRightMargin($rmargin);
|
||||
$this->pdf->SetX($lmargin);
|
||||
$this->pdf->SetY($y);
|
||||
|
||||
$this->pdf->out = false;
|
||||
$this->pdf->MultiCell(140, 4, $title, "LTR", "L", 1);
|
||||
$y2 = $this->pdf->GetY();
|
||||
$h = $y2 - $y;
|
||||
$this->pdf->out = true;
|
||||
$this->pdf->SetX($lmargin);
|
||||
$this->pdf->SetY($y);
|
||||
$this->pdf->Cell(0, $h, "", "LTR", 1, "R", 1);
|
||||
$this->pdf->SetX($lmargin);
|
||||
$this->pdf->SetY($y);
|
||||
$this->pdf->Cell(0, 4, $t, "", 1, "R");
|
||||
$this->pdf->SetX($lmargin);
|
||||
$this->pdf->SetY($y);
|
||||
$this->pdf->MultiCell(140, 4, $title, "", "L");
|
||||
$this->pdf->SetX($lmargin);
|
||||
$this->pdf->SetY($y = $y2);
|
||||
$this->pdf->SetY($y + 2);
|
||||
|
||||
foreach ($rec->get_caption()->get_fields() as $field) {
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, 'B', 12);
|
||||
$this->pdf->Write(5, $field->get_name() . " : ");
|
||||
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, '', 12);
|
||||
$t = str_replace(
|
||||
["<", ">", "&"]
|
||||
, ["<", ">", "&"]
|
||||
, strip_tags($field->get_serialized_values())
|
||||
);
|
||||
$this->pdf->Write(5, $t);
|
||||
|
||||
$this->pdf->Write(6, "\n");
|
||||
}
|
||||
$this->pdf->SetY($this->pdf->GetY() + 10);
|
||||
}
|
||||
}
|
||||
|
||||
protected function print_preview($withtdm, $write_caption)
|
||||
{
|
||||
if ($withtdm === true) {
|
||||
|
@@ -201,6 +201,11 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
$this->notImplemented();
|
||||
}
|
||||
|
||||
private function notImplemented()
|
||||
{
|
||||
throw new LogicException('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -241,11 +246,6 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
$this->notImplemented();
|
||||
}
|
||||
|
||||
private function notImplemented()
|
||||
{
|
||||
throw new LogicException('Not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -330,131 +330,6 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
);
|
||||
}
|
||||
|
||||
private function buildHighlightRules(QueryContext $context)
|
||||
{
|
||||
$highlighted_fields = [];
|
||||
foreach ($context->getHighlightedFields() as $field) {
|
||||
switch ($field->getType()) {
|
||||
case FieldMapping::TYPE_STRING:
|
||||
$index_field = $field->getIndexField();
|
||||
$raw_index_field = $field->getIndexField(true);
|
||||
$highlighted_fields[$index_field] = [
|
||||
// Requires calling Mapping::enableTermVectors() on this field mapping
|
||||
'matched_fields' => [$index_field, $raw_index_field],
|
||||
'type' => 'fvh'
|
||||
];
|
||||
break;
|
||||
case FieldMapping::TYPE_FLOAT:
|
||||
case FieldMapping::TYPE_DOUBLE:
|
||||
case FieldMapping::TYPE_INTEGER:
|
||||
case FieldMapping::TYPE_LONG:
|
||||
case FieldMapping::TYPE_SHORT:
|
||||
case FieldMapping::TYPE_BYTE:
|
||||
continue;
|
||||
case FieldMapping::TYPE_DATE:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'pre_tags' => ['[[em]]'],
|
||||
'post_tags' => ['[[/em]]'],
|
||||
'order' => 'score',
|
||||
'fields' => $highlighted_fields
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function autocomplete($query, SearchEngineOptions $options)
|
||||
{
|
||||
$params = $this->createCompletionParams($query, $options);
|
||||
|
||||
$res = $this->client->suggest($params);
|
||||
|
||||
$ret = [
|
||||
'text' => [],
|
||||
'byField' => []
|
||||
];
|
||||
foreach(array_keys($params['body']) as $fname) {
|
||||
$t = [];
|
||||
foreach($res[$fname] as $suggest) { // don't know why there is a sub-array level
|
||||
foreach($suggest['options'] as $option) {
|
||||
$text = $option['text'];
|
||||
if(!in_array($text, $ret['text'])) {
|
||||
$ret['text'][] = $text;
|
||||
}
|
||||
$t[] = [
|
||||
'label' => $text,
|
||||
'query' => $fname.':'.$text
|
||||
];
|
||||
}
|
||||
}
|
||||
if(!empty($t)) {
|
||||
$ret['byField'][$fname] = $t;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetCache()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearCache()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearAllCache(\DateTime $date = null)
|
||||
{
|
||||
}
|
||||
|
||||
private function createCompletionParams($query, SearchEngineOptions $options)
|
||||
{
|
||||
$body = [];
|
||||
$context = [
|
||||
'record_type' => $options->getSearchType() === SearchEngineOptions::RECORD_RECORD ?
|
||||
SearchEngineInterface::GEM_TYPE_RECORD : SearchEngineInterface::GEM_TYPE_STORY
|
||||
];
|
||||
|
||||
$base_ids = $options->getBasesIds();
|
||||
if (count($base_ids) > 0) {
|
||||
$context['base_id'] = $base_ids;
|
||||
}
|
||||
|
||||
$search_context = $this->context_factory->createContext($options);
|
||||
$fields = $search_context->getUnrestrictedFields();
|
||||
foreach($fields as $field) {
|
||||
if($field->getType() == FieldMapping::TYPE_STRING) {
|
||||
$k = '' . $field->getName();
|
||||
$body[$k] = [
|
||||
'text' => $query,
|
||||
'completion' => [
|
||||
'field' => "caption." . $field->getName() . ".suggest",
|
||||
'context' => &$context
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'index' => $this->indexName,
|
||||
'body' => $body
|
||||
];
|
||||
}
|
||||
|
||||
private function createRecordQueryParams($ESQuery, SearchEngineOptions $options, \record_adapter $record = null)
|
||||
{
|
||||
$params = [
|
||||
@@ -483,66 +358,28 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
return $params;
|
||||
}
|
||||
|
||||
private function getAggregationQueryParams(SearchEngineOptions $options)
|
||||
private function createSortQueryParams(SearchEngineOptions $options)
|
||||
{
|
||||
$aggs = [];
|
||||
// technical aggregates (enable + optional limit)
|
||||
foreach (ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) {
|
||||
$size = $this->options->getAggregableFieldLimit($k);
|
||||
if ($size !== databox_field::FACET_DISABLED) {
|
||||
if ($size === databox_field::FACET_NO_LIMIT) {
|
||||
$size = ESField::FACET_NO_LIMIT;
|
||||
$sort = [];
|
||||
|
||||
if ($options->getSortBy() === null || $options->getSortBy() === SearchEngineOptions::SORT_RELEVANCE) {
|
||||
$sort['_score'] = $options->getSortOrder();
|
||||
}
|
||||
$agg = [
|
||||
'terms' => [
|
||||
'field' => $f['field'],
|
||||
'size' => $size
|
||||
]
|
||||
];
|
||||
$aggs[$k] = $agg;
|
||||
elseif ($options->getSortBy() === SearchEngineOptions::SORT_CREATED_ON) {
|
||||
$sort['created_on'] = $options->getSortOrder();
|
||||
}
|
||||
elseif ($options->getSortBy() === 'recordid') {
|
||||
$sort['record_id'] = $options->getSortOrder();
|
||||
}
|
||||
// fields aggregates
|
||||
$structure = $this->context_factory->getLimitedStructure($options);
|
||||
foreach ($structure->getFacetFields() as $name => $field) {
|
||||
// 2015-05-26 (mdarse) Removed databox filtering.
|
||||
// It was already done by the ACL filter in the query scope, so no
|
||||
// document that shouldn't be displayed can go this far.
|
||||
$agg = [
|
||||
'terms' => [
|
||||
'field' => $field->getIndexField(true),
|
||||
'size' => $field->getFacetValuesLimit()
|
||||
]
|
||||
];
|
||||
$aggs[$name] = AggregationHelper::wrapPrivateFieldAggregation($field, $agg);
|
||||
}
|
||||
return $aggs;
|
||||
else {
|
||||
$sort[sprintf('caption.%s', $options->getSortBy())] = $options->getSortOrder();
|
||||
}
|
||||
|
||||
private function createACLFilters(SearchEngineOptions $options)
|
||||
{
|
||||
// No ACLs if no user
|
||||
if (false === $this->app->getAuthenticator()->isAuthenticated()) {
|
||||
return [];
|
||||
if (!array_key_exists('record_id', $sort)) {
|
||||
$sort['record_id'] = $options->getSortOrder();
|
||||
}
|
||||
|
||||
$acl = $this->app->getAclForUser($this->app->getAuthenticatedUser());
|
||||
|
||||
$grantedCollections = array_keys($acl->get_granted_base([\ACL::ACTIF]));
|
||||
|
||||
if (count($grantedCollections) === 0) {
|
||||
return ['bool' => ['must_not' => ['match_all' => new \stdClass()]]];
|
||||
}
|
||||
|
||||
$appbox = $this->app['phraseanet.appbox'];
|
||||
|
||||
$flagNamesMap = $this->getFlagsKey($appbox);
|
||||
// Get flags rules
|
||||
$flagRules = $this->getFlagsRules($appbox, $acl, $grantedCollections);
|
||||
// Get intersection between collection ACLs and collection chosen by end user
|
||||
$aclRules = $this->getACLsByCollection($flagRules, $flagNamesMap);
|
||||
|
||||
return $this->buildACLsFilters($aclRules, $options);
|
||||
return $sort;
|
||||
}
|
||||
|
||||
private function createQueryFilters(SearchEngineOptions $options)
|
||||
@@ -600,27 +437,6 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
return $filters;
|
||||
}
|
||||
|
||||
private function createSortQueryParams(SearchEngineOptions $options)
|
||||
{
|
||||
$sort = [];
|
||||
|
||||
if ($options->getSortBy() === null || $options->getSortBy() === SearchEngineOptions::SORT_RELEVANCE) {
|
||||
$sort['_score'] = $options->getSortOrder();
|
||||
} elseif ($options->getSortBy() === SearchEngineOptions::SORT_CREATED_ON) {
|
||||
$sort['created_on'] = $options->getSortOrder();
|
||||
} elseif ($options->getSortBy() === 'recordid') {
|
||||
$sort['record_id'] = $options->getSortOrder();
|
||||
} else {
|
||||
$sort[sprintf('caption.%s', $options->getSortBy())] = $options->getSortOrder();
|
||||
}
|
||||
|
||||
if (! array_key_exists('record_id', $sort)) {
|
||||
$sort['record_id'] = $options->getSortOrder();
|
||||
}
|
||||
|
||||
return $sort;
|
||||
}
|
||||
|
||||
private function getFlagsKey(\appbox $appbox)
|
||||
{
|
||||
$flags = [];
|
||||
@@ -635,6 +451,32 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
return $flags;
|
||||
}
|
||||
|
||||
private function createACLFilters(SearchEngineOptions $options)
|
||||
{
|
||||
// No ACLs if no user
|
||||
if (false === $this->app->getAuthenticator()->isAuthenticated()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$acl = $this->app->getAclForUser($this->app->getAuthenticatedUser());
|
||||
|
||||
$grantedCollections = array_keys($acl->get_granted_base([\ACL::ACTIF]));
|
||||
|
||||
if (count($grantedCollections) === 0) {
|
||||
return ['bool' => ['must_not' => ['match_all' => new \stdClass()]]];
|
||||
}
|
||||
|
||||
$appbox = $this->app['phraseanet.appbox'];
|
||||
|
||||
$flagNamesMap = $this->getFlagsKey($appbox);
|
||||
// Get flags rules
|
||||
$flagRules = $this->getFlagsRules($appbox, $acl, $grantedCollections);
|
||||
// Get intersection between collection ACLs and collection chosen by end user
|
||||
$aclRules = $this->getACLsByCollection($flagRules, $flagNamesMap);
|
||||
|
||||
return $this->buildACLsFilters($aclRules, $options);
|
||||
}
|
||||
|
||||
private function getFlagsRules(\appbox $appbox, \ACL $acl, array $collections)
|
||||
{
|
||||
$rules = [];
|
||||
@@ -766,4 +608,166 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private function buildHighlightRules(QueryContext $context)
|
||||
{
|
||||
$highlighted_fields = [];
|
||||
foreach ($context->getHighlightedFields() as $field) {
|
||||
switch ($field->getType()) {
|
||||
case FieldMapping::TYPE_STRING:
|
||||
$index_field = $field->getIndexField();
|
||||
$raw_index_field = $field->getIndexField(true);
|
||||
$highlighted_fields[$index_field . ".light"] = [
|
||||
// Requires calling Mapping::enableTermVectors() on this field mapping
|
||||
// 'matched_fields' => [$index_field, $raw_index_field],
|
||||
'type' => 'fvh',
|
||||
];
|
||||
break;
|
||||
case FieldMapping::TYPE_FLOAT:
|
||||
case FieldMapping::TYPE_DOUBLE:
|
||||
case FieldMapping::TYPE_INTEGER:
|
||||
case FieldMapping::TYPE_LONG:
|
||||
case FieldMapping::TYPE_SHORT:
|
||||
case FieldMapping::TYPE_BYTE:
|
||||
continue;
|
||||
case FieldMapping::TYPE_DATE:
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'pre_tags' => ['[[em]]'],
|
||||
'post_tags' => ['[[/em]]'],
|
||||
'order' => 'score',
|
||||
'fields' => $highlighted_fields
|
||||
];
|
||||
}
|
||||
|
||||
private function getAggregationQueryParams(SearchEngineOptions $options)
|
||||
{
|
||||
$aggs = [];
|
||||
// technical aggregates (enable + optional limit)
|
||||
foreach (ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) {
|
||||
$size = $this->options->getAggregableFieldLimit($k);
|
||||
if ($size !== databox_field::FACET_DISABLED) {
|
||||
if ($size === databox_field::FACET_NO_LIMIT) {
|
||||
$size = ESField::FACET_NO_LIMIT;
|
||||
}
|
||||
$agg = [
|
||||
'terms' => [
|
||||
'field' => $f['field'],
|
||||
'size' => $size
|
||||
]
|
||||
];
|
||||
$aggs[$k] = $agg;
|
||||
}
|
||||
}
|
||||
// fields aggregates
|
||||
$structure = $this->context_factory->getLimitedStructure($options);
|
||||
foreach ($structure->getFacetFields() as $name => $field) {
|
||||
// 2015-05-26 (mdarse) Removed databox filtering.
|
||||
// It was already done by the ACL filter in the query scope, so no
|
||||
// document that shouldn't be displayed can go this far.
|
||||
$agg = [
|
||||
'terms' => [
|
||||
'field' => $field->getIndexField(true),
|
||||
'size' => $field->getFacetValuesLimit()
|
||||
]
|
||||
];
|
||||
$aggs[$name] = AggregationHelper::wrapPrivateFieldAggregation($field, $agg);
|
||||
}
|
||||
|
||||
return $aggs;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function autocomplete($query, SearchEngineOptions $options)
|
||||
{
|
||||
$params = $this->createCompletionParams($query, $options);
|
||||
|
||||
$res = $this->client->suggest($params);
|
||||
|
||||
$ret = [
|
||||
'text' => [],
|
||||
'byField' => []
|
||||
];
|
||||
foreach (array_keys($params['body']) as $fname) {
|
||||
$t = [];
|
||||
foreach ($res[$fname] as $suggest) { // don't know why there is a sub-array level
|
||||
foreach ($suggest['options'] as $option) {
|
||||
$text = $option['text'];
|
||||
if (!in_array($text, $ret['text'])) {
|
||||
$ret['text'][] = $text;
|
||||
}
|
||||
$t[] = [
|
||||
'label' => $text,
|
||||
'query' => $fname . ':' . $text
|
||||
];
|
||||
}
|
||||
}
|
||||
if (!empty($t)) {
|
||||
$ret['byField'][$fname] = $t;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function createCompletionParams($query, SearchEngineOptions $options)
|
||||
{
|
||||
$body = [];
|
||||
$context = [
|
||||
'record_type' => $options->getSearchType() === SearchEngineOptions::RECORD_RECORD ?
|
||||
SearchEngineInterface::GEM_TYPE_RECORD : SearchEngineInterface::GEM_TYPE_STORY
|
||||
];
|
||||
|
||||
$base_ids = $options->getBasesIds();
|
||||
if (count($base_ids) > 0) {
|
||||
$context['base_id'] = $base_ids;
|
||||
}
|
||||
|
||||
$search_context = $this->context_factory->createContext($options);
|
||||
$fields = $search_context->getUnrestrictedFields();
|
||||
foreach ($fields as $field) {
|
||||
if ($field->getType() == FieldMapping::TYPE_STRING) {
|
||||
$k = '' . $field->getName();
|
||||
$body[$k] = [
|
||||
'text' => $query,
|
||||
'completion' => [
|
||||
'field' => "caption." . $field->getName() . ".suggest",
|
||||
'context' => &$context
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'index' => $this->indexName,
|
||||
'body' => $body
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function resetCache()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearCache()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function clearAllCache(\DateTime $date = null)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@@ -32,8 +32,11 @@ class ElasticsearchRecordHydrator
|
||||
if (substr($key, 0, strlen($prefix)) == $prefix) {
|
||||
$key = substr($key, strlen($prefix));
|
||||
}
|
||||
if (substr($key, -6) == '.light') {
|
||||
$key = substr($key, 0, strlen($key) - 6);
|
||||
$highlight[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$record = new ElasticsearchRecord();
|
||||
|
||||
|
@@ -47,12 +47,36 @@ class PhraseanetExtension extends \Twig_Extension
|
||||
new \Twig_SimpleFunction('record_flags', array($this, 'getRecordFlags')),
|
||||
new \Twig_SimpleFunction('border_checker_from_fqcn', array($this, 'getCheckerFromFQCN')),
|
||||
new \Twig_SimpleFunction('caption_field', array($this, 'getCaptionField')),
|
||||
new \Twig_SimpleFunction('caption_field_label', array($this, 'getCaptionFieldLabel')),
|
||||
new \Twig_SimpleFunction('caption_field_order', array($this, 'getCaptionFieldOrder')),
|
||||
|
||||
new \Twig_SimpleFunction('flag_slugify', array(Flag::class, 'normalizeName')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get localized field's label
|
||||
* @param RecordInterface $record
|
||||
* @param $fieldName
|
||||
* @return string - the name label
|
||||
*/
|
||||
public function getCaptionFieldLabel(RecordInterface $record, $fieldName)
|
||||
{
|
||||
if ($record) {
|
||||
/** @var \appbox $appbox */
|
||||
$appbox = $this->app['phraseanet.appbox'];
|
||||
$databox = $appbox->get_databox($record->getDataboxId());
|
||||
foreach ($databox->get_meta_structure() as $meta) {
|
||||
/** @var \databox_field $meta */
|
||||
if ($meta->get_name() === $fieldName) {
|
||||
return $meta->get_label($this->app['locale']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function getCaptionField(RecordInterface $record, $field, $value)
|
||||
{
|
||||
if ($record instanceof ElasticsearchRecord) {
|
||||
@@ -99,6 +123,31 @@ class PhraseanetExtension extends \Twig_Extension
|
||||
return $orders[$databoxId][$orderKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \databox $databox
|
||||
* @return array
|
||||
*/
|
||||
private function retrieveDataboxFieldOrderings(\databox $databox)
|
||||
{
|
||||
$publicOrder = [];
|
||||
$businessOrder = [];
|
||||
|
||||
foreach ($databox->get_meta_structure() as $field) {
|
||||
$fieldName = $field->get_name();
|
||||
|
||||
if (!$field->isBusiness()) {
|
||||
$publicOrder[] = $fieldName;
|
||||
}
|
||||
|
||||
$businessOrder[] = $fieldName;
|
||||
};
|
||||
|
||||
return [
|
||||
'public' => $publicOrder,
|
||||
'business' => $businessOrder,
|
||||
];
|
||||
}
|
||||
|
||||
public function getRecordFlags(RecordInterface $record)
|
||||
{
|
||||
$recordStatuses = [];
|
||||
@@ -132,24 +181,6 @@ class PhraseanetExtension extends \Twig_Extension
|
||||
return $recordStatuses;
|
||||
}
|
||||
|
||||
public function isGrantedOnDatabox($databoxId, $rights)
|
||||
{
|
||||
if (false === ($this->app->getAuthenticatedUser() instanceof User)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$rights = (array) $rights;
|
||||
foreach ($rights as $right) {
|
||||
if (false === $this->app->getAclForUser($this->app->getAuthenticatedUser())->has_right_on_sbas($databoxId, $right)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns true if user is authenticated and has all the passed rights on the base
|
||||
* todo : wtf $rights is an array since it's never called with more than 1 right in it ?
|
||||
@@ -177,6 +208,24 @@ class PhraseanetExtension extends \Twig_Extension
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isGrantedOnDatabox($databoxId, $rights)
|
||||
{
|
||||
if (false === ($this->app->getAuthenticatedUser() instanceof User)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$rights = (array)$rights;
|
||||
foreach ($rights as $right) {
|
||||
if (false === $this->app->getAclForUser($this->app->getAuthenticatedUser())->has_right_on_sbas($databoxId, $right)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getCollectionLogo($baseId)
|
||||
{
|
||||
if (false === $this->app['filesystem']->exists(sprintf('%s/config/minilogos/%s', $this->app['root.path'], $baseId))) {
|
||||
@@ -242,11 +291,6 @@ class PhraseanetExtension extends \Twig_Extension
|
||||
return $this->getSubdefUrl($record, 'thumbnail');
|
||||
}
|
||||
|
||||
public function getThumbnailGifUrl(RecordInterface $record)
|
||||
{
|
||||
return $this->getSubdefUrl($record, 'thumbnailgif');
|
||||
}
|
||||
|
||||
public function getSubdefUrl(RecordInterface $record, $subdefName)
|
||||
{
|
||||
/** @var StaticMode $staticMode */
|
||||
@@ -279,6 +323,11 @@ class PhraseanetExtension extends \Twig_Extension
|
||||
return $path;
|
||||
}
|
||||
|
||||
public function getThumbnailGifUrl(RecordInterface $record)
|
||||
{
|
||||
return $this->getSubdefUrl($record, 'thumbnailgif');
|
||||
}
|
||||
|
||||
public function getSubdefSize(RecordInterface $record, $subdefName)
|
||||
{
|
||||
$ret = null;
|
||||
@@ -325,29 +374,4 @@ class PhraseanetExtension extends \Twig_Extension
|
||||
{
|
||||
return 'phraseanet';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \databox $databox
|
||||
* @return array
|
||||
*/
|
||||
private function retrieveDataboxFieldOrderings(\databox $databox)
|
||||
{
|
||||
$publicOrder = [];
|
||||
$businessOrder = [];
|
||||
|
||||
foreach ($databox->get_meta_structure() as $field) {
|
||||
$fieldName = $field->get_name();
|
||||
|
||||
if (!$field->isBusiness()) {
|
||||
$publicOrder[] = $fieldName;
|
||||
}
|
||||
|
||||
$businessOrder[] = $fieldName;
|
||||
};
|
||||
|
||||
return [
|
||||
'public' => $publicOrder,
|
||||
'business' => $businessOrder,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2018-04-16T07:02:10Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<file date="2018-05-23T10:45:26Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="translated">Bitte geben Sie diesselbe Passwörter ein.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore" approved="yes">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2018-04-16T07:02:50Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<file date="2018-05-23T10:47:03Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="translated">Please provide the same passwords.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore" approved="yes">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2018-04-16T07:03:37Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<file date="2018-05-23T10:48:47Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="translated">Veuillez indiquer des mots de passe identiques.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore" approved="yes">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2018-04-16T07:04:28Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<file date="2018-05-23T10:50:41Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="new">Please provide the same passwords.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -55,7 +55,7 @@ $(function () {
|
||||
$('#fileupload').fileupload({
|
||||
dataType: 'html',
|
||||
add: function(e, data) {
|
||||
if( ! /(\.|\/)(csv|rtf)$/i.test(data.files[0].type)) {
|
||||
if( ! /(\.|\/)(csv|rtf)$/i.test(data.files[0].name)) {
|
||||
{% set supported_file_types = ['csv', 'rtf']|join(' | ') %}
|
||||
alert("{{ 'Invalid file type, only (%supported_file_types%) file formats are supported' | trans({'%supported_file_types%' : supported_file_types}) | e('js') }}");
|
||||
|
||||
|
@@ -93,9 +93,9 @@
|
||||
{% set terms = [] %}
|
||||
{% for data in field.values %}
|
||||
{% if data.from_thesaurus and bounceable %}
|
||||
{% set value = data.value|e|bounce(field.name, data.qjs, field.sbas_id) %}
|
||||
{% set value = data.value|e|bounce(field.name, data.qjs, field.sbas_id)|parseColor %}
|
||||
{% else %}
|
||||
{% set value = data.value|e %}
|
||||
{% set value = data.value|e|parseColor %}
|
||||
{% endif %}
|
||||
{% set terms = [value]|merge(terms) %}
|
||||
{% endfor %}
|
||||
@@ -126,9 +126,9 @@
|
||||
|
||||
{% macro caption(record, can_see_business, display_exif, limitedWidth = false) %}
|
||||
<dl class="{% if limitedWidth %}{% else %}dl-horizontal{% endif %}">
|
||||
{% for field in record.get_caption().get_highlight_fields(null, can_see_business) %}
|
||||
<dt>{{ field.label_name }}</dt>
|
||||
<dd>{{ _self.caption_value(field, bounceable|default(true))|highlight|linkify }}</dd>
|
||||
{% for name, value in record.getCaption(caption_field_order(record, can_see_business)) %}
|
||||
<dt>{{ caption_field_label(record, name) }}</dt>
|
||||
<dd>{{ caption_field(record, name, value)|e|highlight|linkify|parseColor }}</dd>
|
||||
{% endfor %}
|
||||
</dl>
|
||||
{% if display_exif|default(true) and app.getAuthenticator().user is not none and user_setting('technical_display') == 'group' %}
|
||||
|
@@ -128,7 +128,7 @@
|
||||
{% else %}
|
||||
<a target="_blank" href="{{ path('account') }}" title="{{ 'login:: Mon compte' | trans }}">
|
||||
<span>
|
||||
{{app.getAuthenticatedUser().getLogin()}}
|
||||
{{ app.getAuthenticatedUser().getDisplayName() }}
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
@@ -18,6 +18,10 @@
|
||||
<input type="radio" name="lay" value="previewCaptionTdm" id="RADI_PRE_TDM" />
|
||||
{{ 'print:: image de choix et description avec planche contact' | trans }}
|
||||
</label>
|
||||
<label for="RADI_CAP" class="radio">
|
||||
<input type="radio" name="lay" value="caption" id="RADI_CAP" />
|
||||
{{ 'print:: description' | trans }}
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if printer.get_count_thumbnail() > 0 %}
|
||||
|
@@ -24,7 +24,7 @@
|
||||
{% set can_see_business = granted_on_collection(record.baseId, [constant('\\ACL::CANMODIFRECORD')]) %}
|
||||
|
||||
<div class="thumb captionTips"
|
||||
{% if settings.rollover_thumbnail == 'caption' %}tooltipsrc="{{ path('prod_tooltip_caption', { 'sbas_id' : record.databoxId, 'record_id' : record.recordId, 'context' : 'answer', 'number' : record.position|default(0) }) }}"{% endif %}
|
||||
{% if settings.rollover_thumbnail == 'caption' %}title="{{ macro.caption(record, can_see_business, false) | e }}"{% endif %}
|
||||
{% if settings.rollover_thumbnail == 'preview' %}tooltipsrc="{{ path('prod_tooltip_preview', { 'sbas_id' : record.databoxId, 'record_id' : record.recordId }) }}"{% endif %}
|
||||
style="height:{{ settings.images_size }}px; z-index:90;">
|
||||
<div class="doc_infos">
|
||||
|
Reference in New Issue
Block a user