Merge branch 'master' into PHRAS-2680-webhook-privacy-and-security

This commit is contained in:
Nicolas Maillat
2019-11-26 17:46:31 +01:00
committed by GitHub
84 changed files with 3445 additions and 1777 deletions

View File

@@ -123,8 +123,8 @@ workflows:
dockerfile: Dockerfile dockerfile: Dockerfile
extra-build-args: "--target phraseanet-fpm" extra-build-args: "--target phraseanet-fpm"
region: AWS_DEFAULT_REGION region: AWS_DEFAULT_REGION
repo: "${AWS_RESOURCE_NAME_PREFIX}/phraseanet" repo: "phraseanet-fpm"
tag: "alpha-0.1" tag: "${CIRCLE_BRANCH}"
- aws-ecr/build_and_push_image: - aws-ecr/build_and_push_image:
account-url: AWS_ACCOUNT_URL account-url: AWS_ACCOUNT_URL
aws-access-key-id: AWS_ACCESS_KEY_ID aws-access-key-id: AWS_ACCESS_KEY_ID
@@ -134,8 +134,8 @@ workflows:
dockerfile: Dockerfile dockerfile: Dockerfile
extra-build-args: "--target phraseanet-nginx" extra-build-args: "--target phraseanet-nginx"
region: AWS_DEFAULT_REGION region: AWS_DEFAULT_REGION
repo: "${AWS_RESOURCE_NAME_PREFIX}/phraseanet-nginx" repo: "phraseanet-nginx"
tag: "alpha-0.1" tag: "${CIRCLE_BRANCH}"
- aws-ecr/build_and_push_image: - aws-ecr/build_and_push_image:
account-url: AWS_ACCOUNT_URL account-url: AWS_ACCOUNT_URL
aws-access-key-id: AWS_ACCESS_KEY_ID aws-access-key-id: AWS_ACCESS_KEY_ID
@@ -145,5 +145,5 @@ workflows:
dockerfile: Dockerfile dockerfile: Dockerfile
extra-build-args: "--target phraseanet-worker" extra-build-args: "--target phraseanet-worker"
region: AWS_DEFAULT_REGION region: AWS_DEFAULT_REGION
repo: "${AWS_RESOURCE_NAME_PREFIX}/phraseanet" repo: "phraseanet-worker"
tag: "alpha-0.1" tag: "${CIRCLE_BRANCH}"

View File

@@ -86,6 +86,18 @@ COPY grammar /var/alchemy/grammar
COPY templates-profiler /var/alchemy/templates-profiler COPY templates-profiler /var/alchemy/templates-profiler
COPY templates /var/alchemy/templates COPY templates /var/alchemy/templates
COPY tests /var/alchemy/tests COPY tests /var/alchemy/tests
RUN mkdir -p /var/alchemy/Phraseanet/logs \
&& chmod -R 777 /var/alchemy/Phraseanet/logs \
&& mkdir -p /var/alchemy/Phraseanet/cache \
&& chmod -R 777 /var/alchemy/Phraseanet/cache \
&& mkdir -p /var/alchemy/Phraseanet/datas \
&& chmod -R 777 /var/alchemy/Phraseanet/datas \
&& mkdir -p /var/alchemy/Phraseanet/tmp \
&& chmod -R 777 /var/alchemy/Phraseanet/tmp \
&& mkdir -p /var/alchemy/Phraseanet/www/custom \
&& chmod -R 777 /var/alchemy/Phraseanet/www/custom \
&& mkdir -p /var/alchemy/Phraseanet/config \
&& chmod -R 777 /var/alchemy/Phraseanet/config
# Phraseanet # Phraseanet
FROM php:7.0-fpm-stretch as phraseanet-fpm FROM php:7.0-fpm-stretch as phraseanet-fpm
@@ -129,6 +141,23 @@ RUN apt-get update \
&& docker-php-source delete \ && docker-php-source delete \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
&& php -r "unlink('composer-setup.php');"
# Node Installation (node + yarn)
# Reference :
# https://linuxize.com/post/how-to-install-node-js-on-ubuntu-18.04/
# https://yarnpkg.com/lang/en/docs/install/#debian-stable
RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
&& apt install -y nodejs \
&& curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update && apt-get install -y --no-install-recommends yarn \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/
RUN mkdir /entrypoint /var/alchemy \ RUN mkdir /entrypoint /var/alchemy \
&& useradd -u 1000 app \ && useradd -u 1000 app \
&& mkdir -p /home/app/.composer \ && mkdir -p /home/app/.composer \
@@ -136,18 +165,6 @@ RUN mkdir /entrypoint /var/alchemy \
COPY --from=builder --chown=app /var/alchemy /var/alchemy/Phraseanet COPY --from=builder --chown=app /var/alchemy /var/alchemy/Phraseanet
ADD ./docker/phraseanet/ / ADD ./docker/phraseanet/ /
RUN mkdir -p /var/alchemy/Phraseanet/logs \
&& chmod -R 777 /var/alchemy/Phraseanet/logs \
&& mkdir -p /var/alchemy/Phraseanet/cache \
&& chmod -R 777 /var/alchemy/Phraseanet/cache \
&& mkdir -p /var/alchemy/Phraseanet/datas \
&& chmod -R 777 /var/alchemy/Phraseanet/datas \
&& mkdir -p /var/alchemy/Phraseanet/tmp \
&& chmod -R 777 /var/alchemy/Phraseanet/tmp \
&& mkdir -p /var/alchemy/Phraseanet/www/custom \
&& chmod -R 777 /var/alchemy/Phraseanet/www/custom \
&& mkdir -p /var/alchemy/Phraseanet/config \
&& chmod -R 777 /var/alchemy/Phraseanet/config
WORKDIR /var/alchemy/Phraseanet WORKDIR /var/alchemy/Phraseanet
ENTRYPOINT ["/phraseanet-entrypoint.sh"] ENTRYPOINT ["/phraseanet-entrypoint.sh"]
CMD ["/boot.sh"] CMD ["/boot.sh"]

View File

@@ -63,14 +63,16 @@ The docker distribution come with 3 differents containers :
## How to build ## How to build
The three images can be built respectively with these commands : You can build all the images with the following command at the root directory, choosing an arbirary TAG name :
# nginx server ./build.sh <TAG>
docker build --target phraseanet-nginx -t local/phraseanet-nginx .
# php-fpm application It will build and tag the following images :
docker build --target phraseanet-fpm -t local/phraseanet-fpm .
# worker local/phraseanet-worker:<TAG>
docker build --target phraseanet-worker -t local/phraseanet-worker . local/phraseanet-fpm:<TAG>
local/phraseanet-nginx:<TAG>
# Deploy the application
Once the images are built, you can deploy the entire phraseanet stack using the repository : https://github.com/alchemy-fr/phraseanet-docker and follow the instruction inside its `README.md` file.

11
build.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
# nginx server
docker build --target phraseanet-nginx -t local/phraseanet-nginx:$1 .
# php-fpm application
docker build --target phraseanet-fpm -t local/phraseanet-fpm:$1 .
# worker
docker build --target phraseanet-worker -t local/phraseanet-worker:$1 .

0
cache/.gitkeep vendored Normal file
View File

View File

@@ -1,4 +1,6 @@
#!/bin/bash #!/bin/bash
cat nginx.conf.sample | sed "s/\$MAX_BODY_SIZE/$MAX_BODY_SIZE/g" > /etc/nginx/nginx.conf set -xe
cat nginx.conf.sample | sed "s/\$MAX_BODY_SIZE/$MAX_BODY_SIZE/g" > /etc/nginx/conf.d/default.conf
nginx -g "daemon off;" nginx -g "daemon off;"

View File

@@ -0,0 +1,31 @@
user app;
worker_processes 1;
error_log /var/log/ngnix_error.log info;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}

View File

@@ -1,85 +1,39 @@
user app; upstream backend {
worker_processes auto; server phraseanet:9000;
#error_log /var/log/ngnix_error.log info;
error_log /dev/stdout info;
pid /var/run/nginx.pid;
#daemon off;
events {
worker_connections 1024;
multi_accept on;
} }
http { server {
include /etc/nginx/mime.types; listen 80;
default_type application/octet-stream; root /var/alchemy/Phraseanet/www;
server_tokens off;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' index index.php;
'$status $body_bytes_sent "$http_referer" ' client_max_body_size $MAX_BODY_SIZE;
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /dev/stdout main; location /api {
rewrite ^(.*)$ /api.php/$1 last;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
reset_timedout_connection on;
proxy_connect_timeout 300s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
fastcgi_send_timeout 300s;
fastcgi_read_timeout 300;
resolver 127.0.0.11;
upstream backend {
server phraseanet:9000;
} }
server { location / {
listen 80; # First attempt to serve request as file, then
server_name localhost; # as directory, then fall back to index.html
error_log on; try_files $uri $uri/ @rewriteapp;
access_log on; }
root /var/alchemy/Phraseanet/www;
index index.php; location @rewriteapp {
client_max_body_size $MAX_BODY_SIZE; rewrite ^(.*)$ /index.php/$1 last;
}
location /api { # PHP scripts -> PHP-FPM server listening on 127.0.0.1:9000
rewrite ^(.*)$ /api.php/$1 last; location ~ ^/(index|index_dev|api)\.php(/|$) {
} fastcgi_pass backend;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location / { location ~ ^/(status|ping)$ {
# First attempt to serve request as file, then fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# as directory, then fall back to index.html fastcgi_index index.php;
try_files $uri $uri/ @rewriteapp; include fastcgi_params;
} fastcgi_pass backend;
location @rewriteapp {
rewrite ^(.*)$ /index.php/$1 last;
}
# PHP scripts -> PHP-FPM server listening on 127.0.0.1:9000
location ~ ^/(index|index_dev|api)\.php(/|$) {
fastcgi_pass backend;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ ^/(status|ping)$ {
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_pass backend;
}
} }
} }

View File

@@ -2,6 +2,16 @@
set -xe set -xe
if [ $INSTALL_ACCOUNT_EMAIL = ""]; then
echo "INSTALL_ACCOUNT_EMAIL var is not set."
exit 1
fi
if [ $INSTALL_ACCOUNT_PASSWORD = ""]; then
echo "INSTALL_ACCOUNT_PASSWORD var is not set."
exit 1
fi
/var/alchemy/Phraseanet/bin/setup system:install \ /var/alchemy/Phraseanet/bin/setup system:install \
--email=$INSTALL_ACCOUNT_EMAIL \ --email=$INSTALL_ACCOUNT_EMAIL \
--password=$INSTALL_ACCOUNT_PASSWORD \ --password=$INSTALL_ACCOUNT_PASSWORD \

View File

@@ -1,5 +1,11 @@
#!/bin/bash #!/bin/bash
set -xe
chown -R app:app /var/alchemy/Phraseanet/config
chown -R app:app /var/alchemy/Phraseanet/datas
chown -R app:app /var/alchemy/Phraseanet/tmp
chown -R app:app /var/alchemy/Phraseanet/www/thumbnails
FILE=/var/alchemy/Phraseanet/config/configuration.yml FILE=/var/alchemy/Phraseanet/config/configuration.yml
if [ -f "$FILE" ]; then if [ -f "$FILE" ]; then
echo "$FILE exist, skip setup." echo "$FILE exist, skip setup."

View File

@@ -5,4 +5,4 @@ set -e
envsubst < /php.ini.sample > /usr/local/etc/php/php.ini envsubst < /php.ini.sample > /usr/local/etc/php/php.ini
envsubst < /php-fpm.conf.sample > /usr/local/etc/php-fpm.conf envsubst < /php-fpm.conf.sample > /usr/local/etc/php-fpm.conf
docker-php-entrypoint $@ bash -e docker-php-entrypoint $@

View File

@@ -1,3 +1,4 @@
#!/bin/bash #!/bin/bash
mkdir /var/alchemy/Phraseanet/tmp/locks && chown -R app:app /var/alchemy/Phraseanet/tmp
runuser app -c 'php /var/alchemy/Phraseanet/bin/console task-manager:scheduler:run' runuser app -c 'php /var/alchemy/Phraseanet/bin/console task-manager:scheduler:run'

View File

@@ -128,7 +128,7 @@ key:
| quoted_string() | quoted_string()
group: group:
::space::? ::parenthese_:: primary() ::_parenthese:: ::space::? ::space::? ::parenthese_:: ::space::? primary() ::space::? ::_parenthese:: ::space::?
// Thesaurus terms // Thesaurus terms

View File

@@ -73,7 +73,7 @@ class RedisCache extends CacheProvider implements Cache
*/ */
protected function doDelete($id) protected function doDelete($id)
{ {
return $this->_redis->delete($id); return $this->_redis->del($id);
} }
/** /**

View File

@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Command\Setup;
use Alchemy\Phrasea\Command\Command; use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\Core\Configuration\StructureTemplate; use Alchemy\Phrasea\Core\Configuration\StructureTemplate;
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions;
use Doctrine\DBAL\Driver\Connection; use Doctrine\DBAL\Driver\Connection;
use Symfony\Component\Console\Helper\DialogHelper; use Symfony\Component\Console\Helper\DialogHelper;
use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\ArrayInput;
@@ -51,7 +52,9 @@ class Install extends Command
->addOption('db-template', null, InputOption::VALUE_OPTIONAL, 'Databox template (' . $this->structureTemplate->toString() . ')', null) ->addOption('db-template', null, InputOption::VALUE_OPTIONAL, 'Databox template (' . $this->structureTemplate->toString() . ')', null)
->addOption('data-path', null, InputOption::VALUE_OPTIONAL, 'Path to data repository', realpath(__DIR__ . '/../../../../../datas')) ->addOption('data-path', null, InputOption::VALUE_OPTIONAL, 'Path to data repository', realpath(__DIR__ . '/../../../../../datas'))
->addOption('server-name', null, InputOption::VALUE_OPTIONAL, 'Server name') ->addOption('server-name', null, InputOption::VALUE_OPTIONAL, 'Server name')
->addOption('indexer', null, InputOption::VALUE_OPTIONAL, 'Path to Phraseanet Indexer', 'auto') ->addOption('es-host', null, InputOption::VALUE_OPTIONAL, 'ElasticSearch server HTTP host', 'localhost')
->addOption('es-port', null, InputOption::VALUE_OPTIONAL, 'ElasticSearch server HTTP port', 9200)
->addOption('es-index', null, InputOption::VALUE_OPTIONAL, 'ElasticSearch index name', null)
->addOption('yes', 'y', InputOption::VALUE_NONE, 'Answer yes to all questions'); ->addOption('yes', 'y', InputOption::VALUE_NONE, 'Answer yes to all questions');
return $this; return $this;
@@ -121,6 +124,21 @@ class Install extends Command
list($email, $password) = $this->getCredentials($input, $output, $dialog); list($email, $password) = $this->getCredentials($input, $output, $dialog);
$dataPath = $this->getDataPath($input, $output, $dialog); $dataPath = $this->getDataPath($input, $output, $dialog);
if (! $input->getOption('yes')) {
$output->writeln("<info>--- ElasticSearch connection settings ---</info>");
}
list($esHost, $esPort) = $this->getESHost($input, $output, $dialog);
$esIndexName = $this->getESIndexName($input, $output, $dialog);
$esOptions = ElasticsearchOptions::fromArray([
'host' => $esHost,
'port' => $esPort,
'index' => $esIndexName
]);
$output->writeln('');
if (!$input->getOption('yes')) { if (!$input->getOption('yes')) {
$continue = $dialog->askConfirmation($output, "<question>Phraseanet is going to be installed, continue ? (N/y)</question>", false); $continue = $dialog->askConfirmation($output, "<question>Phraseanet is going to be installed, continue ? (N/y)</question>", false);
@@ -132,6 +150,7 @@ class Install extends Command
} }
$this->container['phraseanet.installer']->install($email, $password, $abConn, $serverName, $dataPath, $dbConn, $templateName, $this->detectBinaries()); $this->container['phraseanet.installer']->install($email, $password, $abConn, $serverName, $dataPath, $dbConn, $templateName, $this->detectBinaries());
$this->container['conf']->set(['main', 'search-engine', 'options'], $esOptions->toArray());
if (null !== $this->getApplication()) { if (null !== $this->getApplication()) {
$command = $this->getApplication()->find('crossdomain:generate'); $command = $this->getApplication()->find('crossdomain:generate');
@@ -339,6 +358,35 @@ class Install extends Command
return $serverName; return $serverName;
} }
private function getESHost(InputInterface $input, OutputInterface $output, DialogHelper $dialog)
{
$host = $input->getOption('es-host');
$port = (int) $input->getOption('es-port');
if (! $input->getOption('yes')) {
while (! $host) {
$host = $dialog->ask($output, 'ElasticSearch server host : ', null);
};
while ($port <= 0 || $port >= 65535) {
$port = (int) $dialog->ask($output, 'ElasticSearch server port : ', null);
};
}
return [ $host, $port ];
}
private function getESIndexName(InputInterface $input, OutputInterface $output, DialogHelper $dialog)
{
$index = $input->getOption('es-index');
if (! $input->getOption('yes')) {
$index = $dialog->ask($output, 'ElasticSearch server index name (blank to autogenerate) : ', null);
}
return $index;
}
private function detectBinaries() private function detectBinaries()
{ {
return [ return [

View File

@@ -316,6 +316,7 @@ class FieldsController extends Controller
->set_tbranch($data['tbranch']) ->set_tbranch($data['tbranch'])
->set_generate_cterms($data['generate_cterms']) ->set_generate_cterms($data['generate_cterms'])
->set_gui_editable($data['gui_editable']) ->set_gui_editable($data['gui_editable'])
->set_gui_visible($data['gui_visible'])
->set_report($data['report']) ->set_report($data['report'])
->setVocabularyControl(null) ->setVocabularyControl(null)
->setVocabularyRestricted(false); ->setVocabularyRestricted(false);
@@ -351,7 +352,7 @@ class FieldsController extends Controller
{ {
return [ return [
'name', 'multi', 'thumbtitle', 'tag', 'business', 'indexable', 'aggregable', 'name', 'multi', 'thumbtitle', 'tag', 'business', 'indexable', 'aggregable',
'required', 'separator', 'readonly', 'gui_editable', 'type', 'tbranch', 'generate_cterms', 'report', 'required', 'separator', 'readonly', 'gui_editable', 'gui_visible' , 'type', 'tbranch', 'generate_cterms', 'report',
'vocabulary-type', 'vocabulary-restricted', 'dces-element', 'labels' 'vocabulary-type', 'vocabulary-restricted', 'dces-element', 'labels'
]; ];
} }

View File

@@ -596,6 +596,7 @@ class V1Controller extends Controller
'thesaurus_branch' => $databox_field->get_tbranch(), 'thesaurus_branch' => $databox_field->get_tbranch(),
'generate_cterms' => $databox_field->get_generate_cterms(), 'generate_cterms' => $databox_field->get_generate_cterms(),
'gui_editable' => $databox_field->get_gui_editable(), 'gui_editable' => $databox_field->get_gui_editable(),
'gui_visible' => $databox_field->get_gui_visible(),
'type' => $databox_field->get_type(), 'type' => $databox_field->get_type(),
'indexable' => $databox_field->is_indexable(), 'indexable' => $databox_field->is_indexable(),
'multivalue' => $databox_field->is_multi(), 'multivalue' => $databox_field->is_multi(),

View File

@@ -77,6 +77,7 @@ class EditController extends Controller
'tbranch' => $meta->get_tbranch(), 'tbranch' => $meta->get_tbranch(),
'generate_cterms' => $meta->get_generate_cterms(), 'generate_cterms' => $meta->get_generate_cterms(),
'gui_editable' => $meta->get_gui_editable(), 'gui_editable' => $meta->get_gui_editable(),
'gui_visible' => $meta->get_gui_visible(),
'maxLength' => $meta->get_tag() 'maxLength' => $meta->get_tag()
->getMaxLength(), ->getMaxLength(),
'minLength' => $meta->get_tag() 'minLength' => $meta->get_tag()

View File

@@ -70,7 +70,7 @@ class LazaretController extends Controller
public function getElement($file_id) public function getElement($file_id)
{ {
$ret = ['success' => false, 'message' => '', 'result' => []]; $ret = ['success' => false, 'message' => '', 'result' => []];
/* @var LazaretFile $lazaretFile */ /* @var LazaretFile $lazaretFile */
$lazaretFile = $this->getLazaretFileRepository()->find($file_id); $lazaretFile = $this->getLazaretFileRepository()->find($file_id);
@@ -126,6 +126,16 @@ class LazaretController extends Controller
$ret = $lazaretManipulator->add($file_id, $keepAttributes, $attributesToKeep); $ret = $lazaretManipulator->add($file_id, $keepAttributes, $attributesToKeep);
try{
// get the new record
$record = \Collection::getByBaseId($this->app, $request->request->get('bas_id'))->get_databox()->get_record($ret['result']['record_id']);
$postStatus = (array) $request->request->get('status');
// update status
$this->updateRecordStatus($record, $postStatus);
}catch(\Exception $e){
$ret['message'] = $this->app->trans('An error occured when wanting to change status!');
}
return $this->app->json($ret); return $this->app->json($ret);
} }
@@ -216,6 +226,7 @@ class LazaretController extends Controller
return $this->app->json($ret); return $this->app->json($ret);
} }
$postStatus = (array) $request->request->get('status');
$path = $this->app['tmp.lazaret.path'] . '/'; $path = $this->app['tmp.lazaret.path'] . '/';
$lazaretFileName = $path .$lazaretFile->getFilename(); $lazaretFileName = $path .$lazaretFile->getFilename();
@@ -233,6 +244,9 @@ class LazaretController extends Controller
'' ''
); );
// update status
$this->updateRecordStatus($record, $postStatus);
//Delete lazaret file //Delete lazaret file
$manager = $this->getEntityManager(); $manager = $this->getEntityManager();
$manager->remove($lazaretFile); $manager->remove($lazaretFile);
@@ -278,6 +292,35 @@ class LazaretController extends Controller
); );
} }
/**
* @param Request $request
* @param $databox_id
* @param $record_id
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function getDestinationStatus(Request $request, $databox_id, $record_id)
{
if (!$request->isXmlHttpRequest()) {
$this->app->abort(400);
}
$record = new \record_adapter($this->app, (int) $databox_id, (int) $record_id);
$databox = $this->findDataboxById($databox_id);
$statusStructure = $databox->getStatusStructure();
$recordsStatuses = [];
foreach ($statusStructure as $status) {
// make the key as a string for the json usage in javascript
$bit = "'".$status['bit']."'";
if (!isset($recordsStatuses[$bit])) {
$recordsStatuses[$bit] = $status;
}
$statusSet = \databox_status::bitIsSet($record->getStatusBitField(), $status['bit']);
if (!isset($recordsStatuses[$bit]['flag'])) {
$recordsStatuses[$bit]['flag'] = (int) $statusSet;
}
}
return $this->app->json(['status' => $recordsStatuses]);
}
/** /**
* @return LazaretFileRepository * @return LazaretFileRepository
*/ */
@@ -293,4 +336,32 @@ class LazaretController extends Controller
{ {
return $this->app['border-manager']; return $this->app['border-manager'];
} }
/**
* Set new status to selected record
*
* @param \record_adapter $record
* @param array $postStatus
* @return array|null
*/
private function updateRecordStatus(\record_adapter $record, array $postStatus)
{
$sbasId = $record->getDataboxId();
if (isset($postStatus[$sbasId]) && is_array($postStatus[$sbasId])) {
$postStatus = $postStatus[$sbasId];
$currentStatus = strrev($record->getStatus());
$newStatus = '';
foreach (range(0, 31) as $i) {
$newStatus .= isset($postStatus[$i]) ? ($postStatus[$i] ? '1' : '0') : $currentStatus[$i];
}
$record->setStatus(strrev($newStatus));
$this->getDataboxLogger($record->getDatabox())
->log($record, \Session_Logger::EVENT_STATUS, '', '');
return [
'current_status' => $currentStatus,
'new_status' => $newStatus,
];
}
return null;
}
} }

View File

@@ -341,10 +341,20 @@ class QueryController extends Controller
if ($result->getTotal() === 0) { if ($result->getTotal() === 0) {
$template = 'prod/results/help.html.twig'; $template = 'prod/results/help.html.twig';
} else { }
else {
$template = 'prod/results/records.html.twig'; $template = 'prod/results/records.html.twig';
} }
$json['results'] = $this->render($template, ['results'=> $result]);
/** @var \Closure $filter */
$filter = $this->app['plugin.filter_by_authorization'];
$plugins = [
'workzone' => $filter('workzone'),
'actionbar' => $filter('actionbar'),
];
$json['results'] = $this->render($template, ['results'=> $result, 'plugins'=>$plugins]);
// add technical fields // add technical fields
@@ -382,7 +392,6 @@ class QueryController extends Controller
'labels' => $field->get_labels(), 'labels' => $field->get_labels(),
'type' => $field->get_type(), 'type' => $field->get_type(),
'field' => $field->get_name(), 'field' => $field->get_name(),
'query' => "field." . $field->get_name() . ":%s",
'trans_label' => $field->get_label($this->app['locale']), 'trans_label' => $field->get_label($this->app['locale']),
]; ];
$field->get_label($this->app['locale']); $field->get_label($this->app['locale']);

View File

@@ -82,6 +82,11 @@ class Lazaret implements ControllerProviderInterface, ServiceProviderInterface
->assert('file_id', '\d+') ->assert('file_id', '\d+')
->bind('lazaret_thumbnail'); ->bind('lazaret_thumbnail');
$controllers->get('/{databox_id}/{record_id}/status', 'controller.prod.lazaret:getDestinationStatus')
->assert('databox_id', '\d+')
->assert('record_id', '\d+')
->bind('lazaret_destination_status');
return $controllers; return $controllers;
} }
} }

View File

@@ -38,6 +38,7 @@ final class DbalDataboxFieldRepository implements DataboxFieldRepository
'label_nl', 'label_nl',
'generate_cterms', 'generate_cterms',
'gui_editable', 'gui_editable',
'gui_visible',
]; ];
/** @var DataboxFieldFactory */ /** @var DataboxFieldFactory */

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\Model\Entities; namespace Alchemy\Phrasea\Model\Entities;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\Attribute\AttributeInterface;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo; use Gedmo\Mapping\Annotation as Gedmo;
use \record_adapter; use \record_adapter;
@@ -474,4 +475,32 @@ class LazaretFile
return $merged; return $merged;
} }
/**
* @param Application $app
* @return array|null
*/
public function getStatus(Application $app)
{
/**@var LazaretAttribute $atribute*/
foreach ($this->attributes as $atribute) {
if ($atribute->getName() == AttributeInterface::NAME_STATUS) {
$databox = $this->getCollection($app)->get_databox();
$statusStructure = $databox->getStatusStructure();
$recordsStatuses = [];
foreach ($statusStructure as $status) {
$bit = $status['bit'];
if (!isset($recordsStatuses[$bit])) {
$recordsStatuses[$bit] = $status;
}
$statusSet = \databox_status::bitIsSet(bindec($atribute->getValue()), $bit);
if (!isset($recordsStatuses[$bit]['flag'])) {
$recordsStatuses[$bit]['flag'] = (int) $statusSet;
}
}
return $recordsStatuses;
}
}
return null;
}
} }

View File

@@ -226,6 +226,8 @@ class LazaretManipulator
$this->entityManager->remove($lazaretFile); $this->entityManager->remove($lazaretFile);
$this->entityManager->flush(); $this->entityManager->flush();
$ret['result']['record_id'] = $record->getRecordId();
$ret['success'] = true; $ret['success'] = true;
} catch (\Exception $e) { } catch (\Exception $e) {
$ret['message'] = $this->app->trans('An error occured'); $ret['message'] = $this->app->trans('An error occured');

View File

@@ -45,6 +45,9 @@ class TextNode extends AbstractTermNode implements ContextAbleInterface
foreach ($context->localizeField($field) as $f) { foreach ($context->localizeField($field) as $f) {
$index_fields[] = $f; $index_fields[] = $f;
} }
foreach ($context->truncationField($field) as $f) {
$index_fields[] = $f;
}
} }
if (!$index_fields) { if (!$index_fields) {
return null; return null;

View File

@@ -323,7 +323,7 @@ class ElasticsearchOptions
"aggregated (2 values: fired = 0 or 1)" => -1, "aggregated (2 values: fired = 0 or 1)" => -1,
], ],
'output_formatter' => function($value) { 'output_formatter' => function($value) {
static $map = ['0'=>"No flash", '1'=>"Flash"]; static $map = ["false"=>"No flash", "true"=>"Flash", '0'=>"No flash", '1'=>"Flash"];
return array_key_exists($value, $map) ? $map[$value] : $value; return array_key_exists($value, $map) ? $map[$value] : $value;
}, },
], ],

View File

@@ -90,6 +90,16 @@ class Index
// TODO Maybe replace nfkc_normalizer + asciifolding with icu_folding // TODO Maybe replace nfkc_normalizer + asciifolding with icu_folding
'filter' => ['nfkc_normalizer', 'asciifolding'] 'filter' => ['nfkc_normalizer', 'asciifolding']
], ],
'truncation_analyzer' => [
'type' => 'custom',
'tokenizer' => 'truncation_tokenizer',
'filter' => ['lowercase', 'stop', 'kstem']
],
'truncation_analyzer#search' => [
'type' => 'custom',
'tokenizer' => 'truncation_tokenizer',
'filter' => ['lowercase', 'stop', 'kstem']
],
// Lang specific // Lang specific
'fr_full' => [ 'fr_full' => [
'type' => 'custom', 'type' => 'custom',
@@ -145,6 +155,12 @@ class Index
] ]
], ],
'tokenizer' => [ 'tokenizer' => [
'truncation_tokenizer' => [
"type" => "edgeNGram",
"min_gram" => "2",
"max_gram" => "15",
"token_chars" => [ "letter", "digit", "punctuation", "symbol" ]
],
'thesaurus_path' => [ 'thesaurus_path' => [
'type' => 'path_hierarchy' 'type' => 'path_hierarchy'
] ]

View File

@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Indexer\Record\Hydrator;
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\Exception; use Alchemy\Phrasea\SearchEngine\Elastic\Exception\Exception;
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper; use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\GlobalStructure;
use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus; use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus;
use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus\CandidateTerms; use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus\CandidateTerms;
use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus\Concept; use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus\Concept;
@@ -27,7 +28,7 @@ class ThesaurusHydrator implements HydratorInterface
private $thesaurus; private $thesaurus;
private $candidate_terms; private $candidate_terms;
public function __construct(Structure $structure, Thesaurus $thesaurus, CandidateTerms $candidate_terms) public function __construct(GlobalStructure $structure, Thesaurus $thesaurus, CandidateTerms $candidate_terms)
{ {
$this->structure = $structure; $this->structure = $structure;
$this->thesaurus = $thesaurus; $this->thesaurus = $thesaurus;
@@ -67,7 +68,13 @@ class ThesaurusHydrator implements HydratorInterface
$terms = array(); $terms = array();
$filters = array(); $filters = array();
$field_names = array(); $field_names = array();
/** @var Field[] $dbFields */
$dbFields = $this->structure->getAllFieldsByDatabox($record['databox_id']);
foreach ($fields as $name => $field) { foreach ($fields as $name => $field) {
if(!array_key_exists($name, $dbFields) || !$dbFields[$name]->get_generate_cterms()) {
continue;
}
$root_concepts = $field->getThesaurusRoots(); $root_concepts = $field->getThesaurusRoots();
// Loop through all values to prepare bulk query // Loop through all values to prepare bulk query
$field_values = \igorw\get_in($record, explode('.', $index_fields[$name])); $field_values = \igorw\get_in($record, explode('.', $index_fields[$name]));
@@ -98,10 +105,7 @@ class ThesaurusHydrator implements HydratorInterface
} }
} }
else { else {
$field = $fields[$name]; $this->candidate_terms->insert($field_names[$offset], $values[$offset]);
if($field->get_generate_cterms()) {
$this->candidate_terms->insert($field_names[$offset], $values[$offset]);
}
} }
} }
} }

View File

@@ -55,8 +55,13 @@ class StringFieldMapping extends ComplexFieldMapping
{ {
$child = new StringFieldMapping('light'); $child = new StringFieldMapping('light');
$child->setAnalyzer('general_light'); $child->setAnalyzer('general_light');
$this->addChild($child); $this->addChild($child);
$child = new StringFieldMapping('truncated');
$child->setAnalyzer('truncation_analyzer', 'indexing');
$child->setAnalyzer('truncation_analyzer#search', 'searching');
$this->addChild($child);
$this->addLocalizedChildren($locales); $this->addLocalizedChildren($locales);
return $this; return $this;

View File

@@ -4,6 +4,11 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
class Escaper class Escaper
{ {
public function quoteWord($value)
{
return '"' . $this->escapeRaw($value) . '"';
}
public function escapeWord($value) public function escapeWord($value)
{ {
// Strip double quotes from values to prevent broken queries // Strip double quotes from values to prevent broken queries

View File

@@ -46,22 +46,23 @@ class FacetsResponse
if (!isset($bucket['key']) || !isset($bucket['doc_count'])) { if (!isset($bucket['key']) || !isset($bucket['doc_count'])) {
$this->throwAggregationResponseError(); $this->throwAggregationResponseError();
} }
$key = array_key_exists('key_as_string', $bucket) ? $bucket['key_as_string'] : $bucket['key'];
if($tf) { if($tf) {
// the field is one of the hardcoded tech fields // the field is one of the hardcoded tech fields
$value = [ $value = [
'value' => $valueFormatter($bucket['key']), 'value' => $valueFormatter($key),
'raw_value' => $bucket['key'], 'raw_value' => $key,
'count' => $bucket['doc_count'], 'count' => $bucket['doc_count'],
'query' => sprintf($tf['query'], $this->escaper->escapeWord($bucket['key'])) 'query' => sprintf($tf['query'], $this->escaper->escapeWord($key))
]; ];
} }
else { else {
// the field is a normal field // the field is a normal field
$value = [ $value = [
'value' => $bucket['key'], 'value' => $key,
'raw_value' => $bucket['key'], 'raw_value' => $key,
'count' => $bucket['doc_count'], 'count' => $bucket['doc_count'],
'query' => sprintf('field.%s:%s', $this->escaper->escapeWord($name), $this->escaper->escapeWord($bucket['key'])) 'query' => sprintf('field.%s=%s', $this->escaper->escapeWord($name), $this->escaper->quoteWord($key))
]; ];
} }

View File

@@ -9,6 +9,7 @@ use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Field;
use Alchemy\Phrasea\SearchEngine\Elastic\AST\Field as ASTField; use Alchemy\Phrasea\SearchEngine\Elastic\AST\Field as ASTField;
use Alchemy\Phrasea\SearchEngine\Elastic\AST\Flag; use Alchemy\Phrasea\SearchEngine\Elastic\AST\Flag;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure; use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
/** /**
* @todo Check for private fields and only search on them if allowed * @todo Check for private fields and only search on them if allowed
@@ -23,13 +24,23 @@ class QueryContext
private $queryLocale; private $queryLocale;
/** @var array */ /** @var array */
private $fields; private $fields;
/** @var SearchEngineOptions */
private $options;
public function __construct(Structure $structure, array $locales, $queryLocale, array $fields = null) /**
* @param SearchEngineOptions|null $options
* @param Structure $structure
* @param array $locales
* @param $queryLocale
* @param array $fields
*/
public function __construct($options, Structure $structure, array $locales, $queryLocale, array $fields = null)
{ {
$this->structure = $structure; $this->structure = $structure;
$this->locales = $locales; $this->locales = $locales;
$this->queryLocale = $queryLocale; $this->queryLocale = $queryLocale;
$this->fields = $fields; $this->fields = $fields;
$this->options = $options;
} }
public function narrowToFields(array $fields) public function narrowToFields(array $fields)
@@ -43,7 +54,7 @@ class QueryContext
} }
} }
return new static($this->structure, $this->locales, $this->queryLocale, $fields); return new static($this->options, $this->structure, $this->locales, $this->queryLocale, $fields);
} }
/** /**
@@ -131,6 +142,16 @@ class QueryContext
return $ret; return $ret;
} }
public function truncationField(Field $field)
{
if($this->options && $this->options->useTruncation()) {
return [sprintf('%s.truncated', $field->getIndexField())];
}
else {
return [];
}
}
private function localizeFieldName($field) private function localizeFieldName($field)
{ {
$fields = array(); $fields = array();

View File

@@ -23,7 +23,7 @@ class QueryContextFactory
? $this->getLimitedStructure($options) ? $this->getLimitedStructure($options)
: $this->structure; : $this->structure;
$context = new QueryContext($structure, $this->locales, $this->current_locale); $context = new QueryContext($options, $structure, $this->locales, $this->current_locale);
if ($options) { if ($options) {
$fields = $this->getSearchedFields($options); $fields = $this->getSearchedFields($options);

View File

@@ -63,4 +63,26 @@ class StringUtils
return self::$transliterator->transliterate($string); return self::$transliterator->transliterate($string);
} }
/**
* replace bad chars (ascii 0...31 except 9,10,13)
*
* @param $s
* @param string $replace
* @return mixed
*/
public static function substituteCtrlCharacters($s, $replace = '_')
{
static $bad_chars = null;
if($bad_chars === null) {
$bad_chars = [];
for($i=0; $i<32; $i++) {
if($i != 9 && $i != 10 && $i != 13) {
$bad_chars[] = chr($i);
}
}
}
return str_replace($bad_chars, $replace, $s);
}
} }

View File

@@ -24,6 +24,11 @@ class Field implements Typed
*/ */
private $name; private $name;
/**
* @var int
*/
private $databox_id;
/** /**
* @var string * @var string
*/ */
@@ -73,6 +78,7 @@ class Field implements Typed
} }
return new self($field->get_name(), $type, [ return new self($field->get_name(), $type, [
'databox_id' => $databox->get_sbas_id(),
'searchable' => $field->is_indexable(), 'searchable' => $field->is_indexable(),
'private' => $field->isBusiness(), 'private' => $field->isBusiness(),
'facet' => $facet, 'facet' => $facet,
@@ -102,6 +108,7 @@ class Field implements Typed
{ {
$this->name = (string) $name; $this->name = (string) $name;
$this->type = $type; $this->type = $type;
$this->databox_id = \igorw\get_in($options, ['databox_id'], 0);
$this->is_searchable = \igorw\get_in($options, ['searchable'], true); $this->is_searchable = \igorw\get_in($options, ['searchable'], true);
$this->is_private = \igorw\get_in($options, ['private'], false); $this->is_private = \igorw\get_in($options, ['private'], false);
$this->facet = \igorw\get_in($options, ['facet']); $this->facet = \igorw\get_in($options, ['facet']);
@@ -126,6 +133,7 @@ class Field implements Typed
public function withOptions(array $options) public function withOptions(array $options)
{ {
return new self($this->name, $this->type, $options + [ return new self($this->name, $this->type, $options + [
'databox_id' => $this->databox_id,
'searchable' => $this->is_searchable, 'searchable' => $this->is_searchable,
'private' => $this->is_private, 'private' => $this->is_private,
'facet' => $this->facet, 'facet' => $this->facet,
@@ -155,6 +163,11 @@ class Field implements Typed
return sprintf('concept_path.%s', $this->name); return sprintf('concept_path.%s', $this->name);
} }
public function get_databox_id()
{
return $this->databox_id;
}
public function getType() public function getType()
{ {
return $this->type; return $this->type;

View File

@@ -14,6 +14,12 @@ final class GlobalStructure implements Structure
*/ */
private $fields = array(); private $fields = array();
/**
* @var Field[][]
*/
private $fieldsByDatabox = [];
/** /**
* @var Field[] * @var Field[]
* */ * */
@@ -119,6 +125,10 @@ final class GlobalStructure implements Structure
public function add(Field $field) public function add(Field $field)
{ {
// store info for each field, not still merged by databox
$this->fieldsByDatabox[$field->get_databox_id()][$field->getName()] = $field;
// store merged infos (same field name)
$name = $field->getName(); $name = $field->getName();
if (isset($this->fields[$name])) { if (isset($this->fields[$name])) {
@@ -152,6 +162,11 @@ final class GlobalStructure implements Structure
return $this->fields; return $this->fields;
} }
public function getAllFieldsByDatabox($databox_id)
{
return $this->fieldsByDatabox[$databox_id];
}
/** /**
* @return Field[] * @return Field[]
*/ */

View File

@@ -32,6 +32,7 @@ class CandidateTerms
public function insert($field, $value) public function insert($field, $value)
{ {
$value = StringUtils::substituteCtrlCharacters($value, '');
$this->ensureVisitorSetup(); $this->ensureVisitorSetup();
if (!$this->visitor->hasTerm($field, $value)) { if (!$this->visitor->hasTerm($field, $value)) {
$this->new_candidates[$value] = $field; $this->new_candidates[$value] = $field;

View File

@@ -71,6 +71,8 @@ class SearchEngineOptions
protected $i18n; protected $i18n;
/** @var bool */ /** @var bool */
protected $stemming = true; protected $stemming = true;
/** @var bool */
protected $use_truncation = false;
/** @var string */ /** @var string */
protected $sort_by; protected $sort_by;
@@ -105,7 +107,8 @@ class SearchEngineOptions
'sort_ord', 'sort_ord',
'business_fields', 'business_fields',
'max_results', 'max_results',
'first_result' 'first_result',
'use_truncation',
]; ];
/** /**
@@ -217,6 +220,29 @@ class SearchEngineOptions
return $this; return $this;
} }
/**
* Tells whether to use truncation or not
*
* @param boolean $boolean
* @return $this
*/
public function setUseTruncation($boolean)
{
$this->use_truncation = !!$boolean;
return $this;
}
/**
* Return wheter the use of truncation is enabled or not
*
* @return boolean
*/
public function useTruncation()
{
return $this->use_truncation;
}
/** /**
* Return wheter the use of stemming is enabled or not * Return wheter the use of stemming is enabled or not
* *
@@ -542,6 +568,8 @@ class SearchEngineOptions
$options->setFields($databoxFields); $options->setFields($databoxFields);
$options->setDateFields($databoxDateFields); $options->setDateFields($databoxDateFields);
$options->setUseTruncation((Boolean) $request->get('truncation'));
return $options; return $options;
} }
@@ -628,6 +656,7 @@ class SearchEngineOptions
} }
}, },
'stemming' => $optionSetter('setStemming'), 'stemming' => $optionSetter('setStemming'),
'use_truncation' => $optionSetter('setUseTruncation'),
'date_fields' => function ($value, SearchEngineOptions $options) use ($fieldNormalizer) { 'date_fields' => function ($value, SearchEngineOptions $options) use ($fieldNormalizer) {
$options->setDateFields($fieldNormalizer($value)); $options->setDateFields($fieldNormalizer($value));
}, },

View File

@@ -48,6 +48,7 @@ class PhraseanetExtension extends \Twig_Extension
new \Twig_SimpleFunction('border_checker_from_fqcn', array($this, 'getCheckerFromFQCN')), new \Twig_SimpleFunction('border_checker_from_fqcn', array($this, 'getCheckerFromFQCN')),
new \Twig_SimpleFunction('caption_field', array($this, 'getCaptionField')), new \Twig_SimpleFunction('caption_field', array($this, 'getCaptionField')),
new \Twig_SimpleFunction('caption_field_label', array($this, 'getCaptionFieldLabel')), new \Twig_SimpleFunction('caption_field_label', array($this, 'getCaptionFieldLabel')),
new \Twig_SimpleFunction('caption_field_gui_visible', array($this, 'getCaptionFieldGuiVisible')),
new \Twig_SimpleFunction('caption_field_order', array($this, 'getCaptionFieldOrder')), new \Twig_SimpleFunction('caption_field_order', array($this, 'getCaptionFieldOrder')),
new \Twig_SimpleFunction('flag_slugify', array(Flag::class, 'normalizeName')), new \Twig_SimpleFunction('flag_slugify', array(Flag::class, 'normalizeName')),
@@ -77,6 +78,29 @@ class PhraseanetExtension extends \Twig_Extension
return ''; return '';
} }
/**
* get localized field's gui_visible
* @param RecordInterface $record
* @param $fieldName
* @return string - the name gui_visible
*/
public function getCaptionFieldGuiVisible(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_gui_visible($this->app['locale']);
}
}
}
return '';
}
public function getCaptionField(RecordInterface $record, $field, $value) public function getCaptionField(RecordInterface $record, $field, $value)
{ {
if ($record instanceof ElasticsearchRecord) { if ($record instanceof ElasticsearchRecord) {

View File

@@ -80,7 +80,7 @@ class RedisSessionHandler implements \SessionHandlerInterface
*/ */
public function destroy($sessionId) public function destroy($sessionId)
{ {
return 1 === $this->redis->delete($this->prefix.$sessionId); return 1 === $this->redis->del($this->prefix.$sessionId);
} }
/** /**

View File

@@ -463,7 +463,8 @@ class databox extends base implements ThumbnailedElement
->set_type($type) ->set_type($type)
->set_tbranch(isset($field['tbranch']) ? (string) $field['tbranch'] : '') ->set_tbranch(isset($field['tbranch']) ? (string) $field['tbranch'] : '')
->set_generate_cterms((isset($field['generate_cterms']) && (string) $field['generate_cterms'] == 1)) ->set_generate_cterms((isset($field['generate_cterms']) && (string) $field['generate_cterms'] == 1))
->set_gui_editable((isset($field['gui_editable']) && (string) $field['gui_editable'] == 1)) ->set_gui_editable((!isset($field['gui_editable']) || (isset($field['gui_editable']) && (string) $field['gui_editable'] == 1)))
->set_gui_visible((!isset($field['gui_visible']) || (isset($field['gui_visible']) && (string) $field['gui_visible'] == 1)))
->set_thumbtitle(isset($field['thumbtitle']) ? (string) $field['thumbtitle'] : (isset($field['thumbTitle']) ? $field['thumbTitle'] : '0')) ->set_thumbtitle(isset($field['thumbtitle']) ? (string) $field['thumbtitle'] : (isset($field['thumbTitle']) ? $field['thumbTitle'] : '0'))
->set_report(isset($field['report']) ? (string) $field['report'] : '1') ->set_report(isset($field['report']) ? (string) $field['report'] : '1')
->save(); ->save();

View File

@@ -45,6 +45,7 @@ class databox_field implements cache_cacheableInterface
protected $tbranch; protected $tbranch;
protected $generate_cterms; protected $generate_cterms;
protected $gui_editable; protected $gui_editable;
protected $gui_visible;
protected $separator; protected $separator;
protected $thumbtitle; protected $thumbtitle;
@@ -170,6 +171,7 @@ class databox_field implements cache_cacheableInterface
$this->tbranch = $row['tbranch']; $this->tbranch = $row['tbranch'];
$this->generate_cterms = (bool)$row['generate_cterms']; $this->generate_cterms = (bool)$row['generate_cterms'];
$this->gui_editable = (bool)$row['gui_editable']; $this->gui_editable = (bool)$row['gui_editable'];
$this->gui_visible = (bool)$row['gui_visible'];
$this->VocabularyType = $row['VocabularyControlType']; $this->VocabularyType = $row['VocabularyControlType'];
$this->VocabularyRestriction = (bool)$row['RestrictToVocabularyControl']; $this->VocabularyRestriction = (bool)$row['RestrictToVocabularyControl'];
@@ -312,6 +314,7 @@ class databox_field implements cache_cacheableInterface
`tbranch` = :tbranch, `tbranch` = :tbranch,
`generate_cterms` = :generate_cterms, `generate_cterms` = :generate_cterms,
`gui_editable` = :gui_editable, `gui_editable` = :gui_editable,
`gui_visible` = :gui_visible,
`sorter` = :position, `sorter` = :position,
`thumbtitle` = :thumbtitle, `thumbtitle` = :thumbtitle,
`VocabularyControlType` = :VocabularyControlType, `VocabularyControlType` = :VocabularyControlType,
@@ -337,6 +340,7 @@ class databox_field implements cache_cacheableInterface
':tbranch' => $this->tbranch, ':tbranch' => $this->tbranch,
':generate_cterms' => $this->generate_cterms ? '1' : '0', ':generate_cterms' => $this->generate_cterms ? '1' : '0',
':gui_editable' => $this->gui_editable ? '1' : '0', ':gui_editable' => $this->gui_editable ? '1' : '0',
':gui_visible' => $this->gui_visible ? '1' : '0',
':position' => $this->position, ':position' => $this->position,
':thumbtitle' => $this->thumbtitle, ':thumbtitle' => $this->thumbtitle,
':VocabularyControlType' => $this->getVocabularyControl() ? $this->getVocabularyControl()->getType() : null, ':VocabularyControlType' => $this->getVocabularyControl() ? $this->getVocabularyControl()->getType() : null,
@@ -390,6 +394,7 @@ class databox_field implements cache_cacheableInterface
$meta->setAttribute('tbranch', $this->tbranch); $meta->setAttribute('tbranch', $this->tbranch);
$meta->setAttribute('generate_cterms', $this->generate_cterms ? '1' : '0'); $meta->setAttribute('generate_cterms', $this->generate_cterms ? '1' : '0');
$meta->setAttribute('gui_editable', $this->gui_editable ? '1' : '0'); $meta->setAttribute('gui_editable', $this->gui_editable ? '1' : '0');
$meta->setAttribute('gui_visible', $this->gui_visible ? '1' : '0');
if ($this->multi) { if ($this->multi) {
$meta->setAttribute('separator', $this->separator); $meta->setAttribute('separator', $this->separator);
} }
@@ -743,6 +748,17 @@ class databox_field implements cache_cacheableInterface
return $this; return $this;
} }
/**
* @param boolean $gui_visible
* @return databox_field
*/
public function set_gui_visible($gui_visible)
{
$this->gui_visible = $gui_visible;
return $this;
}
/** /**
* *
* @param string $separator * @param string $separator
@@ -845,6 +861,15 @@ class databox_field implements cache_cacheableInterface
return $this->gui_editable; return $this->gui_editable;
} }
/**
*
* @return boolean
*/
public function get_gui_visible()
{
return $this->gui_visible;
}
/** /**
* @param Boolean $all If set to false, returns a one-char separator to use for serialiation * @param Boolean $all If set to false, returns a one-char separator to use for serialiation
* *
@@ -957,6 +982,7 @@ class databox_field implements cache_cacheableInterface
'tbranch' => $this->tbranch, 'tbranch' => $this->tbranch,
'generate_cterms' => $this->generate_cterms, 'generate_cterms' => $this->generate_cterms,
'gui_editable' => $this->gui_editable, 'gui_editable' => $this->gui_editable,
'gui_visible' => $this->gui_visible,
'separator' => $this->separator, 'separator' => $this->separator,
'required' => $this->required, 'required' => $this->required,
'report' => $this->report, 'report' => $this->report,
@@ -995,10 +1021,10 @@ class databox_field implements cache_cacheableInterface
} }
$sql = "INSERT INTO metadatas_structure $sql = "INSERT INTO metadatas_structure
(`id`, `name`, `src`, `readonly`, `gui_editable`, `required`, `indexable`, `type`, `tbranch`, `generate_cterms`, (`id`, `name`, `src`, `readonly`, `gui_editable`,`gui_visible`, `required`, `indexable`, `type`, `tbranch`, `generate_cterms`,
`thumbtitle`, `multi`, `business`, `aggregable`, `thumbtitle`, `multi`, `business`, `aggregable`,
`report`, `sorter`, `separator`) `report`, `sorter`, `separator`)
VALUES (null, :name, '', 0, 1, 0, 1, 'string', '', 1, VALUES (null, :name, '', 0, 1, 1, 0, 1, 'string', '', 1,
null, 0, 0, 0, null, 0, 0, 0,
1, :sorter, '')"; 1, :sorter, '')";

View File

@@ -2049,6 +2049,14 @@
<default>1</default> <default>1</default>
<comment></comment> <comment></comment>
</field> </field>
<field>
<name>gui_visible</name>
<type>int(1) unsigned</type>
<null></null>
<extra></extra>
<default>1</default>
<comment></comment>
</field>
</fields> </fields>
<indexes> <indexes>
<index> <index>

View File

@@ -79,7 +79,7 @@
<size>748</size> <size>748</size>
<mediatype>video</mediatype> <mediatype>video</mediatype>
<writeDatas>yes</writeDatas> <writeDatas>yes</writeDatas>
<acodec>libfaac</acodec> <acodec>libmp3lame</acodec>
<vcodec>libx264</vcodec> <vcodec>libx264</vcodec>
<devices>screen</devices> <devices>screen</devices>
<bitrate>1000</bitrate> <bitrate>1000</bitrate>

View File

@@ -79,7 +79,7 @@
<size>748</size> <size>748</size>
<mediatype>video</mediatype> <mediatype>video</mediatype>
<writeDatas>yes</writeDatas> <writeDatas>yes</writeDatas>
<acodec>libfaac</acodec> <acodec>libmp3lame</acodec>
<vcodec>libx264</vcodec> <vcodec>libx264</vcodec>
<devices>screen</devices> <devices>screen</devices>
<bitrate>1000</bitrate> <bitrate>1000</bitrate>

View File

@@ -79,7 +79,7 @@
<size>748</size> <size>748</size>
<mediatype>video</mediatype> <mediatype>video</mediatype>
<writeDatas>yes</writeDatas> <writeDatas>yes</writeDatas>
<acodec>libfaac</acodec> <acodec>libmp3lame</acodec>
<vcodec>libx264</vcodec> <vcodec>libx264</vcodec>
<devices>screen</devices> <devices>screen</devices>
<bitrate>1000</bitrate> <bitrate>1000</bitrate>

View File

@@ -65,7 +65,7 @@
"normalize-css": "^2.1.0", "normalize-css": "^2.1.0",
"npm": "^6.0.0", "npm": "^6.0.0",
"npm-modernizr": "^2.8.3", "npm-modernizr": "^2.8.3",
"phraseanet-production-client": "0.34.72-d", "phraseanet-production-client": "0.34.80-d",
"requirejs": "^2.3.5", "requirejs": "^2.3.5",
"tinymce": "^4.0.28", "tinymce": "^4.0.28",
"underscore": "^1.8.3", "underscore": "^1.8.3",

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

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?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"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2019-05-21T05:53:02Z" source-language="en" target-language="de" datatype="plaintext" original="not.available"> <file date="2019-11-19T08:48:53Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <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> <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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?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"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2019-05-21T05:54:16Z" source-language="en" target-language="en" datatype="plaintext" original="not.available"> <file date="2019-11-19T08:49:17Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <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> <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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?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"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2019-05-21T05:55:28Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available"> <file date="2019-11-15T08:03:23Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <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> <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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?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"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2019-05-21T05:56:47Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available"> <file date="2019-11-19T08:50:13Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <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> <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>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: sketchtool 58 (101010) - https://sketch.com -->
<title>5609DDD5-6B9C-411B-B926-EEA284949013</title>
<desc>Created with sketchtool.</desc>
<defs>
<polygon id="path-1" points="0 0 22.3169609 16.2062701 0 32.4125403"></polygon>
<filter x="-31.4%" y="-15.4%" width="162.7%" height="143.2%" filterUnits="objectBoundingBox" id="filter-3">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="Pictos" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pictos/Arrow/Pleine">
<g id="Colors/Black" transform="translate(5.000000, 0.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Mask" fill="black" fill-opacity="1">
<use filter="url(#filter-3)" xlink:href="#path-1"></use>
</g>
<g id="Colors/Rectangular/Black" mask="url(#mask-2)" fill="#000000">
<g transform="translate(-5.000000, 0.000000)" id="Rectangle">
<rect x="0" y="0" width="32" height="32"></rect>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="times-circle" class="svg-inline--fa fa-times-circle fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#aaa" d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm101.8-262.2L295.6 256l62.2 62.2c4.7 4.7 4.7 12.3 0 17l-22.6 22.6c-4.7 4.7-12.3 4.7-17 0L256 295.6l-62.2 62.2c-4.7 4.7-12.3 4.7-17 0l-22.6-22.6c-4.7-4.7-4.7-12.3 0-17l62.2-62.2-62.2-62.2c-4.7-4.7-4.7-12.3 0-17l22.6-22.6c4.7-4.7 12.3-4.7 17 0l62.2 62.2 62.2-62.2c4.7-4.7 12.3-4.7 17 0l22.6 22.6c4.7 4.7 4.7 12.3 0 17z"></path></svg>

After

Width:  |  Height:  |  Size: 705 B

View File

@@ -0,0 +1 @@
<svg aria-hidden="true" focusable="false" data-prefix="far" data-icon="check-circle" class="svg-inline--fa fa-check-circle fa-w-16" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#aaa" d="M256 8C119.033 8 8 119.033 8 256s111.033 248 248 248 248-111.033 248-248S392.967 8 256 8zm0 48c110.532 0 200 89.451 200 200 0 110.532-89.451 200-200 200-110.532 0-200-89.451-200-200 0-110.532 89.451-200 200-200m140.204 130.267l-22.536-22.718c-4.667-4.705-12.265-4.736-16.97-.068L215.346 303.697l-59.792-60.277c-4.667-4.705-12.265-4.736-16.97-.069l-22.719 22.536c-4.705 4.667-4.736 12.265-.068 16.971l90.781 91.516c4.667 4.705 12.265 4.736 16.97.068l172.589-171.204c4.704-4.668 4.734-12.266.067-16.971z"></path></svg>

After

Width:  |  Height:  |  Size: 738 B

View File

@@ -50,7 +50,9 @@ $mainMenuLinkBackgroundHoverColor: transparent;
} }
} }
[class*=" icon-"].fa, [class^=icon-].fa, .fa {
font-family: Fontawesome!important;
}
[class^="icon-"], [class*=" icon-"].icomoon { [class^="icon-"], [class*=" icon-"].icomoon {
display: inline-block; display: inline-block;
width: inherit; width: inherit;

View File

@@ -1,4 +1,5 @@
$iconsPath: '../../../assets/common/images/icons/'; $iconsPath: '../../../assets/common/images/icons/';
ul.image_set{ ul.image_set{
padding:0; padding:0;
margin:0; margin:0;
@@ -6,26 +7,57 @@ ul.image_set{
width:100%; width:100%;
border:none; border:none;
list-style-type: none; list-style-type: none;
display: flex;
flex-wrap: wrap;
} }
li.image_box a img{ li.image_box a img{
position:relative; position:relative;
vertical-align:middle;
border:none; border:none;
width: auto!important;
height: 100% !important;
top: 0 !important;
object-fit: contain;
} }
li.image_box a{ li.image_box a{
padding:0; padding:0;
text-shadow:0; text-shadow:0;
margin:0; margin:0;
width: 100%;
} }
li.image_box{ li.image_box{
width:80px; width: 18%;
height:80px; position: relative;
position:relative; margin: 0 2.5% 15px 0;
float:left; padding: 0;
margin:0px 15px 15px 0px; display: flex;
padding:0px; align-items: center;
text-align:center; text-align: center;
background: #ededed;
&:nth-child(5n) {
margin-right: 0;
}
.thumb_wrapper {
background: #ededed;
width: 100%!important;
height: 160px!important;
@media screen and (max-width: 767px) {
height: 130px !important;
}
}
} }
@media screen and (max-width: 767px) {
li.image_box{
width: 32%;
margin: 0 2% 15px 0;
&:nth-child(5n) {
margin-right: 2% ;
}
&:nth-child(3n) {
margin-right: 0;
}
}
}
a.no.active_choice{ a.no.active_choice{
background-color:red; background-color:red;
color: #fff; color: #fff;
@@ -45,10 +77,12 @@ a.active_choice{
} }
.valid_choice.agree{ .valid_choice.agree{
background-image: url('#{$iconsPath}ok.png'); background: #7ed321;
border-top-left-radius: 100px;
} }
.valid_choice.disagree{ .valid_choice.disagree{
background-image: url('#{$iconsPath}delete.png'); background: #d0021b;
border-top-left-radius: 100px;
} }
.thumb_wrapper { .thumb_wrapper {
@@ -70,3 +104,7 @@ a.active_choice{
} }
} }
.ui-footer .ui-title, .ui-header .ui-title {
font-size: 18px;
}

View File

@@ -1,5 +1,28 @@
@import './jquery-mobile/jquery-validator'; @import './jquery-mobile/jquery-validator';
@font-face {
font-family: 'icomoon';
src: url("../../common/fonts/PhraseanetIcomoon/fonts/icomoon.eot?xt8hfo");
src: url("../../common/fonts/PhraseanetIcomoon/fonts/icomoon.eot?xt8hfo#iefix") format("embedded-opentype"), url("../../common/fonts/PhraseanetIcomoon/fonts/icomoon.ttf?xt8hfo") format("truetype"), url("../../common/fonts/PhraseanetIcomoon/fonts/icomoon.woff?xt8hfo") format("woff"), url("../../common/fonts/PhraseanetIcomoon/fonts/icomoon.svg?xt8hfo#icomoon") format("svg");
font-weight: normal;
font-style: normal;
}
[class^="icon-"], [class*=" icon-"] {
/* use !important to prevent issues with browser extensions that change fonts */
font-family: 'icomoon' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.nav_button { .nav_button {
width: 90%; width: 90%;
margin: 0px auto; margin: 0px auto;
@@ -24,4 +47,669 @@
#right-btn { #right-btn {
float: right; float: right;
} }
.report-modal, .ui-dialog .ui-dialog-content {
background: linear-gradient(#3c3c3c, #111);
}
.ui-bar-c, .ui-body-c, .ui-btn-down-c, .ui-btn-hover-c, .ui-btn-up-c, .ui-overlay-c {
text-shadow: none;
}
@import '../../_shared/styles/variables';
$lightboxPath: '../images/';
$imagesPath: '/assets/vendors/jquery-ui/images/dark-hive/';
$mainMenuBackgroundColor: #c7c7c7; //BFBFBF;
$mainMenuBottomBorder: 1px solid #c7c7c7;
$mainMenuLinkColor: #212121;
$mainMenuLinkHoverColor: #000000;
$mainMenuLinkActiveColor: #BFBFBF;
$mainMenuLinkBackgroundHoverColor: transparent;
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 13px;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
img {
border: none;
vertical-align: middle;
}
.title15 {
font-size: 15px;
font-weight: bold;
}
.record_display_box {
width: 100%;
height: 100%;
display: block;
table {
vertical-align: middle;
table-layout: fixed;
}
.title {
margin: 0 10px;
}
.record {
position: relative;
max-width: none;
max-height: none;
}
.header {
color: #BFBFBF;
height: 30px;
bottom: auto;
overflow: hidden;
.title {
overflow: hidden;
line-height: 20px;
height: 20px;
}
}
.lightbox_container {
top: 30px;
overflow: hidden;
}
.display_id {
top: 5px;
margin: 0 0 0 5px;
background: #bebebe;
}
}
#sc_wrapper {
left: 20px;
right: 20px;
overflow-x: scroll;
overflow-y: hidden;
}
#sc_container {
position: relative;
height: 100%;
}
.basket_element_wrapper {
position: relative;
float: left;
padding: 0 5px;
}
.basket_element {
position: relative;
float: left;
width: 114px;
height: 130px;
border: 1px solid #212121;
text-align: left;
padding: 5px 8px;
&.selected {
background-color: #212121;
}
.display_id {
top: 4px;
left: 8px;
}
.agreement {
position: absolute;
top: 4px;
right: 8px;
z-index: 99;
}
.image {
position: relative;
z-index: 90;
}
.previewTips {
background-image: url('#{$iconsPath}zoom.gif');
background-position: center center;
background-repeat: no-repeat;
cursor: help;
position: absolute;
bottom: 4px;
right: 8px;
height: 18px;
width: 18px;
z-index: 99;
}
}
#report .display_id {
top: 0;
left: 0;
border-radius: 0;
background-color: rgba(216, 216, 216, 0.7);
font-weight: 700;
z-index: 99;
color: #333333;
position: absolute;
width: 22px;
padding: 2px 0;
font-size: 12px;
}
#report .CHIM.diapo {
text-align: center;
}
.display_id {
background-color: #FFFFFF;
padding: 3px 6px;
font-weight: bold;
z-index: 99;
color: #212121;
-moz-border-radius: 50%;
-webkit-border-radius: 50%;
border-radius: 50%;
position: absolute;
}
.not_decided {
opacity: 0.30;
filter: alpha(opacity=30);
}
#sc_wrapper .not_decided {
display: none;
}
#right_scroller {
width: 30px;
right: -10px;
left: auto;
background-image: url('#{$lightboxPath}right_arrow.png');
background-position: center center;
background-repeat: no-repeat;
}
#left_scroller {
width: 30px;
left: -10px;
right: auto;
background-image: url('#{$lightboxPath}left_arrow.png');
background-position: center center;
background-repeat: no-repeat;
}
#basket_infos {
overflow: hidden;
background-color: #1F1E1B;
color: #BFBFBF;
}
#basket_options {
height: 35px;
top: auto;
background-color: #1F1E1B;
text-align: center;
}
#basket_options .confirm_report {
margin: 5px auto;
}
#basket_infos .user_infos {
height: 120px;
top: auto;
}
#basket_infos {
table {
width: 100%;
margin: 5px 0;
.title {
width: 100%;
}
.report_wrapper {
text-align: right;
}
}
}
#right_column {
left: auto;
right: 0;
width: 240px;
}
#right_column_validation_toggle {
bottom: 45px;
background-color: #1F1E1B;
height: 30px;
top: auto;
text-align: center;
display: none;
line-height: 25px;
color: #BFBFBF;
}
#right_column .right_column_title {
height: 30px;
bottom: auto;
}
#right_column .right_column_title img.expanded {
display: none;
}
#right_column .right_column_title img.collapsed {
display: inline;
}
#right_column .right_column_title.expanded img.expanded {
display: inline;
}
#right_column .right_column_title.expanded img.collapsed {
display: none;
}
#right_column .right_column_wrapper {
top: 30px;
bottom: 45px;
}
#right_column .right_column_wrapper.caption {
bottom: 85px;
}
#record_infos {
overflow-x: hidden;
overflow-y: auto;
}
#record_compare {
visibility: hidden;
top: auto;
left: auto;
}
#record_compare .header, #record_compare .lightbox_container {
left: 5px;
}
#record_wrapper.comparison #record_main .header, #record_wrapper.comparison #record_main .lightbox_container {
right: 5px;
}
.agreement_selector {
position: absolute;
bottom: 10px;
right: 10px;
}
.clickable {
cursor: pointer;
}
.big_box.agree {
border: 2px solid #35AC00;
background-color: #35AC00;
}
.big_box.disagree {
border: 2px solid #DE1200;
background-color: #DE1200;
}
.big_box, .big_box.not_decided {
width: 95px;
margin: 0 auto;
padding: 6px 10px;
height: 30px;
color: #1F1E1B;
background-color: #353430;
border: 2px solid #353430;
text-align: center;
opacity: 1;
filter: alpha(opacity=100);
}
.big_box span {
margin: 0 10px;
}
li.userchoice {
margin: 5px 0 0px 20px;
}
.userchoice.disagree {
color: #DE1200;
}
.userchoice.agree {
color: #35AC00;
}
.basket_report_user {
padding: 7px 10px;
}
.basket_report_user_wrapper {
margin: 0;
border-bottom: 1px solid #b2b2b2;
border-radius: 0;
display: inline-block;
padding: 10px 15px;
width: 100%;
box-sizing: border-box;
background: #e5e5e5;
text-shadow: none;
float: left;
}
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text {
padding: 0.2em 1em 0.2em 2.1em;
}
/*******
*
* Index
*
* ******/
#main_index {
position: relative;
width: 600px;
margin: 0 auto;
}
#main_wrapper {
width: 100%;
}
#main_wrapper h1 {
font-weight: bold;
font-size: 25px;
}
table th {
text-align: right;
vertical-align: bottom;
height: 60px;
border-bottom: 1px solid #8F8F8F;
}
table th.title {
text-align: left;
}
table th h1 {
margin-left: 20px;
}
table th i {
margin-right: 20px;
}
.ui-state-default.note_closer, .ui-state-default.note_saver {
background-color: #353430;
padding: 5px;
margin: 0 10px;
}
.ui-state-default.note_saver {
background-color: #1F1E1B;
}
.record_display_box form .buttons {
margin: 5px;
text-align: right;
}
.record_display_box form {
margin: 15px 0;
width: 90%;
}
.record_display_box form textarea {
width: 100%;
height: 75px;
}
#navigation {
width: 200px;
}
.basket_downloader {
background-color: #1F1E1B;
margin: 0 10px;
padding: 2px;
border: 0;
}
hr {
width: 100%;
height: 1px;
background-color: #212121;
border: none;
}
.report {
margin: 0 10px;
vertical-align: bottom;
}
/*
*
* Overrides JqueryUI
*
*/
.ui-button {
background: transparent;
border: none;
margin: 0;
padding: 0;
}
.ui-button-text-only .ui-button-text {
padding: 0.15em;
}
.ui-dialog {
.ui-dialog-titlebar {
padding: 1em 1em;
}
}
.videoTips {
width: 100%;
height: 100%;
}
#basket_infos {
margin-bottom: 20px;
.mobile_aggreement_box {
padding: 20px;
}
}
.ui-button-icon.ui-icon.ui-icon-closethick {
background-position: -73px 0px;
background-color: rgba(0, 0, 0, .9);
padding: 0;
}
.btn-container {
padding: 0 20px;
}
button.confirm_report {
background: #38c !important;
color: #fff !important;
font-size: 16px;
font-weight: bold;
padding: 6px;
display: inline-block;
border: 1px solid #38c;
text-shadow: 0 1px 0 #111;
border-radius: 16px;
font-family: Roboto, sans-serif;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2) !important;
}
.report_wrapper {
position: relative;
margin-bottom: 20px;
}
.report_btn {
position: absolute;
top: -41px;
right: 0;
z-index: 1;
background: #8bc34a;
border: 1px solid #8bc34a;
box-sizing: border-box;
padding: 8px 13px;
min-width: 110px;
border-radius: 4px;
color: #fff !important;
text-decoration: none;
text-align: center;
transition: all 0.3s;
&:hover, &:focus {
background: darken(#8bc34a, 0.2);
border-color: darken(#8bc34a, 0.3);
}
&.report_list {
background: #f44336;
border-color: #f44336;
&:hover, &:focus {
background: darken(#f44336, 0.2);
border-color: darken(#f44336, 0.3);
}
}
}
.report_list {
display: none;
}
.report_summary_backup, .report_list_backup {
display: none;
}
.chim-wrapper-block {
margin-bottom: 15px;
.chim-block {
margin: 0;
}
.chim-inner {
width: 100%;
display: inline-block;
min-width: 296px;
}
.chim-left {
display: inline-block;
width: 100%;
background: #ededed;
text-align: center;
position: relative;
.diapo {
display: inline-block;
div {
max-width: 100%;
}
}
}
.chim-right {
width: 100%;
.validate-icon {
float: left;
height: 25px;
vertical-align: middle;
display: flex;
flex-wrap: wrap;
align-items: center;
}
h3 {
font-size: 16px;
margin: 0;
padding-top: 3px;
}
}
}
.thumb_wrapper img.record_image {
max-width: 100%;
}
/*header lightbox*/
.ui-footer .ui-title, .ui-header .ui-title {
min-height: 26px;
padding: 10px 0;
}
.ui-listview.lightbox-list-view {
& > .ui-li-static {
padding: .7em 1em;
text-overflow: inherit;
white-space: inherit;
}
& > li {
border-color: #b2b2b2;
background: none;
p {
text-overflow: inherit;
white-space: inherit;
line-height: 15px;
font-size: 13px;
color: #141414;
}
}
h3 {
font-family: Roboto, sans-serif;;
font-size: 16px;
font-weight: bold;
font-stretch: normal;
font-style: normal;
line-height: 0.94;
letter-spacing: normal;
color: #141414;
}
}
.ui-footer.ui-bar-inherit {
border: 0;
}
.center-image {
text-align: center;
}
/*validate page*/
.validate-icon {
float: left;
position: absolute;
.icomoon {
color: #fff;
font-size: 17px;
padding: 3px;
border-radius: 50px;
display: inline-block;
}
.icon-disagree {
background: #cd2f2f;
}
.icon-agree {
background: #8bc34a;
}
}
.validate-info {
float: left;
padding-left: 36px;
}

View File

@@ -109,3 +109,48 @@ dd {
float: left; float: left;
} }
} }
/*Help menu*/
.contextMenu.helpcontextmenu {
display: none;
&.shown {
display: block;
position: absolute;
z-index: 101;
}
}
.help-trigger {
display:inline-block;
cursor:pointer;
padding: 0 4px;
border:none;
margin-left: -12px;
margin-right: 94px;
.fa-caret-down:before {
content: "\25BC";
font-size: 11px;
}
}
.context-menu-theme-vista {
background-image: none;
background-color: #414141;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
.context-menu-item {
transition: 500ms;
&:hover {
background-image: none;
background-color: #75abff;
border: none;
}
.context-menu-item-inner {
padding: 4px 12px;
margin-left: 0;
font-family: Helvetica;
font-size: 12px;
font-weight: 700;
color: #fff;
}
}
}

View File

@@ -50,7 +50,6 @@
class="ui-btn-right jqm-home">{{ 'Home' | trans }}</a> class="ui-btn-right jqm-home">{{ 'Home' | trans }}</a>
</div> </div>
<div id="content" data-role="content"> <div id="content" data-role="content">
{{ thumbnail.format100percent(record.get_preview()) }}
<div class="nav_button"> <div class="nav_button">
{% if prevId != NULL %} {% if prevId != NULL %}
<a data-ajax="false" id="left-btn" <a data-ajax="false" id="left-btn"
@@ -64,13 +63,14 @@
{% endif %} {% endif %}
<div style="clear: both;"></div> <div style="clear: both;"></div>
</div> </div>
<div class="center-image">{{ thumbnail.format100percent(record.get_preview()) }}</div>
{% if basket_element.getBasket().getValidation() %} {% if basket_element.getBasket().getValidation() %}
{% if basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanAgree() %} {% if basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanAgree() %}
<fieldset data-role="controlgroup" data-type="horizontal" style="text-align:center;"> <fieldset data-role="controlgroup" data-type="horizontal" style="text-align:center;">
<input {% if basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == true%}checked="checked"{% endif %} type="radio" name="radio-view" id="radio-view-yes_{{basket_element.getId()}}" value="yes" /> <input onclick="window.location.reload();" {% if basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == true%}checked="checked"{% endif %} type="radio" name="radio-view" id="radio-view-yes_{{basket_element.getId()}}" value="yes" />
<label class="agreement_radio" style="width:110px;text-align:center;" <label class="agreement_radio" style="width:110px;text-align:center;"
for="radio-view-yes_{{ basket_element.getId() }}">{{ 'validation:: OUI' | trans }}</label> for="radio-view-yes_{{ basket_element.getId() }}">{{ 'validation:: OUI' | trans }}</label>
<input {% if basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == false and basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() is not null %}checked="checked"{% endif %} type="radio" name="radio-view" id="radio-view-no_{{basket_element.getId()}}" value="no" /> <input onclick="window.location.reload();" {% if basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == false and basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() is not null %}checked="checked"{% endif %} type="radio" name="radio-view" id="radio-view-no_{{basket_element.getId()}}" value="no" />
<label class="agreement_radio" style="width:110px;text-align:center;" <label class="agreement_radio" style="width:110px;text-align:center;"
for="radio-view-no_{{ basket_element.getId() }}">{{ 'validation:: NON' | trans }}</label> for="radio-view-no_{{ basket_element.getId() }}">{{ 'validation:: NON' | trans }}</label>
</fieldset> </fieldset>
@@ -81,7 +81,7 @@
</a> </a>
</div> </div>
<div> <div>
<ul data-role="listview" id="notes_{{basket_element.getId()}}"> <ul data-role="listview" class="lightbox-list-view" id="notes_{{basket_element.getId()}}">
{% include 'lightbox/sc_note.html.twig' %} {% include 'lightbox/sc_note.html.twig' %}
</ul> </ul>
</div> </div>

View File

@@ -1,17 +1,21 @@
{% for validationDatas in basket_element.getValidationDatas() %} {% for validationDatas in basket_element.getValidationDatas() %}
{% set is_mine = validationDatas.getParticipant().getUser().getId() == app.getAuthenticatedUser().getId() %}
{% if validationDatas.getNote() != '' or (validationDatas.getAgreement() is not null and is_mine) %}
<li> <li>
<h3 style="text-align:left;"> <div class="validate-icon">
{% if is_mine == false and validationDatas.getAgreement() is not null %} {% if basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanSeeOthers() or validationDatas.getParticipant().getUser() == app.getAuthenticatedUser() %}
<img style="vertical-align:middle;" {% if validationDatas.getAgreement() == true %}<span class="icomoon icon-agree">&#xe95f;</span>{% endif %}
src="/assets/lightbox/images/{% if validationDatas.getAgreement() == true %}agree.png{% else %}disagree.png{% endif %}" /> {% if validationDatas.getAgreement() == false and validationDatas.getAgreement() is not null %}<span class="icomoon icon-disagree">&#xe971; {{ validationDatas.getAgreement() }}</span>{% endif %}
{% endif %}
</div>
<div class="validate-info">
<h3>
{{ validationDatas.getParticipant().getUser().getDisplayName() }}
</h3>
{% if basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanSeeOthers() or validationDatas.getParticipant().getUser() == app.getAuthenticatedUser() %}
{% if validationDatas.getNote() != '' %}
<p style="text-align:left;">{{ 'validation:: note' | trans }} : {{ validationDatas.getNote()|nl2br }} </p>
{% endif %}
{% endif %} {% endif %}
{{ validationDatas.getParticipant().getUser().getDisplayName() }}
</h3> </div>
{% if validationDatas.getNote() != '' %}
<p style="text-align:left;">{{ 'validation:: note' | trans }} : {{ validationDatas.getNote()|nl2br }}</p>
{% endif %}
</li> </li>
{% endif %}
{% endfor %} {% endfor %}

View File

@@ -38,29 +38,65 @@
{% set basket_length = basket.getElements().count() %} {% set basket_length = basket.getElements().count() %}
{% trans with {'%basket_length%' : basket_length} %}%basket_length% documents{% endtrans %} {% trans with {'%basket_length%' : basket_length} %}%basket_length% documents{% endtrans %}
</p> </p>
<ul class="image_set"> {% if basket.getValidation() %}
{% for basket_element in basket.getElements() %} <div class="report_wrapper">
<li class="image_box" id="sselcontid_{{basket_element.getId()}}"> <a id="report_summary" class="report_btn report_summary" href="#" onclick="$.ajax({
{% if basket_element.getBasket().getValidation() and basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanAgree() %} type: 'GET',
<div class="valid_choice valid_choice_{{basket_element.getId()}} {% if basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == true %}agree{% elseif basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == false and basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() is not null %}disagree{% endif %}"> url: '/lightbox/ajax/LOAD_REPORT/' + $('#navigation').val() + '/',
</div> dataType: 'html',
success: function (data) {
$('#report_list_backup').empty().append($('#report').html());
$('#report').empty().append(data);
$('#report .record_image').css('height','auto');
return;
}
});
$(this).hide();
$('#report_list').show();">
{{ 'lightbox::recaptitulatif' | trans }}
</a>
<a id="report_list" class="report_btn report_list" href="#" onclick=" $(this).hide();
$('#report_summary').show();
$('#report').empty().append($('#report_list_backup').html());">
{{ 'lightbox::list' | trans }}
</a>
</div>
<div class="report_list_backup" id="report_list_backup">&nbsp;</div>
<div class="report_summary_backup " id="report_summary_backup">&nbsp;</div>
{% endif %} {% endif %}
<a href="{{ path('lightbox_ajax_load_basketelement', { 'sselcont_id' : basket_element.getId() }) }}"> <input type="hidden" id="navigation" value="{{ basket.getId() }}">
{{thumbnail.format(basket_element.getRecord(app).get_thumbnail(), 80, 80, '', true, false)}} <div id="report" class="summary_block">
</a> <ul class="image_set">
<input type="hidden" class="display_id" name="display_id" value="{{basket_element.getOrd()}}" /> {% for basket_element in basket.getElements() %}
</li>
{% endfor %} <li class="image_box" id="sselcontid_{{basket_element.getId()}}">
</ul> <div class="display_id">
</div> {{basket_element.getOrd()}}
<div data-role="footer"> </div>
{% if basket.getValidation() and basket.getValidation().getParticipant(app.getAuthenticatedUser()).getCanAgree() %} {% if basket_element.getBasket().getValidation() and basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanAgree() %}
<button class="confirm_report" style="width:100%;" title="{{ 'validation::envoyer mon rapport' | trans }}"> <div class="valid_choice valid_choice_{{basket_element.getId()}} {% if basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == true %}agree{% elseif basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() == false and basket_element.getUserValidationDatas(app.getAuthenticatedUser()).getAgreement() is not null %}disagree{% endif %}">
{{ 'validation::envoyer mon rapport' | trans }} </div>
<img src="/assets/common/images/icons/loader1F1E1B.gif" style="visibility:hidden;" class="loader"/> {% endif %}
</button> <a href="{{ path('lightbox_ajax_load_basketelement', { 'sselcont_id' : basket_element.getId() }) }}">
{% endif %} {{thumbnail.format(basket_element.getRecord(app).get_thumbnail(), 300, 300, '', true, false)}}
</div> </a>
<input type="hidden" class="display_id" name="display_id" value="{{basket_element.getOrd()}}" />
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="btn-container">
{% if basket.getValidation() and basket.getValidation().getParticipant(app.getAuthenticatedUser()).getCanAgree() %}
<button class="confirm_report" style="width:100%;" title="{{ 'validation::envoyer mon rapport' | trans }}">
{{ 'validation::envoyer mon rapport' | trans }}
<img src="/assets/common/images/icons/loader1F1E1B.gif" style="visibility:hidden;" class="loader"/>
</button>
{% endif %}
</div>
</div>
</div> </div>
{% endblock %} {% endblock %}

View File

@@ -193,7 +193,15 @@
<td> <td>
<label for="gui_editable" class="checkbox"> <label for="gui_editable" class="checkbox">
<input id="gui_editable" type="checkbox" <%= field.gui_editable ? "checked='checked'" : "" %> /> <input id="gui_editable" type="checkbox" <%= field.gui_editable ? "checked='checked'" : "" %> />
{% trans %}gui_editable{% endtrans %} {% trans %}Gui-editable{% endtrans %}
</label>
</td>
</tr>
<tr>
<td>
<label for="gui_visible" class="checkbox">
<input id="gui_visible" type="checkbox" <%= field.gui_visible ? "checked='checked'" : "" %> />
{% trans %}Gui-visible{% endtrans %}
</label> </label>
</td> </td>
</tr> </tr>
@@ -256,7 +264,7 @@
<td><input id="tbranch" type="text" value="<%= field.tbranch %>"/></td> <td><input id="tbranch" type="text" value="<%= field.tbranch %>"/></td>
</tr> </tr>
<tr> <tr>
<td><label for="generate_cterms" class="checkbox">{% trans %}generate_cterms{% endtrans %}</label></td> <td><label for="generate_cterms" class="checkbox">{% trans %}Generate-cterms{% endtrans %}</label></td>
<td><input id="generate_cterms" type="checkbox" <%= field.generate_cterms ? "checked='checked'" : "" %> /></td> <td><input id="generate_cterms" type="checkbox" <%= field.generate_cterms ? "checked='checked'" : "" %> /></td>
</tr> </tr>
</table> </table>

View File

@@ -1,8 +1,10 @@
{% macro caption(record, can_see_business, display_exif, limitedWidth = false) %} {% macro caption(record, can_see_business, display_exif, limitedWidth = false) %}
<dl class="{% if limitedWidth %}{% else %}dl-horizontal{% endif %}"> <dl class="{% if limitedWidth %}{% else %}dl-horizontal{% endif %}">
{% for name, value in record.getCaption(caption_field_order(record, can_see_business)) %} {% for name, value in record.getCaption(caption_field_order(record, can_see_business)) %}
<dt>{{ caption_field_label(record, name) }}</dt> {% if caption_field_gui_visible(record, name) == 1 %}
<dd>{{ caption_field(record, name, value)|e|highlight|linkify|parseColor }}</dd> <dt>{{ caption_field_label(record, name) }}</dt>
<dd>{{ caption_field(record, name, value)|e|highlight|linkify|parseColor }}</dd>
{% endif %}
{% endfor %} {% endfor %}
</dl> </dl>
{% if display_exif|default(true) and app.getAuthenticator().user is not none and user_setting('technical_display') == 'group' %} {% if display_exif|default(true) and app.getAuthenticator().user is not none and user_setting('technical_display') == 'group' %}

View File

@@ -302,8 +302,18 @@
$(document).ready(function () { $(document).ready(function () {
$('body').on('click', '#help-trigger', function (event) { $('body').on('click', '#help-trigger', function (event) {
$('#mainMenu .helpcontextmenu').toggleClass('shown'); $('#mainMenu .helpcontextmenu').toggleClass('shown');
console.log('mety');
}); });
$(document).on('click', function (e) {
if($('#mainMenu .helpcontextmenu').hasClass('shown')) {
var $this = $(e.target);
if ($this.closest('#mainMenu .helpcontextmenu.shown, .help-trigger').length == 0 && $this[0].id != "toggle") {
$('#mainMenu .helpcontextmenu').removeClass('shown');
}
}
});
// var key = 'help'; // var key = 'help';
var configurationSettingLinks = {{ configuration|json_encode|raw }}; var configurationSettingLinks = {{ configuration|json_encode|raw }};
//seperate array based on location of link //seperate array based on location of link

View File

@@ -4,48 +4,50 @@
<div style="margin:0 7px;overflow:hidden;"> <div style="margin:0 7px;overflow:hidden;">
{% for basket_element in basket.getElements() %} {% for basket_element in basket.getElements() %}
{% set record = basket_element.getRecord(app) %} {% set record = basket_element.getRecord(app) %}
<div class="chim-wrapper wrapCHIM_{{basket_element.getId()}} valid"> <div class="chim-wrapper-block chim-wrapper wrapCHIM_{{basket_element.getId()}} valid">
<div style="margin:20px;"> <div class="chim-block">
<table style="width: 100%; min-width: 330px;"> <div class="chim-inner">
<tr valign="top"> <div class="chim-left">
<td style="width:165px;"> <div id="CHIM_{{basket_element.getId()}}_{{record.get_serialize_key()}}" class="CHIM diapo">
<div id="CHIM_{{basket_element.getId()}}_{{record.get_serialize_key()}}" <div class="display_id">
class="CHIM diapo"> {{basket_element.getOrd()}}
<div class="display_id"> </div>
{{basket_element.getOrd()}} {{thumbnail.format(record.get_thumbnail(),165, 125, '', true, false)}}
</div>
</div> </div>
{{thumbnail.format(record.get_thumbnail(),165, 125, '', true, false)}} <div class="chim-right">
{% for validationDatas in basket_element.getValidationDatas()%}
<div class="basket_report_user_wrapper ui-corner-all">
{% if validationDatas.getAgreement() == true %}
{% set imguser = '<span class="icomoon icon-agree">&#xe95f;</span>' %}
{% set styleuser = '' %}
{% elseif validationDatas.getAgreement() is null %}
{% set imguser = '&nbsp;' %}
{% set styleuser = 'margin-left:18px;' %}
{% else %}
{% set imguser = '<span class="icomoon icon-disagree">&#xe971;</span>' %}
{% set styleuser = '' %}
{% endif %}
<div class="validate-icon">
{% if basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanSeeOthers() or validationDatas.getParticipant().getUser() == app.getAuthenticatedUser() %}
{{imguser|raw}}
{% endif %}
</div> </div>
</td> <div class="validate-info">
<td style="width:10px;"> <h3> {{validationDatas.getParticipant().getUser().getDisplayName()}}</h3>
</td> {% if validationDatas.getNote() != '' %}
<td> {% if basket_element.getBasket().getValidation().getParticipant(app.getAuthenticatedUser()).getCanSeeOthers() or validationDatas.getParticipant().getUser() == app.getAuthenticatedUser() %}
{% for validationDatas in basket_element.getValidationDatas()%} <p> {{validationDatas.getNote()|nl2br}}</p>
<div class="basket_report_user_wrapper ui-corner-all"> {% endif %}
<div class="basket_report_user"> {% endif %}
{% if validationDatas.getAgreement() == true %} </div>
{% set imguser = '<img src="/assets/lightbox/images/agree.png" />' %} </div>
{% set styleuser = '' %} {% endfor %}
{% elseif validationDatas.getAgreement() is null %} </div>
{% set imguser = '' %}
{% set styleuser = 'margin-left:18px;' %}
{% else %}
{% set imguser = '<img src="/assets/lightbox/images/disagree.png" />' %}
{% set styleuser = '' %}
{% endif %}
<b style="{{styleuser}}">{{imguser|raw}} {{validationDatas.getParticipant().getUser().getDisplayName()}}</b>
{% if validationDatas.getNote() != '' %}
: {{validationDatas.getNote()|nl2br}}
{% endif %}
</div>
</div>
{% endfor %}
</td>
</tr>
</table>
</div> </div>
</div> </div>
<div><hr/></div> </div>
{% endfor %} {% endfor %}
</div> </div>

View File

@@ -90,7 +90,7 @@
{% endif %} {% endif %}
{% for field in fields %} {% for field in fields %}
{% set i = field.get_id() %} {% set i = field.get_id() %}
{% if field.is_readonly() is empty %} {% if field.is_readonly() is empty and field.get_gui_editable()== 1 %}
<div class="edit_field edit-field-action" id="EditFieldBox_{{i}}" <div class="edit_field edit-field-action" id="EditFieldBox_{{i}}"
data-id="{{i}}" data-id="{{i}}"
data-name="{{field.get_name()}}"> data-name="{{field.get_name()}}">

View File

@@ -1,4 +1,5 @@
{% include 'prod/results/record.html.twig' with { {% include 'prod/results/record.html.twig' with {
'record': record, 'record': record,
'settings': settings 'settings': settings,
'plugins': plugins
} %} } %}

View File

@@ -7,7 +7,8 @@
<td valign="top" style='width:{{ settings.images_size + 50 }}px'> <td valign="top" style='width:{{ settings.images_size + 50 }}px'>
{% include 'prod/results/record.html.twig' with { {% include 'prod/results/record.html.twig' with {
'record': record, 'record': record,
'settings': settings 'settings': settings,
'plugins': plugins
} %} } %}
</td> </td>
<td valign="middle"> <td valign="middle">

View File

@@ -155,6 +155,29 @@
</div> </div>
{% endif %} {% endif %}
{% endif %} {% endif %}
{# add plugins entries #}
{% for plugin in plugins.actionbar|default([]) %}
{% set menu = plugin.ActionBar['_context_']|default([]) %}
{% for k, action in menu %}
{% if plugin.isContextMenuOptionAvailable(k, record) %}
<div title="" class="context-menu-item"
onclick="{{ plugin.getContextMenuJS(k) }}('{{ k }}', '{{record.baseId}}', '{{record.recordId}}', '{{ record.id }}');">
<div class="context-menu-item-inner">
{% set icon = (action.icon ?? false) ? plugin_asset(plugin.PluginName, action.icon) : null %}
{% set label = (action.label ?? false) ? (action.label|trans({}, plugin.PluginLocale)) : 'undefined label' %}
<a title="{{ label }}" href="#">
{% if icon %}
<img style="cursor:pointer;" src="{{ icon }}" alt="{{ label }}">
{% endif %}
<span>{{ label }}</span>
</a>
</div>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div> </div>
</td> </td>
</tr> </tr>

View File

@@ -31,7 +31,8 @@
'doctype_display': doctype_display, 'doctype_display': doctype_display,
'handle_dblclick' : true, 'handle_dblclick' : true,
'show_context_menu': true 'show_context_menu': true
} },
'plugins': plugins
} %} } %}
{% endblock %} {% endblock %}
{% endfor %} {% endfor %}

View File

@@ -44,270 +44,159 @@
</div> </div>
</span> </span>
<span class="dropdownButton"> {% set menus = {
<div class="btn-group"> 'export': [
<button id="TOOL_disktt" class="default_action TOOL_disktt_btn results_window btn btn-inverse" data-selection-source="search-result"> {
<img src="/assets/common/images/icons/disktt_history.png" height="16" width="16" class="btn-image"/> {{ 'action : exporter' | trans }} 'class':'TOOL_disktt_btn',
</button> 'icon':'/assets/common/images/icons/disktt_history.png',
<button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span class="caret"></span> 'label':'action : exporter' | trans },
</button> {
<ul class="dropdown-menu"> 'class':'TOOL_print_btn',
<li> 'icon':'/assets/common/images/icons/print_history.png',
<a class="TOOL_print_btn results_window" data-selection-source="search-result"> 'label':'action : print' | trans }
<img src="/assets/common/images/icons/print_history.png" height="16" width="16" class="btn-image"/> ],
{{ 'action : print' | trans }} 'edit': [],
</a> 'push': [],
</li> 'tools': [],
</ul> 'delete': []
</div> } %}
</span>
{% set actions = {} %} {# menu "edit" #}
{% set m = [] %}
{% if acl.has_right(constant('\\ACL::CANMODIFRECORD')) %} {% if acl.has_right(constant('\\ACL::CANMODIFRECORD')) %}
{% set label %} {% set m = m|merge([
{{ 'action : editer' | trans }} {
{% endset %} 'class':'TOOL_ppen_btn',
{% set actions = actions|merge( { 'edit' : {'icon': "/assets/common/images/icons/ppen_history.png", 'class':'TOOL_ppen_btn', 'label' : label} }) %} 'icon':'/assets/common/images/icons/ppen_history.png',
{% set label %} 'label':'action : editer' | trans },
{{ 'prod::toolbar : video editor' | trans }} {
{% endset %} 'class':'TOOL_videoeditor_btn',
{% set actions = actions|merge( { 'video' : {'icon': "/assets/common/images/icons/icon-video-editor.png", 'class':'TOOL_videoeditor_btn', 'label' : label} }) %} 'icon':'/assets/common/images/icons/icon-video-editor.png',
'label':'prod::toolbar : video editor' | trans }
]) %}
{% endif %} {% endif %}
{% if acl.has_right(constant('\\ACL::CHGSTATUS')) %} {% if acl.has_right(constant('\\\ACL::CHGSTATUS')) %}
{% set label %} {% set m = m|merge([
{{ 'action : status' | trans }} {
{% endset %} 'class':'TOOL_chgstatus_btn',
{% set actions = actions|merge( { 'status' : {'icon': "/assets/common/images/icons/chgstatus_history.png", 'class':'TOOL_chgstatus_btn', 'label' : label} }) %} 'icon':'/assets/common/images/icons/chgstatus_history.png',
'label':'action : status' | trans }
]) %}
{% endif %} {% endif %}
{% if acl.has_right(constant('\\ACL::CANDELETERECORD')) and acl.has_right(constant('\\ACL::CANADDRECORD')) %} {% if acl.has_right(constant('\\ACL::CANDELETERECORD')) and acl.has_right(constant('\\ACL::CANADDRECORD')) %}
{% set label %} {% set m = m|merge([
{{ 'action : collection' | trans }} {
{% endset %} 'class':'TOOL_chgcoll_btn',
{% set actions = actions|merge( { 'move' : {'icon': "/assets/common/images/icons/chgcoll_history.png", 'class':'TOOL_chgcoll_btn', 'label' : label} }) %} 'icon':'/assets/common/images/icons/chgcoll_history.png',
'label':'action : collection' | trans }
]) %}
{% endif %}
{% set menus = menus|merge({'edit' : m}) %}
{# menu "push" #}
{% set m = [] %}
{% if acl.has_right(constant('\\ACL::CANPUSH')) %}
{% set m = m|merge([
{
'class':'TOOL_pushdoc_btn',
'icon':'/assets/common/images/icons/push16.png',
'label':'action : push' | trans },
{
'class':'TOOL_feedback_btn',
'icon':'/assets/common/images/icons/feedback16.png',
'label':'Feedback' | trans }
]) %}
{% endif %}
{% if acl.has_right(constant('\\ACL::BAS_CHUPUB')) %}
{% set m = m|merge([
{
'class':'TOOL_publish_btn',
'icon':'/assets/common/images/icons/rss16.png',
'label':'action : publier' | trans }
]) %}
{% endif %}
{% set menus = menus|merge({'push' : m}) %}
{# menu "tools" #}
{% if acl.has_right(constant('\\ACL::IMGTOOLS')) %}
{% set menus = menus|merge({'tools' : [
{
'class':'TOOL_imgtools_btn',
'icon':'/assets/common/images/icons/imgtools_history.png',
'label':'action : outils' | trans }
]}) %}
{% endif %} {% endif %}
{% set n_actions = actions|length %} {# menu "delete" #}
{% if n_actions > 1 %} {% if acl.has_right(constant('\\ACL::CANDELETERECORD')) %}
<span class="dropdownButton"> {% set menus = menus|merge({'delete' : [
<div class="btn-group"> {
{% for action in actions %} 'class':'TOOL_trash_btn',
{% if loop.first %} 'icon':'/assets/common/images/icons/delete.png',
<button class="default_action {{ action.class }} results_window btn btn-inverse" data-selection-source="search-result"> 'label':'action : supprimer' | trans }
<img src="{{ action.icon }}" height="16" width="16" class="btn-image"/> {{ action.label }} ]}) %}
</button> {% endif %}
{% endif %}
{% endfor %} {# add plugins entries #}
<button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span {% if plugins.actionbar is not empty %}
class="caret"></span></button> {% for plugin in plugins.actionbar %}
<ul class="dropdown-menu"> {% for k, menu in plugin.getActionBar() %}
{% for action in actions %} {% if k != '_context_' %}
{% if not loop.first %} {% set m = menus[k]|default([]) %}
<li> {% for action in menu %}
<a class="{{ action.class }} results_window" data-selection-source="search-result"> {% set m = m|merge([{
<img src="{{ action.icon }}" height="16" width="16" class="btn-image"/> 'class':action.classes|default(''),
{{ action.label }} 'icon':plugin_asset(plugin.PluginName, action.icon),
</a> 'label':action.label|trans({}, plugin.PluginLocale) }])
</li> %}
{% if not loop.last %}
<li class="divider"></li>
{% endif %}
{% endif %}
{% endfor %} {% endfor %}
</ul> {% set menus = menus|merge({(k) : m}) %}
</div> {% endif %}
</span> {% endfor %}
{% elseif n_actions == 1 %} {% endfor %}
<span class="classicButton">
<div class="btn-group">
{% for action in actions %}
<button class="{{ action.class }} results_window btn btn-inverse" data-selection-source="search-result">
<img src="{{ action.icon }}" height="16" width="16" class="btn-image"/> {{ action.label }}
</button>
{% endfor %}
</div>
</span>
{% endif %} {% endif %}
{% if acl.has_right(constant('\\ACL::CANPUSH')) and acl.has_right(constant('\\ACL::BAS_CHUPUB')) %} {# print #}
<span class="dropdownButton"> {% for menu_entries in menus %}
<div class="btn-group"> {% if menu_entries|length > 0 %}
<button class="TOOL_pushdoc_btn default_action results_window btn btn-inverse" data-selection-source="search-result"> <span class="dropdownButton">
<img src="/assets/common/images/icons/push16.png" height="16" width="16" class="btn-image"/> {{ 'action : push' | trans }} <div class="btn-group">
</button> {% set menu_entry = menu_entries[0] %}
<button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span <button class="results_window btn btn-inverse {{ menu_entry.class }}" data-selection-source="search-result">
class="caret"></span></button> <img src="{{ menu_entry.icon }}" class="btn-image"/>
<ul class="dropdown-menu"> {{ menu_entry.label }}
<li> </button>
<a class="TOOL_feedback_btn results_window" data-selection-source="search-result"> {% set menu_entries = menu_entries|slice(1) %}
<img src="/assets/common/images/icons/feedback16.png" height="16" width="16" class="btn-image"/> {% if menu_entries|length > 0 %}
{{ 'Feedback' | trans }}
</a>
</li>
{#<li class="divider"></li>#}
{#<li>#}
{#<a class="TOOL_bridge_btn results_window" href="{{ path("prod_bridge_manager") }}" data-selection-source="search-result">#}
{#<img src="/assets/common/images/icons/door.png" height="16" width="16" class="btn-image"/>#}
{#{{ 'action : bridge' | trans }}#}
{#</a>#}
{#</li>#}
<li class="divider"></li>
<li>
<a class="TOOL_publish_btn results_window" data-selection-source="search-result">
<img src="/assets/common/images/icons/rss16.png" height="16" width="16" class="btn-image"/>
{{ 'action : publier' | trans }}
</a>
</li>
{% if plugins.actionbar is not empty %}
{% for plugin in plugins.actionbar %}
<li class="divider"></li>
{% for key, action in plugin.getActionBar().push|default([]) %}
<li>
<a class="results_window {{ action.classes|default('') }}" data-selection-source="search-result">
{% if action.icon %}
<img src="{{ plugin_asset(plugin.PluginName, action.icon) }}" height="16" width="16" class="btn-image"/>
{% endif %}
{{ action.label|trans({}, plugin.PluginLocale) }}
</a>
</li>
{% endfor %}
{% endfor %}
{% endif %}
</ul>
</div>
</span>
{% elseif acl.has_right(constant('\\ACL::CANPUSH')) %}
<span class="dropdownButton">
<div class="btn-group">
<button class="TOOL_pushdoc_btn default_action results_window btn btn-inverse" data-selection-source="search-result">
<img src="/assets/common/images/icons/push16.png" height="16" width="16" class="btn-image"/> {{ 'action : push' | trans }}
</button>
<button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span
class="caret"></span></button>
<ul class="submenu dropdown-menu">
<li>
<a class="TOOL_feedback_btn results_window" data-selection-source="search-result">
<img src="/assets/common/images/icons/feedback16.png" height="16" width="16" class="btn-image"/>
{{ 'Feedback' | trans }}
</a>
</li>
{% if plugins.actionbar is not empty %}
{% for plugin in plugins.actionbar %}
<li class="divider"></li>
{% for key, action in plugin.getActionBar().push|default([]) %}
<li>
<a class="results_window {{ action.classes|default('') }}" data-selection-source="search-result">
{% if action.icon %}
<img src="{{ plugin_asset(plugin.PluginName, action.icon) }}" height="16" width="16" class="btn-image"/>
{% endif %}
{{ action.label|trans({}, plugin.PluginLocale) }}
</a>
</li>
{% endfor %}
{% endfor %}
{% endif %}
</ul>
</div>
</span>
{% elseif acl.has_right(constant('\\ACL::BAS_CHUPUB')) %}
<span class="dropdownButton">
<div class="btn-group">
{#<button class="TOOL_pushdoc_btn default_action results_window btn btn-inverse" data-selection-source="search-result">#}
{#<img src="/assets/common/images/icons/door.png" height="16" width="16" class="btn-image"/> {{ 'action : bridge' | trans }}#}
{#</button>#}
<button class="TOOL_publish_btn results_window btn btn-inverse">
<img src="/assets/common/images/icons/rss16.png" height="16" width="16" class="btn-image"/>
{{ 'action : publier' | trans }}
</button>
<button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span
class="caret"></span></button>
{% if plugins.actionbar is not empty %}
<button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span <button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span
class="caret"></span></button> class="caret"></span></button>
<ul class="submenu dropdown-menu"> <ul class="dropdown-menu">
{% for plugin in plugins.actionbar %} {% for menu_entry in menu_entries %}
<li class="divider"></li>
{% for key, action in plugin.getActionBar().push|default([]) %}
<li>
<a class="results_window {{ action.classes|default('') }}">
{% if action.icon %}
<img src="{{ plugin_asset(plugin.PluginName, action.icon) }}"
height="16" width="16" class="btn-image"/>
{% endif %}
{{ action.label|trans({}, plugin.PluginLocale) }}
</a>
</li>
{% endfor %}
{% endfor %}
</ul>
{% endif %}
</div>
</span>
{% elseif plugins.actionbar is not empty %}
<span class="dropdownButton">
<div class="btn-group">
{% set firstButton = true %}
{% for plugin in plugins.actionbar %}
{% for key, action in plugin.getActionBar().push|default([]) %}
{% if firstButton %}
<button class="default_action results_window btn btn-inverse" data-selection-source="search-result">
<a class="results_window {{ action.classes|default('') }}" data-selection-source="search-result">
{% if action.icon %}
<img src="{{ plugin_asset(plugin.PluginName, action.icon) }}" height="16" width="16"/>
{% endif %}
{{ action.label|trans({}, plugin.PluginLocale) }}
</a>
</button>
{% if not (loop.last and loop.parent.loop.last) %}
<button class="trigger btn btn-inverse dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
<ul class="submenu dropdown-menu">
{% endif %}
{% if not loop.first %}<li class="divider"></li>{% endif %}
{% if not firstButton %}
<li> <li>
<a class="results_window {{ action.classes|default('') }}" data-selection-source="search-result"> <a class="results_window {{ menu_entry.class }}" data-selection-source="search-result">
{% if action.icon %} <img src="{{ menu_entry.icon }}" class="btn-image"/>
<img src="{{ plugin_asset(plugin.PluginName, action.icon) }}" height="16" width="16" class="btn-image"/> {{ menu_entry.label }}
{% endif %}
{{ action.label|trans({}, plugin.PluginLocale) }}
</a> </a>
</li> </li>
{% else %} {% endfor %}
{% set firstButton = false %} </ul>
{% endif %} {% endif %}
{% endif %} </div>
{% endfor %} </span>
{% endfor %} {% endif %}
{% if not firstButton %} {% endfor %}
</ul>
{% endif %}
</div>
</span>
{% endif %}
{% if acl.has_right(constant('\\ACL::IMGTOOLS')) %}
<span class="classicButton">
<div class="btn-group">
<button class="TOOL_imgtools_btn results_window btn btn-inverse" data-selection-source="search-result">
<img src="/assets/common/images/icons/imgtools_history.png" height="16" width="16" class="btn-image"/> {{ 'action : outils' | trans }}
</button>
</div>
</span>
{% endif %}
{% if acl.has_right(constant('\\ACL::CANDELETERECORD')) %}
<span class="classicButton">
<div class="btn-group">
<button class="TOOL_trash_btn results_window btn btn-inverse" data-selection-source="search-result">
<img src="/assets/common/images/icons/delete.png" height="16" width="16" class="btn-image"/> {{ 'action : supprimer' | trans }}
</button>
</div>
</span>
{% endif %}
{% endblock %} {% endblock %}
{% block toolbarJS %} {% block toolbarJS %}
{% if plugins.actionbar is not empty %} {% if plugins.actionbar is not empty %}
{% for plugin in plugins.actionbar %} {% for pluginId, plugin in plugins.actionbar %}
{{ (plugin.JS|default(''))|raw }} {% if plugin.getActionBarTemplate is defined %}
{% endfor %} {% set template = plugin.getActionBarTemplate() %}
{% if template %}
{% include template with {'app': app, 'plugin_id': pluginId, 'plugin': plugin} only %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View File

@@ -35,7 +35,7 @@
<ul class="unstyled"> <ul class="unstyled">
{% for file in lazaretFiles %} {% for file in lazaretFiles %}
<li class="row-fluid wrapper-item well"> <li class="row-fluid wrapper-item well">
{{ _self.lazaretElement(app, file) }} {{ _self.lazaretElement(app, file) }}
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
@@ -48,56 +48,56 @@
</div> </div>
<script> <script>
$('document').ready(function(){ $('document').ready(function () {
$(".btn-group.emptying").hide(); $(".btn-group.emptying").hide();
var scope = $('#lazaretBox'); var scope = $('#lazaretBox');
$("#tab-lazaret").scrollTop(0); $("#tab-lazaret").scrollTop(0);
function getLazaretId(el){ function getLazaretId(el) {
return el.closest('div.lazaret-file').find('input[name=lazaret_file]').val(); return el.closest('div.lazaret-file').find('input[name=lazaret_file]').val();
} }
function getDestinationId(el){ function getDestinationId(el) {
return el.closest('div.lazaret-file').find('input[name=lazaret_file_destination]').val(); return el.closest('div.lazaret-file').find('input[name=lazaret_file_destination]').val();
} }
function startAjax(button){ function startAjax(button) {
button.closest(".btn-group").find('button').prop('disabled', true); button.closest(".btn-group").find('button').prop('disabled', true);
button.closest(".btn-group").addClass('loading'); button.closest(".btn-group").addClass('loading');
} }
function stopAjax(button){ function stopAjax(button) {
button.closest(".btn-group").find('button').prop('disabled', false); button.closest(".btn-group").find('button').prop('disabled', false);
button.closest(".btn-group").removeClass('loading'); button.closest(".btn-group").removeClass('loading');
} }
function reloadContent(force){ function reloadContent(force) {
var nbItems = scope.find(".wrapper-item").length; var nbItems = scope.find(".wrapper-item").length;
if( nbItems === 0 || force === true) { if (nbItems === 0 || force === true) {
$.ajax({ $.ajax({
url:'/prod/lazaret/', url: '/prod/lazaret/',
beforeSend: function(){ beforeSend: function () {
$("#lazaretBox").empty().append(language.loading ); $("#lazaretBox").empty().append(language.loading);
}, },
success: function(data) { success: function (data) {
scope.empty().append(data); scope.empty().append(data);
}, },
error : function() { error: function () {
$("#lazaretBox").empty().append(language.errorAjaxRequest); $("#lazaretBox").empty().append(language.errorAjaxRequest);
} }
}); });
} }
} }
$(".records-subititution .diapo", scope) /* $(".records-subititution .diapo", scope)
.bind('click', function(e){ .bind('click', function(e){
$(this).closest('.lazaret-proposals').find('.diapo').removeClass('selected'); $(this).closest('.lazaret-proposals').find('.diapo').removeClass('selected');
$(this).addClass('selected'); $(this).addClass('selected');
} }
); );*/
$(".records-subititution .captionTips", scope).tooltip(); $(".records-subititution .captionTips", scope).tooltip();
$(".records-subititution .infoTips", scope).tooltip(); $(".records-subititution .infoTips", scope).tooltip();
@@ -106,23 +106,23 @@
var emptying = false; // true=emptying, set to false to stop var emptying = false; // true=emptying, set to false to stop
// stop emptying lazaret // stop emptying lazaret
$('button.stopempty-lazaret', scope).bind('click', function() { $('button.stopempty-lazaret', scope).bind('click', function () {
emptying = false; emptying = false;
}); });
// empty lazaret // empty lazaret
$('button.empty-lazaret', scope).bind('click', function(){ $('button.empty-lazaret', scope).bind('click', function () {
var that = $(this); var that = $(this);
if(!confirm("{{ "Empty quarantine will remove all items, are you sure you want to continue ?" | trans }}")) { if (!confirm("{{ "Empty quarantine will remove all items, are you sure you want to continue ?" | trans }}")) {
return false; return false;
} }
$(".btn-group.empty").hide(); $(".btn-group.empty").hide();
$(".btn-group.emptying").show(); $(".btn-group.emptying").show();
var f = function() { var f = function () {
var todo = 0; var todo = 0;
var msg_html = ""; var msg_html = "";
$.ajax({ $.ajax({
@@ -135,7 +135,7 @@
success: function (data) { success: function (data) {
if (data.success) { if (data.success) {
todo = data.result.todo; todo = data.result.todo;
$("#QUARANTINE_TOOLBAR_EMPTYING_TODO").text(""+todo); $("#QUARANTINE_TOOLBAR_EMPTYING_TODO").text("" + todo);
} else { } else {
emptying = false; // force stop emptying = false; // force stop
msg_html = _.template($("#alert_error_tpl").html(), { msg_html = _.template($("#alert_error_tpl").html(), {
@@ -150,67 +150,72 @@
}); });
} }
}) })
.done(function(data) { .done(function (data) {
if(emptying && todo > 0) { if (emptying && todo > 0) {
window.setTimeout(f, 500); // wait between loops window.setTimeout(f, 500); // wait between loops
}
})
.fail(function() {
emptying = false; // force stop
})
.always(function(){
if(!emptying || todo <= 0) {
$(".btn-group.emptying").hide();
$(".btn-group.empty").show();
if(msg_html != "") {
$("#QUARANTINE_TOOLBAR_EMPTYING_MSG").html(msg_html);
} }
else { })
reloadContent(true); .fail(function () {
emptying = false; // force stop
})
.always(function () {
if (!emptying || todo <= 0) {
$(".btn-group.emptying").hide();
$(".btn-group.empty").show();
if (msg_html != "") {
$("#QUARANTINE_TOOLBAR_EMPTYING_MSG").html(msg_html);
}
else {
reloadContent(true);
}
} }
} });
});
}; };
// start emptying // start emptying
emptying = true; emptying = true;
f(); f();
}); });
var data;
//add lazaret file click action //add lazaret file click action
$("button.add-lazaret", scope).bind('click', function(){ $("button.add-lazaret", scope).bind('click', function () {
var that = $(this); var that = $(this);
var lazaretId = getLazaretId(that); var lazaretId = getLazaretId(that);
var destinationCollectionId = getDestinationId(that); var destinationCollectionId = getDestinationId(that);
var container = $(this).closest('.wrapper-item');
var form = $(this).closest("form");
/*fix POST on firefox*/
data = form.serializeArray();
var allData = that.parent().closest('.wrapper-item').find(".change-record-wrapper").html();
that.closest(".form-backup ").append(allData);
that.parent().closest('.wrapper-item').find(".change-record ").remove();
$.ajax({ $.ajax({
type : 'POST', type: 'POST',
url: '/prod/lazaret/'+lazaretId+'/force-add/', url: '/prod/lazaret/' + lazaretId + '/force-add/',
dataType: 'json', dataType: 'json',
data : { data: data,
bas_id:destinationCollectionId, beforeSend: function () {
keep_attributes: 1
},
beforeSend: function(){
startAjax(that); startAjax(that);
}, },
success: function(data){ success: function (data) {
if(data.success){ if (data.success) {
that.closest(".wrapper-item").remove(); container.remove();
}else{ } else {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content:data.message content: data.message
}); });
that.closest(".diapo").append(html); that.closest(".diapo").append(html);
} }
}, },
error: function(){ error: function () {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content:language.errorAjaxRequest content: language.errorAjaxRequest
}); });
that.closest(".diapo").append(html); that.closest(".diapo").append(html);
}, },
complete: function(){ complete: function () {
stopAjax(that); stopAjax(that);
reloadContent(); reloadContent();
} }
@@ -218,42 +223,131 @@
}); });
//delete lazaret file click action //delete lazaret file click action
$("button.delete-lazaret", scope).bind('click', function(){ $("button.delete-lazaret", scope).bind('click', function () {
var that = $(this); var that = $(this);
var lazaretId = getLazaretId(that); var lazaretId = getLazaretId(that);
var container = $(this).closest('.wrapper-item');
var form = $(this).closest("form");
data = form.serializeArray();
var allData = that.parent().closest('.wrapper-item').find(".change-record-wrapper").html();
that.closest(".form-backup ").append(allData);
that.parent().closest('.wrapper-item').find(".change-record ").remove();
$.ajax({ $.ajax({
type : 'POST', type: 'POST',
url: '/prod/lazaret/'+lazaretId+'/deny/', url: '/prod/lazaret/' + lazaretId + '/deny/',
dataType: 'json', dataType: 'json',
beforeSend: function(){ beforeSend: function () {
startAjax(that); startAjax(that);
}, },
success: function(data){ success: function (data) {
if(data.success){ if (data.success) {
that.closest(".wrapper-item").remove(); container.remove();
}else{ } else {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content:data.message content: data.message
}); });
that.closest(".diapo").append(html); that.closest(".diapo").append(html);
} }
}, },
error: function(){ error: function () {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content:language.errorAjaxRequest content: language.errorAjaxRequest
}); });
that.closest(".diapo").append(html); that.closest(".diapo").append(html);
}, },
complete: function(){ complete: function () {
stopAjax(that); stopAjax(that);
reloadContent(); reloadContent();
} }
}); });
}); });
//update status list
function resetStatus(that) {
that.removeClass('selected');
var html = that.parent().closest('.wrapper-item').find(".status-backup").html();
that.parent().closest('.wrapper-item').find(".status-container").html('');
that.parent().closest('.wrapper-item').find(".status-container").append(html);
};
$(".span12 img, .reset-status").click(function () {
var that = $(this).closest('.wrapper-item').find('.lazaret-proposals .diapo');
resetStatus(that);
});
$(".records-subititution .diapo", scope).bind('click', function () {
var that = $(this);
var diapo = that.closest('.lazaret-proposals').find('.diapo');
var container = that.closest('.wrapper-item');
diapo.not(this).removeClass('selected');
/*Set selected or not to check for sending ajax request*/
if (that.hasClass("selected")) {
resetStatus(that);
} else {
that.addClass('selected');
var elements = $(".selected", container);
var recordId = elements.first().attr("data-record_id");
var sBas = elements.first().attr("sbas");
$.ajax({
type: 'GET',
url: '/prod/lazaret/' + sBas + '/' + recordId + '/status',
dataType: 'json',
beforeSend: function () {
startAjax(that);
},
success: function (data) {
if (data.status) {
html = '';
for ([key, value] of Object.entries(data.status)) {
if (value.flag == 1) {
checkValOff = '';
checkValOn = 'checked=checked';
} else {
checkValOff = 'checked=checked';
checkValOn = '';
}
var labelOff = value['labels_off_i18n']["{{ app['locale'] }}"];
var labelOn = value['labels_on_i18n']["{{ app['locale'] }}"];
if (labelOff == null || labelOff == "") {
labelOff = 'off';
}
if (labelOn == null || labelOn == "") {
labelOn = 'on';
}
html += '<tr>';
html += '<td class="status-tab-left">';
if (value['img_off'] != null) {
html += ' <img src="{{ value['img_off'] }}" width="16" height="16" />';
}
;
html += '<span>' + labelOff + '</span>';
html += '<input type="radio" name="status[' + sBas + '][' + value.bit + ']" value="0" ' + checkValOff + ' />';
html += '</td>';
html += '<td class="status-tab-right">';
html += '<input type="radio" name="status[' + sBas + '][' + value.bit + ']" value="1" ' + checkValOn + ' />';
html += '<span>' + labelOn + '</span>';
if (value['img_on'] != null) {
html += '<img src="' + value['img_on'] + '" width="16" height="16" />';
}
;
html += '</td>';
html += '</tr>';
}
;
that.parent().closest('.wrapper-item').find(".status-container").html('');
that.parent().closest('.wrapper-item').find(".status-container").append(html);
}
},
complete: function () {
stopAjax(that);
reloadContent();
}
});
}
});
//substitute lazaret file click action //substitute lazaret file click action
$("button.subtitute-lazaret", scope).bind('click', function(){ $("button.subtitute-lazaret", scope).bind('click', function () {
var that = $(this); var that = $(this);
var lazaretId = getLazaretId(that); var lazaretId = getLazaretId(that);
var container = $(this).closest('.wrapper-item'); var container = $(this).closest('.wrapper-item');
@@ -262,70 +356,77 @@
var elements = []; var elements = [];
var nbElement = 0; var nbElement = 0;
if(nbProposals >= 1){ if (nbProposals >= 1) {
elements = $(".selected", container); elements = $(".selected", container);
nbElement = elements.length; nbElement = elements.length;
}else{ } else {
return false; return false;
} }
if(nbElement === 0){ if (nbElement === 0) {
alert(language.selectOneRecord); alert(language.selectOneRecord);
return false; return false;
}else if(nbElement > 1){ } else if (nbElement > 1) {
alert(language.onlyOneRecord); alert(language.onlyOneRecord);
return false; return false;
} }
var recordId = elements.first().attr("data-record_id"); var recordId = elements.first().attr("data-record_id");
var form = $(this).closest("form");
$(".record_id").val(recordId);
var form = $(this).closest("form");
data = form.serializeArray();
var allData = that.parent().closest('.wrapper-item').find(".change-record-wrapper").html();
that.closest(".form-backup ").append(allData);
that.parent().closest('.wrapper-item').find(".change-record ").remove();
$.ajax({ $.ajax({
type : 'POST', type: 'POST',
url: '/prod/lazaret/'+lazaretId+'/accept/', url: '/prod/lazaret/' + lazaretId + '/accept/',
dataType: 'json', dataType: 'json',
data:{ data: data,
record_id: recordId beforeSend: function () {
startAjax(that);
}, },
beforeSend: function(){ success: function (data) {
startAjax(that); if (data.success) {
}, container.remove();
success: function(data){ } else {
if(data.success){
that.closest(".wrapper-item").remove();
}else{
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content:data.message content: data.message
}); });
that.closest(".diapo").append(html); that.closest(".diapo").append(html);
} }
}, },
error: function(){ error: function () {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content:language.errorAjaxRequest content: language.errorAjaxRequest
}); });
that.closest(".diapo").append(html); that.closest(".diapo").append(html);
}, },
complete: function(){ complete: function () {
stopAjax(that); stopAjax(that);
reloadContent(); reloadContent();
} }
}); });
}); });
/*Toggle status block*/
$(".toggle-status").click(function () {
$(this).nextAll('.status-wrapper').first().toggleClass('hidden');
});
}); });
</script> </script>
<style>
.lazaret-proposals .diapo {
float:none;
}
</style>
{% macro lazaretElement(app, file) %} {% macro lazaretElement(app, file) %}
{% import "common/thumbnail.html.twig" as thumb %} {% import "common/thumbnail.html.twig" as thumb %}
{% set records = file.getRecordsToSubstitute(app, true) %} {% set records = file.getRecordsToSubstitute(app, true) %}
<div class="lazaret-file span4"> <div class="lazaret-file span4">
<h5>{{ "Last uploaded version" | trans }}</h5> <h5>{{ "Last uploaded version" | trans }}</h5>
<ul class="thumbnails"> <ul class="thumbnails">
<li class="span12" > <li class="span12">
<div class="thumbnail"> <div class="thumbnail">
<img src="/prod/lazaret/{{ file.getId() }}/thumbnail/"/> <img src="/prod/lazaret/{{ file.getId() }}/thumbnail/"/>
<div class="caption"> <div class="caption">
@@ -344,19 +445,128 @@
<p>{{ border_checker_from_fqcn(check.getCheckClassname()).getMessage(app['translator']) }}</p> <p>{{ border_checker_from_fqcn(check.getCheckClassname()).getMessage(app['translator']) }}</p>
{% endfor %} {% endfor %}
</div> </div>
<div class="btn-group" style="text-align:center; padding:5px;"> <form class="change-record" name="change-records-status" action="/" method="POST">
<button class="btn add-lazaret" title="{{ "Add" | trans }}"> <div class="change-record-wrapper">
<img src="/assets/common/images/icons/add.png" width="16" height="16" class="btn-image">{{ "Add" | trans }} {% set collection = file.getCollection(app) %}
</button> <input type="hidden" name="bas_id" value="{{ collection.get_base_id() }}">
<button class="btn delete-lazaret" title="{{ "Delete" | trans }}"> <input type="hidden" name="keep_attributes" value="1">
<img src="/assets/common/images/icons/delete.png" width="16" height="16" class="btn-image">{{ "Delete" | trans }} <input class="record_id" type="hidden" name="record_id">
</button> <div class="update-status">
{% if records|length > 0 %} <div id="status-{{ collection.get_base_id() }}" class='collection-status'>
<button class="btn subtitute-lazaret" title="{{ "Substitute" | trans }}"> <a href="#" class="reset-status btn">Reset status</a>
<img src="/assets/common/images/icons/reload.png" width="16" height="16" class="btn-image">{{ "Substitute" | trans }} <h5 class="toggle-status">{{ 'upload:: Status :' | trans }} <img src="/assets/common/images/icons/icon-right-arrow.svg" width="10" height="10" class="btn-status"></h5>
</button> <div class="status-wrapper hidden">
<table style="margin: auto">
<tbody class="status-container">
{% if file.getStatus(app) is not null %}
{% for bit, status in file.getStatus(app) %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16" />
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" {% if status['flag'] == 0 %}checked="checked"{% endif%}/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" {% if status['flag'] == 1 %}checked="checked"{% endif%} />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16" />
{% endif %}
</td>
</tr>
{% endfor %}
{% else %}
{% for bit, status in collection.get_databox().getStatusStructure() %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16" />
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" checked="checked"/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16" />
{% endif %}
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
<div class="btn-group" style="text-align:center; padding:5px;">
<button class="btn add-lazaret" title="{{ "Add" | trans }}">
<img src="/assets/common/images/icons/add.png" width="16" height="16" class="btn-image">{{ "Add" | trans }}
</button>
<button class="btn delete-lazaret" title="{{ "Delete" | trans }}">
<img src="/assets/common/images/icons/delete.png" width="16" height="16" class="btn-image">{{ "Delete" | trans }}
</button>
{% if records|length > 0 %}
<button class="btn subtitute-lazaret" title="{{ "Substitute" | trans }}">
<img src="/assets/common/images/icons/reload.png" width="16" height="16" class="btn-image">{{ "Substitute" | trans }}
</button>
{% endif %}
</div>
</div>
</form>
<div class="hidden form-backup"></div>
{# bloc to backup initial value of status list#}
<table class="hidden">
<tbody class="status-backup">
{% if file.getStatus(app) is not null %}
{% for bit, status in file.getStatus(app) %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16"/>
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" {% if status['flag'] == 0 %}checked="checked"{% endif%}/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" {% if status['flag'] == 1 %}checked="checked"{% endif%} />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16"/>
{% endif %}
</td>
</tr>
{% endfor %}
{% else %}
{% for bit, status in collection.get_databox().getStatusStructure() %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16" />
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" checked="checked"/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16" />
{% endif %}
</td>
</tr>
{% endfor %}
{% endif %} {% endif %}
</div> </tbody>
</table>
</div> </div>
</li> </li>
</ul> </ul>
@@ -369,11 +579,11 @@
{% if record_count > 0 %} {% if record_count > 0 %}
<div class="lazaret-proposals span8"> <div class="lazaret-proposals span8">
<h5> <h5>
{% if record_count <= 1 %} {% if record_count <= 1 %}
{% trans %}A record matches the unique identifier :{% endtrans %} {% trans %}A record matches the unique identifier :{% endtrans %}
{% else %} {% else %}
{% trans with {'%record_count%' : record_count} %}%record_count% records match the unique identifier :{% endtrans %} {% trans with {'%record_count%' : record_count} %}%record_count% records match the unique identifier :{% endtrans %}
{% endif %} {% endif %}
</h5> </h5>
<ul class="thumbnails"> <ul class="thumbnails">
{% for record in records %} {% for record in records %}
@@ -383,15 +593,15 @@
and app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), constant('\\ACL::CANDELETERECORD')) %} and app.getAclForUser(app.getAuthenticatedUser()).has_right_on_base(record.get_base_id(), constant('\\ACL::CANDELETERECORD')) %}
<li class="records-subititution span3" style="width:210px"> <li class="records-subititution span3" style="width:210px">
{% include 'prod/results/record.html.twig' with { {% include 'prod/results/record.html.twig' with {
'record': record, 'record': record,
'settings': { 'settings': {
'images_size': 169, 'images_size': 169,
'technical_display': '1', 'technical_display': '1',
'rollover_thumbnail': 'caption', 'rollover_thumbnail': 'caption',
'doctype_display': '1', 'doctype_display': '1',
'handle_dblclick' : false, 'handle_dblclick' : false,
'show_context_menu': false 'show_context_menu': false
} }
} %} } %}
<div class="caption"> <div class="caption">
{% for reason in reasons %} {% for reason in reasons %}
@@ -406,3 +616,30 @@
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
<style>
.lazaret-proposals .diapo {
float:none;
}
.collection-status {
margin: 0 11px 14px;
background: #f5f5f5;
padding-bottom: 10px;
color: #151515;
}
.collection-status h5 {
padding: 10px 10px 0 10px;
cursor: pointer;
margin-bottom: 0;
}
.reset-status {
display: inline-block;
float: right;
background: #fff;
border: 1px solid;
padding: 2px 5px;
margin-top: -4px;
margin-right: -6px;
}
</style>

View File

@@ -230,6 +230,7 @@ class FieldsTest extends \PhraseanetAuthenticatedWebTestCase
'vocabulary-type' => 'User', 'vocabulary-type' => 'User',
'vocabulary-restricted' => true, 'vocabulary-restricted' => true,
'gui_editable' => true, 'gui_editable' => true,
'gui_visible' => true,
'generate_cterms' => true, 'generate_cterms' => true,
]); ]);

View File

@@ -48,6 +48,7 @@ class TextNodeTest extends \PHPUnit_Framework_TestCase
$query_context->getUnrestrictedFields()->willReturn([$field]); $query_context->getUnrestrictedFields()->willReturn([$field]);
$query_context->getPrivateFields()->willReturn([]); $query_context->getPrivateFields()->willReturn([]);
$query_context->localizeField($field)->willReturn(['foo.fr', 'foo.en']); $query_context->localizeField($field)->willReturn(['foo.fr', 'foo.en']);
$query_context->truncationField($field)->willReturn([]);
$node = new TextNode('bar', new Context('baz')); $node = new TextNode('bar', new Context('baz'));
$query = $node->buildQuery($query_context->reveal()); $query = $node->buildQuery($query_context->reveal());
@@ -80,12 +81,18 @@ class TextNodeTest extends \PHPUnit_Framework_TestCase
$query_context $query_context
->localizeField($public_field) ->localizeField($public_field)
->willReturn(['foo.fr', 'foo.en']); ->willReturn(['foo.fr', 'foo.en']);
$query_context
->truncationField($public_field)
->willReturn([]);
$query_context $query_context
->getPrivateFields() ->getPrivateFields()
->willReturn([$private_field]); ->willReturn([$private_field]);
$query_context $query_context
->localizeField($private_field) ->localizeField($private_field)
->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']); ->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']);
$query_context
->truncationField($private_field)
->willReturn([]);
$node = new TextNode('baz'); $node = new TextNode('baz');
$query = $node->buildQuery($query_context->reveal()); $query = $node->buildQuery($query_context->reveal());
@@ -136,6 +143,7 @@ class TextNodeTest extends \PHPUnit_Framework_TestCase
$query_context->getUnrestrictedFields()->willReturn([$field]); $query_context->getUnrestrictedFields()->willReturn([$field]);
$query_context->getPrivateFields()->willReturn([]); $query_context->getPrivateFields()->willReturn([]);
$query_context->localizeField($field)->willReturn(['foo.fr', 'foo.en']); $query_context->localizeField($field)->willReturn(['foo.fr', 'foo.en']);
$query_context->truncationField($field)->willReturn([]);
$node = new TextNode('bar'); $node = new TextNode('bar');
$node->setConcepts([ $node->setConcepts([
@@ -180,12 +188,18 @@ class TextNodeTest extends \PHPUnit_Framework_TestCase
$query_context $query_context
->localizeField($public_field) ->localizeField($public_field)
->willReturn(['foo.fr', 'foo.en']); ->willReturn(['foo.fr', 'foo.en']);
$query_context
->truncationField($public_field)
->willReturn([]);
$query_context $query_context
->getPrivateFields() ->getPrivateFields()
->willReturn([$private_field]); ->willReturn([$private_field]);
$query_context $query_context
->localizeField($private_field) ->localizeField($private_field)
->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']); ->willReturn(['private_caption.bar.fr', 'private_caption.bar.en']);
$query_context
->truncationField($private_field)
->willReturn([]);
$node = new TextNode('baz'); $node = new TextNode('baz');
$node->setConcepts([ $node->setConcepts([

View File

@@ -18,7 +18,7 @@ class QueryContextTest extends \PHPUnit_Framework_TestCase
{ {
$structure = $this->prophesize(Structure::class)->reveal(); $structure = $this->prophesize(Structure::class)->reveal();
$available_locales = ['ab', 'cd', 'ef']; $available_locales = ['ab', 'cd', 'ef'];
$context = new QueryContext($structure, $available_locales, 'fr'); $context = new QueryContext(null, $structure, $available_locales, 'fr');
$narrowed = $context->narrowToFields(['some_field']); $narrowed = $context->narrowToFields(['some_field']);
$this->assertEquals(['some_field'], $narrowed->getFields()); $this->assertEquals(['some_field'], $narrowed->getFields());
} }
@@ -33,10 +33,10 @@ class QueryContextTest extends \PHPUnit_Framework_TestCase
'bar' => $bar_field 'bar' => $bar_field
]); ]);
$context = new QueryContext($structure->reveal(), [], 'fr'); $context = new QueryContext(null, $structure->reveal(), [], 'fr');
$this->assertEquals([$foo_field, $bar_field], $context->getUnrestrictedFields()); $this->assertEquals([$foo_field, $bar_field], $context->getUnrestrictedFields());
$narrowed_context = new QueryContext($structure->reveal(), [], 'fr', ['foo']); $narrowed_context = new QueryContext(null, $structure->reveal(), [], 'fr', ['foo']);
$this->assertEquals([$foo_field], $narrowed_context->getUnrestrictedFields()); $this->assertEquals([$foo_field], $narrowed_context->getUnrestrictedFields());
} }
@@ -50,10 +50,10 @@ class QueryContextTest extends \PHPUnit_Framework_TestCase
'bar' => $bar_field 'bar' => $bar_field
]); ]);
$context = new QueryContext($structure->reveal(), [], 'fr'); $context = new QueryContext(null, $structure->reveal(), [], 'fr');
$this->assertEquals([$foo_field, $bar_field], $context->getPrivateFields()); $this->assertEquals([$foo_field, $bar_field], $context->getPrivateFields());
$narrowed_context = new QueryContext($structure->reveal(), [], 'fr', ['foo']); $narrowed_context = new QueryContext(null, $structure->reveal(), [], 'fr', ['foo']);
$this->assertEquals([$foo_field], $narrowed_context->getPrivateFields()); $this->assertEquals([$foo_field], $narrowed_context->getPrivateFields());
} }
} }

View File

@@ -36,6 +36,7 @@ class StructureTest extends \PHPUnit_Framework_TestCase
$field->isFacet()->willReturn(false); $field->isFacet()->willReturn(false);
$field->hasConceptInference()->willReturn(false); $field->hasConceptInference()->willReturn(false);
$field->getDependantCollections()->willReturn(['1']); $field->getDependantCollections()->willReturn(['1']);
$field->get_databox_id()->willReturn('1');
$structure->add($field->reveal()); $structure->add($field->reveal());
$this->assertCount(1, $structure->getAllFields()); $this->assertCount(1, $structure->getAllFields());
@@ -60,6 +61,7 @@ class StructureTest extends \PHPUnit_Framework_TestCase
$field->isPrivate()->willReturn(false); $field->isPrivate()->willReturn(false);
$field->isFacet()->willReturn(false); $field->isFacet()->willReturn(false);
$field->hasConceptInference()->willReturn(false); $field->hasConceptInference()->willReturn(false);
$field->get_databox_id()->willReturn('1');
$other = new Field('foo', FieldMapping::TYPE_STRING); $other = new Field('foo', FieldMapping::TYPE_STRING);

View File

@@ -14,14 +14,14 @@ use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Typed;
class ValueCheckerTest extends \PHPUnit_Framework_TestCase class ValueCheckerTest extends \PHPUnit_Framework_TestCase
{ {
/** /**
* @dataProvider escapeRawProvider * @dataProvider valueCheckerProvider
*/ */
public function testValueCompatibility($subject, $value, $compatible) public function testValueCompatibility($subject, $value, $compatible)
{ {
$this->assertEquals($compatible, ValueChecker::isValueCompatible($subject, $value)); $this->assertEquals($compatible, ValueChecker::isValueCompatible($subject, $value));
} }
public function escapeRawProvider() public function valueCheckerProvider()
{ {
$values = [ $values = [
[FieldMapping::TYPE_FLOAT , 42 , true ], [FieldMapping::TYPE_FLOAT , 42 , true ],

View File

@@ -28,6 +28,7 @@ define([
"tbranch": "", "tbranch": "",
"generate_cterms": false, "generate_cterms": false,
"gui_editable": true, "gui_editable": true,
"gui_visible": true,
"separator": "", "separator": "",
"required": false, "required": false,
"report": true, "report": true,

View File

@@ -52,6 +52,10 @@ define([
this.field.get('gui_editable').should.equal("1"); this.field.get('gui_editable').should.equal("1");
}); });
it("should default gui_visible property to '1'", function () {
this.field.get('gui_visible').should.equal("1");
});
it("should default separator property to 'empty'", function () { it("should default separator property to 'empty'", function () {
this.field.get('separator').should.equal(""); this.field.get('separator').should.equal("");
}); });

View File

@@ -3815,9 +3815,9 @@ fsevents@^1.0.0, fsevents@^1.1.2, fsevents@^1.2.7:
node-pre-gyp "^0.12.0" node-pre-gyp "^0.12.0"
fstream@^1.0.0, fstream@^1.0.2: fstream@^1.0.0, fstream@^1.0.2:
version "1.0.11" version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
dependencies: dependencies:
graceful-fs "^4.1.2" graceful-fs "^4.1.2"
inherits "~2.0.0" inherits "~2.0.0"
@@ -4049,7 +4049,7 @@ glob@^5.0.15:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1:
version "7.1.4" version "7.1.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
@@ -4061,6 +4061,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@^7.1.3:
version "7.1.6"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@~3.1.21: glob@~3.1.21:
version "3.1.21" version "3.1.21"
resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd" resolved "https://registry.yarnpkg.com/glob/-/glob-3.1.21.tgz#d29e0a055dea5138f4d07ed40e8982e83c2066cd"
@@ -4166,10 +4178,10 @@ graceful-fs@^3.0.0:
dependencies: dependencies:
natives "^1.1.0" natives "^1.1.0"
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@~4.1.4: graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9:
version "4.1.15" version "4.2.3"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA== integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
graceful-fs@~1.2.0: graceful-fs@~1.2.0:
version "1.2.3" version "1.2.3"
@@ -4181,6 +4193,11 @@ graceful-fs@~2.0.0:
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-2.0.3.tgz#7cd2cdb228a4a3f36e95efa6cc142de7d1a136d0"
integrity sha1-fNLNsiiko/Nule+mzBQt59GhNtA= integrity sha1-fNLNsiiko/Nule+mzBQt59GhNtA=
graceful-fs@~4.1.4:
version "4.1.15"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
"graceful-readlink@>= 1.0.0": "graceful-readlink@>= 1.0.0":
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
@@ -4757,7 +4774,12 @@ inherits@1:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b"
integrity sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js= integrity sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
inherits@2.0.3:
version "2.0.3" version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
@@ -5974,9 +5996,9 @@ lodash.keys@~2.4.1:
lodash.isobject "~2.4.1" lodash.isobject "~2.4.1"
lodash.merge@^4.6.0: lodash.merge@^4.6.0:
version "4.6.1" version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.1.tgz#adc25d9cb99b9391c59624f379fbba60d7111d54" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ== integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.restparam@^3.0.0: lodash.restparam@^3.0.0:
version "3.6.1" version "3.6.1"
@@ -6483,9 +6505,9 @@ mitt@^1.1.3:
integrity sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA== integrity sha512-mUDCnVNsAi+eD6qA0HkRkwYczbLHJ49z17BGe2PYRhZL4wpZUFZGJHU7/5tmvohoma+Hdn0Vh/oJTiPEmgSruA==
mixin-deep@^1.2.0: mixin-deep@^1.2.0:
version "1.3.1" version "1.3.2"
resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.1.tgz#a49e7268dce1a0d9698e45326c5626df3543d0fe" resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
integrity sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ== integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
dependencies: dependencies:
for-in "^1.0.2" for-in "^1.0.2"
is-extendable "^1.0.1" is-extendable "^1.0.1"
@@ -7555,10 +7577,10 @@ phraseanet-common@^0.4.1:
js-cookie "^2.1.0" js-cookie "^2.1.0"
pym.js "^1.3.1" pym.js "^1.3.1"
phraseanet-production-client@0.34.72-d: phraseanet-production-client@0.34.80-d:
version "0.34.72-d" version "0.34.80-d"
resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.72-d.tgz#028a5ccd589e696b5433eea9d53d9367966613c8" resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.80-d.tgz#1e54bee4306ab11528377cb63c19d8c7491ef0f3"
integrity sha512-IPaDRqXwyJegoKmzr56bggxTzN4TnmuAqU4O7rDEhh0aqdCiuC8rlH/yzKoLeEIMSrESCw5mBhrI//ccntvv9w== integrity sha512-ilGs7ndDNztwlyeW9MA2TMiMhZC+P1/lNNeIsIuh+KuJH8M3Y3SWBcmsN2lqu5iM1Xg5FbWJ6iXcCSrLWHTqsw==
dependencies: dependencies:
"@mapbox/mapbox-gl-language" "^0.9.2" "@mapbox/mapbox-gl-language" "^0.9.2"
"@turf/turf" "^5.1.6" "@turf/turf" "^5.1.6"
@@ -8296,9 +8318,9 @@ right-align@^0.1.1:
align-text "^0.1.1" align-text "^0.1.1"
rimraf@2, rimraf@^2.2.8, rimraf@^2.5.0, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: rimraf@2, rimraf@^2.2.8, rimraf@^2.5.0, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3:
version "2.6.3" version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies: dependencies:
glob "^7.1.3" glob "^7.1.3"