mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-23 18:03:17 +00:00
Merge branch 'master' into doctrine-metadata-cache
This commit is contained in:
12
Dockerfile
12
Dockerfile
@@ -36,7 +36,11 @@ RUN apt-get update \
|
||||
xpdf \
|
||||
&& update-locale "LANG=fr_FR.UTF-8 UTF-8" \
|
||||
&& dpkg-reconfigure --frontend noninteractive locales \
|
||||
&& docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \
|
||||
&& docker-php-source extract \
|
||||
&& docker-php-ext-install -j$(nproc) gd \
|
||||
&& docker-php-ext-install zip exif iconv mbstring pcntl sockets xsl intl pdo_mysql gettext bcmath mcrypt \
|
||||
&& pecl install redis amqp-1.9.3 zmq-beta imagick-beta \
|
||||
@@ -126,6 +130,12 @@ RUN mkdir -p /var/alchemy/Phraseanet/logs \
|
||||
|
||||
FROM phraseanet-system as phraseanet-fpm
|
||||
|
||||
RUN docker-php-source extract \
|
||||
&& pecl install xdebug-2.9.0 \
|
||||
&& docker-php-ext-enable xdebug \
|
||||
#&& pecl clear-cache \
|
||||
&& docker-php-source delete
|
||||
|
||||
COPY --from=builder --chown=app /var/alchemy /var/alchemy/Phraseanet
|
||||
ADD ./docker/phraseanet/ /
|
||||
WORKDIR /var/alchemy/Phraseanet
|
||||
|
15
bin/console
15
bin/console
@@ -23,7 +23,9 @@ use Alchemy\Phrasea\Command\SearchEngine\IndexPopulateCommand;
|
||||
use Alchemy\Phrasea\Command\Thesaurus\FindConceptsCommand;
|
||||
use Alchemy\Phrasea\Core\Version;
|
||||
use Alchemy\Phrasea\Command\CreateCollection;
|
||||
use Alchemy\Phrasea\Command\Collection\ListCollectionCommand;
|
||||
use Alchemy\Phrasea\Command\Databox\CreateDataboxCommand;
|
||||
use Alchemy\Phrasea\Command\Databox\ListDataboxCommand;
|
||||
use Alchemy\Phrasea\Command\MailTest;
|
||||
use Alchemy\Phrasea\Command\Compile\Configuration;
|
||||
use Alchemy\Phrasea\Command\RecordAdd;
|
||||
@@ -46,6 +48,9 @@ use Alchemy\Phrasea\Command\Task\TaskRun;
|
||||
use Alchemy\Phrasea\Command\Task\TaskStart;
|
||||
use Alchemy\Phrasea\Command\Task\TaskState;
|
||||
use Alchemy\Phrasea\Command\Task\TaskStop;
|
||||
use Alchemy\Phrasea\Command\User\UserCreateCommand;
|
||||
use Alchemy\Phrasea\Command\User\UserSetPasswordCommand;
|
||||
use Alchemy\Phrasea\Command\User\UserListCommand;
|
||||
use Alchemy\Phrasea\Command\UpgradeDBDatas;
|
||||
|
||||
require_once __DIR__ . '/../lib/autoload.php';
|
||||
@@ -108,8 +113,18 @@ $cli->command(new \module_console_fieldsRename('fields:rename'));
|
||||
$cli->command(new \module_console_fieldsMerge('fields:merge'));
|
||||
|
||||
$cli->command(new CreateCollection('collection:create'));
|
||||
$cli->command(new ListCollectionCommand('collection:list'));
|
||||
|
||||
$cli->command(new ListDataboxCommand('databox:list'));
|
||||
$cli->command(new CreateDataboxCommand('databox:create'));
|
||||
|
||||
$cli->command(new UserCreateCommand('user:create'));
|
||||
|
||||
$cli->command(new UserSetPasswordCommand('user:set-password'));
|
||||
|
||||
$cli->command(new UserListCommand('user:list'));
|
||||
|
||||
|
||||
$cli->command(new RecordAdd('records:add'));
|
||||
$cli->command(new RescanTechnicalDatas('records:rescan-technical-datas'));
|
||||
$cli->command(new BuildMissingSubdefs('records:build-missing-subdefs'));
|
||||
|
31
composer.lock
generated
31
composer.lock
generated
@@ -131,16 +131,16 @@
|
||||
},
|
||||
{
|
||||
"name": "alchemy/embed-bundle",
|
||||
"version": "2.0.8",
|
||||
"version": "2.0.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/alchemy-fr/embed-bundle.git",
|
||||
"reference": "cbaa5e34b7b6ccbe128f8c804649c8a3ecd1e621"
|
||||
"reference": "8cdb9612a9e3edd998b68f0803eacca8e0f50775"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/cbaa5e34b7b6ccbe128f8c804649c8a3ecd1e621",
|
||||
"reference": "cbaa5e34b7b6ccbe128f8c804649c8a3ecd1e621",
|
||||
"url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/8cdb9612a9e3edd998b68f0803eacca8e0f50775",
|
||||
"reference": "8cdb9612a9e3edd998b68f0803eacca8e0f50775",
|
||||
"shasum": ""
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -177,7 +177,11 @@
|
||||
}
|
||||
],
|
||||
"description": "Embed resources bundle",
|
||||
"time": "2019-10-09T14:34:23+00:00"
|
||||
"support": {
|
||||
"source": "https://github.com/alchemy-fr/embed-bundle/tree/2.0.9",
|
||||
"issues": "https://github.com/alchemy-fr/embed-bundle/issues"
|
||||
},
|
||||
"time": "2020-02-04T14:53:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "alchemy/geonames-api-consumer",
|
||||
@@ -271,16 +275,16 @@
|
||||
},
|
||||
{
|
||||
"name": "alchemy/mediavorus",
|
||||
"version": "0.4.9",
|
||||
"version": "0.4.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/alchemy-fr/MediaVorus.git",
|
||||
"reference": "1a96dc4142ff8474c11285cab9eab11df9683255"
|
||||
"reference": "3e235eb1efb528aea2973c946f4bf47630b98985"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/1a96dc4142ff8474c11285cab9eab11df9683255",
|
||||
"reference": "1a96dc4142ff8474c11285cab9eab11df9683255",
|
||||
"url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/3e235eb1efb528aea2973c946f4bf47630b98985",
|
||||
"reference": "3e235eb1efb528aea2973c946f4bf47630b98985",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -296,6 +300,7 @@
|
||||
},
|
||||
"require-dev": {
|
||||
"jms/serializer": "~0.12.0",
|
||||
"phpunit/phpunit": "^4.0|^5.0",
|
||||
"silex/silex": "~1.0",
|
||||
"symfony/yaml": "~2.0"
|
||||
},
|
||||
@@ -329,7 +334,7 @@
|
||||
"keywords": [
|
||||
"metadata"
|
||||
],
|
||||
"time": "2019-01-22T11:23:34+00:00"
|
||||
"time": "2020-02-18T13:37:45+00:00"
|
||||
},
|
||||
{
|
||||
"name": "alchemy/oauth2php",
|
||||
@@ -2856,6 +2861,7 @@
|
||||
}
|
||||
],
|
||||
"description": "Provides a simple API and specification that abstracts away the details of HTTP into a single PHP function.",
|
||||
"abandoned": true,
|
||||
"time": "2015-05-20T03:37:09+00:00"
|
||||
},
|
||||
{
|
||||
@@ -2906,6 +2912,7 @@
|
||||
"Guzzle",
|
||||
"stream"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2014-10-12T19:18:40+00:00"
|
||||
},
|
||||
{
|
||||
@@ -6162,7 +6169,7 @@
|
||||
],
|
||||
"description": "A WebProfiler for Silex",
|
||||
"homepage": "http://silex.sensiolabs.org/",
|
||||
"abandoned": true,
|
||||
"abandoned": "symfony/web-profiler-bundle",
|
||||
"time": "2016-01-10T11:39:13+00:00"
|
||||
},
|
||||
{
|
||||
@@ -6412,6 +6419,7 @@
|
||||
"profiler",
|
||||
"silex"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2016-10-26T11:08:02+00:00"
|
||||
},
|
||||
{
|
||||
@@ -6454,6 +6462,7 @@
|
||||
"plugin",
|
||||
"silex"
|
||||
],
|
||||
"abandoned": true,
|
||||
"time": "2015-11-11T07:16:28+00:00"
|
||||
},
|
||||
{
|
||||
|
@@ -22,13 +22,54 @@ main:
|
||||
path: '/tmp/db.sqlite'
|
||||
charset: UTF8
|
||||
cache:
|
||||
type: MemcacheCache
|
||||
type: redis
|
||||
options:
|
||||
host: localhost
|
||||
port: 11211
|
||||
port: 6379
|
||||
search-engine:
|
||||
type: phrasea
|
||||
options: []
|
||||
type: elasticsearch
|
||||
options:
|
||||
host: elasticsearch
|
||||
port: 9200
|
||||
index: ''
|
||||
shards: 3
|
||||
replicas: 0
|
||||
minScore: 2
|
||||
highlight: true
|
||||
populate_order: RECORD_ID
|
||||
populate_direction: DESC
|
||||
activeTab: ''
|
||||
facets:
|
||||
_base:
|
||||
limit: 10
|
||||
_collection:
|
||||
limit: 10
|
||||
_doctype:
|
||||
limit: 10
|
||||
_camera_model:
|
||||
limit: 0
|
||||
_iso:
|
||||
limit: 0
|
||||
_aperture:
|
||||
limit: 0
|
||||
_shutterspeed:
|
||||
limit: 0
|
||||
_flashfired:
|
||||
limit: 0
|
||||
_framerate:
|
||||
limit: 0
|
||||
_audiosamplerate:
|
||||
limit: 0
|
||||
_videocodec:
|
||||
limit: 0
|
||||
_audiocodec:
|
||||
limit: 0
|
||||
_orientation:
|
||||
limit: 0
|
||||
_colorspace:
|
||||
limit: 0
|
||||
_mimetype:
|
||||
limit: 0
|
||||
task-manager:
|
||||
status: started
|
||||
enabled: true
|
||||
@@ -62,12 +103,7 @@ main:
|
||||
mp4box_timeout: 60
|
||||
swftools_timeout: 60
|
||||
unoconv_timeout: 60
|
||||
task-manager:
|
||||
status: started
|
||||
listener:
|
||||
protocol: tcp
|
||||
host: 127.0.0.1
|
||||
port: 6700
|
||||
exiftool_timeout: 60
|
||||
storage:
|
||||
subdefs: null
|
||||
cache: null
|
||||
@@ -75,20 +111,7 @@ main:
|
||||
download: null
|
||||
lazaret: null
|
||||
caption: null
|
||||
bridge:
|
||||
youtube:
|
||||
enabled: false
|
||||
client_id: null
|
||||
client_secret: null
|
||||
developer_key: null
|
||||
flickr:
|
||||
enabled: false
|
||||
client_id: null
|
||||
client_secret: null
|
||||
dailymotion:
|
||||
enabled: false
|
||||
client_id: null
|
||||
client_secret: null
|
||||
tmp_files: null
|
||||
border-manager:
|
||||
enabled: true
|
||||
extension-mapping:
|
||||
@@ -98,12 +121,17 @@ border-manager:
|
||||
-
|
||||
type: Checker\Sha256
|
||||
enabled: true
|
||||
collections: []
|
||||
compare-ignore-collections: []
|
||||
-
|
||||
type: Checker\UUID
|
||||
enabled: true
|
||||
collections: []
|
||||
compare-ignore-collections: []
|
||||
-
|
||||
type: Checker\Colorspace
|
||||
enabled: false
|
||||
collections: []
|
||||
options:
|
||||
colorspaces: [cmyk, grayscale, rgb]
|
||||
media_types: [Image]
|
||||
@@ -123,6 +151,8 @@ border-manager:
|
||||
enabled: false
|
||||
options:
|
||||
sensitive: true
|
||||
collections: []
|
||||
compare-ignore-collections: []
|
||||
-
|
||||
type: Checker\MediaType
|
||||
enabled: false
|
||||
@@ -244,6 +274,14 @@ embed_bundle:
|
||||
document:
|
||||
player: flexpaper
|
||||
enable_pdfjs: true
|
||||
video-editor:
|
||||
ChapterVttFieldName: VideoTextTrackChapters
|
||||
seekBackwardStep: 500 # in ms
|
||||
seekForwardStep: 500 # in ms
|
||||
playbackRates:
|
||||
- 1
|
||||
- '1.5'
|
||||
- 3
|
||||
geocoding-providers:
|
||||
-
|
||||
map-provider: mapboxWebGL
|
||||
|
@@ -27,9 +27,10 @@ fi
|
||||
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.host elasticsearch
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.minScore 2
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.base_aggregate_limit 10
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.collection_aggregate_limit 10
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.doctype_aggregate_limit 10
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.minScore 2
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.facets._base.limit 10
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.facets._collection.limit 10
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.search-engine.options.facets._doctype.limit 10
|
||||
|
||||
## Redis
|
||||
/var/alchemy/Phraseanet/bin/setup system:config set main.cache.options.host redis
|
||||
|
@@ -14,4 +14,4 @@ else
|
||||
runuser app -c '/auto-install.sh'
|
||||
fi
|
||||
|
||||
php-fpm
|
||||
php-fpm -F
|
||||
|
@@ -4,5 +4,16 @@ set -e
|
||||
|
||||
envsubst < /php.ini.sample > /usr/local/etc/php/php.ini
|
||||
envsubst < /php-fpm.conf.sample > /usr/local/etc/php-fpm.conf
|
||||
echo "XDEBUG=$XDEBUG"
|
||||
if [ $XDEBUG = "ON" ]; then
|
||||
echo "XDEBUG IS ENABLED. YOU MAY KEEP THIS FEATURE DISABLED IN PRODUCTION."
|
||||
echo "xdebug.remote_enable=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||
echo "xdebug.remote_autostart=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||
echo "xdebug.remote_host=$XDEBUG_SERVER" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||
echo "xdebug.remote_port=$XDEBUG_REMOTE_PORT" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||
echo "xdebug.remote_handler=dbgp" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||
echo "xdebug.remote_connect_back=0" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||
#echo "xdebug.idekey=11896" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
|
||||
fi
|
||||
|
||||
bash -e docker-php-entrypoint $@
|
||||
|
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2016 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
namespace Alchemy\Phrasea\Command\Collection;
|
||||
|
||||
use Alchemy\Phrasea\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ListCollectionCommand extends Command
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
parent::__construct('collection:list');
|
||||
$this->setDescription('List all collection in Phraseanet')
|
||||
->addOption('databox_id', 'd', InputOption::VALUE_REQUIRED, 'The id of the databox to list collection')
|
||||
->addOption('jsonformat', null, InputOption::VALUE_NONE, 'Output in json format')
|
||||
->setHelp('');
|
||||
return $this;
|
||||
}
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
try {
|
||||
$jsonformat = $input->getOption('jsonformat');
|
||||
$databox = $this->container->findDataboxById($input->getOption('databox_id'));
|
||||
$collections = $this->listDataboxCollections($databox);
|
||||
|
||||
if ($jsonformat) {
|
||||
foreach ($collections as $collection) {
|
||||
$collectionList[] = array_combine(['id local for API', 'id distant', 'name','label','status','total records'], $collection);
|
||||
}
|
||||
echo json_encode($collectionList);
|
||||
} else {
|
||||
$table = $this->getHelperSet()->get('table');
|
||||
$table
|
||||
->setHeaders(['id local for API', 'id distant', 'name','label','status','total records'])
|
||||
->setRows($collections)
|
||||
->render($output);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln("<error>{$e->getMessage()}</error>");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function listDataboxCollections(\databox $databox)
|
||||
{
|
||||
return array_map(function (\collection $collection) {
|
||||
return $this->listCollection($collection);
|
||||
}, array_merge($databox->get_collections(),$this->getUnabledCollection($databox->get_activable_colls())));
|
||||
}
|
||||
|
||||
private function getUnabledCollection($collections)
|
||||
{
|
||||
return array_map(function ($colId){
|
||||
return \collection::getByBaseId($this->container, $colId);
|
||||
},$collections);
|
||||
|
||||
}
|
||||
|
||||
private function listCollection(\collection $collection)
|
||||
{
|
||||
return [
|
||||
$collection->get_base_id(),
|
||||
$collection->get_coll_id(),
|
||||
$collection->get_name(),
|
||||
'en: ' . $collection->get_label('en') .
|
||||
', de: ' . $collection->get_label('de') .
|
||||
', fr: ' . $collection->get_label('fr') .
|
||||
', nl: ' . $collection->get_label('nl'),
|
||||
($collection->is_active()) ? 'enabled' : 'disabled',
|
||||
$collection->get_record_amount()
|
||||
];
|
||||
}
|
||||
}
|
72
lib/Alchemy/Phrasea/Command/Databox/ListDataboxCommand.php
Normal file
72
lib/Alchemy/Phrasea/Command/Databox/ListDataboxCommand.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2016 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Command\Databox;
|
||||
|
||||
use Alchemy\Phrasea\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ListDataboxCommand extends Command
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
parent::__construct('databox:list');
|
||||
|
||||
$this->setDescription('List all databox in Phraseanet')
|
||||
->addOption('jsonformat', null, InputOption::VALUE_NONE, 'Output in json format')
|
||||
->setHelp('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
try {
|
||||
$jsonformat = $input->getOption('jsonformat');
|
||||
$databoxes = array_map(function (\databox $databox) {
|
||||
return $this->listDatabox($databox);
|
||||
}, $this->container->getApplicationBox()->get_databoxes());
|
||||
|
||||
if ($jsonformat) {
|
||||
foreach ($databoxes as $databox) {
|
||||
$databoxList[] = array_combine(['id', 'name', 'alias'], $databox);
|
||||
}
|
||||
echo json_encode($databoxList);
|
||||
} else {
|
||||
$table = $this->getHelperSet()->get('table');
|
||||
$table
|
||||
->setHeaders(['id', 'name', 'alias'])
|
||||
->setRows($databoxes)
|
||||
->render($output);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$output->writeln('<error>Listing databox failed : '.$e->getMessage().'</error>');
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function listDatabox(\databox $databox)
|
||||
{
|
||||
return [
|
||||
$databox->get_sbas_id(),
|
||||
$databox->get_dbname(),
|
||||
$databox->get_viewname()
|
||||
];
|
||||
}
|
||||
|
||||
}
|
@@ -15,6 +15,7 @@ use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Command\Command;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Plugin\Plugin;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\HttpKernel\Client;
|
||||
@@ -30,6 +31,15 @@ class JsFixtures extends Command
|
||||
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
/** @var Plugin $plugin */
|
||||
$msg = [];
|
||||
foreach($this->container['plugins.manager']->listPlugins() as $plugin) {
|
||||
$msg[] = sprintf(" bin/setup plugins:remove \"%s\"", $plugin->getName());
|
||||
}
|
||||
if(count($msg) !== 0) {
|
||||
throw new RuntimeException("You must remove plugins first:\n" . join("\n", $msg));
|
||||
}
|
||||
|
||||
if (!file_exists($this->container['db.fixture.info']['path'])) {
|
||||
throw new RuntimeException('You must generate sqlite db first, run "bin/developer phraseanet:regenerate-sqlite" command.');
|
||||
}
|
||||
@@ -104,6 +114,7 @@ class JsFixtures extends Command
|
||||
private function writeResponse(OutputInterface $output, $method, $path, $to, $authenticateUser = false)
|
||||
{
|
||||
$environment = Application::ENV_TEST;
|
||||
/** @var Application $app */
|
||||
$app = require __DIR__ . '/../../Application/Root.php';
|
||||
$app['orm.em'] = $app->extend('orm.em', function($em, $app) {
|
||||
return $app['orm.ems'][$app['db.fixture.hash.key']];
|
||||
|
211
lib/Alchemy/Phrasea/Command/User/UserCreateCommand.php
Normal file
211
lib/Alchemy/Phrasea/Command/User/UserCreateCommand.php
Normal file
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2016 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Command\User;
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\NotifierAware;
|
||||
use Alchemy\Phrasea\Command\Command;
|
||||
use Alchemy\Phrasea\Core\LazyLocator;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailRequestPasswordSetup;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailRequestEmailConfirmation;
|
||||
use Alchemy\Phrasea\Notification\Receiver;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
|
||||
class UserCreateCommand extends Command
|
||||
{
|
||||
use NotifierAware;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
parent::__construct('user:create');
|
||||
|
||||
$this->setDescription('Create user in Phraseanet')
|
||||
->addOption('user_login', null, InputOption::VALUE_REQUIRED, 'The desired login for created user.')
|
||||
->addOption('user_mail', null, InputOption::VALUE_OPTIONAL, 'The desired mail for created user.')
|
||||
->addOption('user_password', null, InputOption::VALUE_OPTIONAL, 'The desired password')
|
||||
->addOption('send_mail_confirm', null, InputOption::VALUE_NONE, 'Send an email to user, for validate email.')
|
||||
->addOption('send_mail_password', null, InputOption::VALUE_NONE, 'Send an email to user, for password definition, work only if user_password is not define')
|
||||
->addOption('model_number', null, InputOption::VALUE_OPTIONAL, 'Id of model')
|
||||
->addOption('user_gender', null, InputOption::VALUE_OPTIONAL, 'The gender for created user.')
|
||||
->addOption('user_firstname', null, InputOption::VALUE_OPTIONAL, 'The first name for created user.')
|
||||
->addOption('user_lastname', null, InputOption::VALUE_OPTIONAL, 'The last name for created user.')
|
||||
->addOption('user_compagny', null, InputOption::VALUE_OPTIONAL, 'The compagny for created user.')
|
||||
->addOption('user_job', null, InputOption::VALUE_OPTIONAL, 'The job for created user.')
|
||||
->addOption('user_activitie', null, InputOption::VALUE_OPTIONAL, 'The activitie for created user.')
|
||||
->addOption('user_phone', null, InputOption::VALUE_OPTIONAL, 'The phone number for created user.')
|
||||
->setHelp('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
||||
$userLogin = $input->getOption('user_login');
|
||||
$userMail = $input->getOption('user_mail');
|
||||
$userPassword = $input->getOption('user_password');
|
||||
$sendMailConfirm = $input->getOption('send_mail_confirm');
|
||||
$sendMailPassword = $input->getOption('send_mail_password');
|
||||
$modelNumber = $input->getOption('model_number');
|
||||
$userGender = $input->getOption('user_gender');
|
||||
$userFirstName = $input->getOption('user_firstname');
|
||||
$userLastName = $input->getOption('user_lastname');
|
||||
$userCompagny = $input->getOption('user_compagny');
|
||||
$userJob = $input->getOption('user_job');
|
||||
$userActivity = $input->getOption('user_activitie');
|
||||
$userPhone = $input->getOption('user_phone');
|
||||
|
||||
$userRepository = $this->container['repo.users'];
|
||||
|
||||
if ($userMail) {
|
||||
if (!\Swift_Validate::email($userMail)) {
|
||||
$output->writeln('<error>Invalid mail address</error>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (null !== $userRepository->findByEmail($userMail)) {
|
||||
$output->writeln('<error>An user exist with this email.</error>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$password = (!is_null($userPassword)) ? $userPassword : $this->container['random.medium']->generateString(128);
|
||||
$userManipulator = $this->container['manipulator.user'];
|
||||
$user = $userManipulator->createUser($userLogin, $password, $userMail);
|
||||
|
||||
if ($userGender) {
|
||||
if (null === $gender = $this->verifyGender($userGender)) {
|
||||
$output->writeln('<bg=yellow;options=bold>Gender '.$userGender.' not exists.</>');
|
||||
}
|
||||
$user->setGender($gender);
|
||||
}
|
||||
|
||||
if($userFirstName) $user->setFirstName($userFirstName);
|
||||
if($userLastName) $user->setLastName($userLastName);
|
||||
if($userCompagny) $user->setCompany($userCompagny);
|
||||
if($userJob) $user->setJob($userJob);
|
||||
if($userActivity) $user->setActivity($userActivity);
|
||||
if($userPhone) $user->setPhone($userPhone);
|
||||
|
||||
if ($sendMailPassword and $userMail and is_null($userPassword)) {
|
||||
$this->sendPasswordSetupMail($user);
|
||||
}
|
||||
|
||||
if ($sendMailConfirm and $userMail) {
|
||||
$user->setMailLocked(true);
|
||||
$this->sendAccountUnlockEmail($user);
|
||||
}
|
||||
|
||||
if ($modelNumber) {
|
||||
$template = $userRepository->find($modelNumber);
|
||||
if (!$template) {
|
||||
$output->writeln('<bg=yellow;options=bold>Model '.$modelNumber.' not found.</>');
|
||||
} else {
|
||||
$base_ids = [];
|
||||
foreach ($this->container->getApplicationBox()->get_databoxes() as $databox) {
|
||||
foreach ($databox->get_collections() as $collection) {
|
||||
$base_ids[] = $collection->get_base_id();
|
||||
}
|
||||
}
|
||||
$this->container->getAclForUser($user)->apply_model($template, $base_ids);
|
||||
}
|
||||
}
|
||||
|
||||
$this->container['orm.em']->flush();
|
||||
|
||||
$output->writeln("<info>Create new user successful !</info>");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get gender for user
|
||||
* @param $type
|
||||
* @return int|null
|
||||
*/
|
||||
private function verifyGender($type)
|
||||
{
|
||||
switch (strtolower($type)) {
|
||||
case "mlle.":
|
||||
case "mlle":
|
||||
case "miss":
|
||||
case "mademoiselle":
|
||||
case "0":
|
||||
$gender = User::GENDER_MISS;
|
||||
break;
|
||||
case "mme":
|
||||
case "madame":
|
||||
case "ms":
|
||||
case "ms.":
|
||||
case "1":
|
||||
$gender = User::GENDER_MRS;
|
||||
break;
|
||||
case "m":
|
||||
case "m.":
|
||||
case "mr":
|
||||
case "mr.":
|
||||
case "monsieur":
|
||||
case "mister":
|
||||
case "2":
|
||||
$gender = User::GENDER_MR;
|
||||
break;
|
||||
default:
|
||||
$gender = null;
|
||||
}
|
||||
return $gender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send mail for renew password
|
||||
* @param User $user
|
||||
*/
|
||||
public function sendPasswordSetupMail(User $user)
|
||||
{
|
||||
$this->setDelivererLocator(new LazyLocator($this->container, 'notification.deliverer'));
|
||||
$receiver = Receiver::fromUser($user);
|
||||
|
||||
$token = $this->container['manipulator.token']->createResetPasswordToken($user);
|
||||
|
||||
$mail = MailRequestPasswordSetup::create($this->container, $receiver);
|
||||
$servername = $this->container['conf']->get('servername');
|
||||
$mail->setButtonUrl('http://'.$servername.'/login/renew-password/?token='.$token->getValue());
|
||||
$mail->setLogin($user->getLogin());
|
||||
|
||||
$this->deliver($mail);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
*/
|
||||
public function sendAccountUnlockEmail(User $user)
|
||||
{
|
||||
$this->setDelivererLocator(new LazyLocator($this->container, 'notification.deliverer'));
|
||||
$receiver = Receiver::fromUser($user);
|
||||
|
||||
$token = $this->container['manipulator.token']->createAccountUnlockToken($user);
|
||||
|
||||
$mail = MailRequestEmailConfirmation::create($this->container, $receiver);
|
||||
$servername = $this->container['conf']->get('servername');
|
||||
$mail->setButtonUrl('http://'.$servername.'/login/register-confirm/?code='.$token->getValue());
|
||||
$mail->setExpiration($token->getExpiration());
|
||||
|
||||
$this->deliver($mail);
|
||||
}
|
||||
|
||||
}
|
287
lib/Alchemy/Phrasea/Command/User/UserListCommand.php
Normal file
287
lib/Alchemy/Phrasea/Command/User/UserListCommand.php
Normal file
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2016 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Command\User;
|
||||
|
||||
use Alchemy\Phrasea\Command\Command;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Symfony\Component\Console\Helper\TableCell;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Alchemy\Phrasea\Utilities\NullableDateTime;
|
||||
|
||||
|
||||
class UserListCommand extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
parent::__construct('user:list');
|
||||
|
||||
$this->setDescription('List of all user (experimental)')
|
||||
->addOption('user_id', null, InputOption::VALUE_OPTIONAL, ' The id of user export only info this user ')
|
||||
->addOption('user_email', null, InputOption::VALUE_OPTIONAL, 'The mail of user export only info this user .')
|
||||
->addOption('database_id', null, InputOption::VALUE_OPTIONAL, 'Id of database.')
|
||||
->addOption('collection_id', null, InputOption::VALUE_OPTIONAL, 'Id of the collection.')
|
||||
->addOption('mail_lock_status', null, InputOption::VALUE_NONE, 'Status by mail locked')
|
||||
->addOption('guest', null, InputOption::VALUE_NONE, 'Only guest user')
|
||||
->addOption('created', null, InputOption::VALUE_OPTIONAL, 'Created at with operator,aaaa-mm-jj hh:mm:ss.')
|
||||
->addOption('updated', null, InputOption::VALUE_OPTIONAL, 'Update at with operator,aaaa-mm-jj hh:mm:ss.')
|
||||
->addOption('application', null, InputOption::VALUE_NONE, 'List application of user work only if --user_id is set')
|
||||
->addOption('right', null, InputOption::VALUE_NONE, 'Show right information')
|
||||
->addOption('adress', null, InputOption::VALUE_NONE, 'Show adress information')
|
||||
->addOption('models', null, InputOption::VALUE_NONE, "Show only defined models, if --user_id is set with --models it's the template owner")
|
||||
->addOption('jsonformat', null, InputOption::VALUE_NONE, 'Output in json format')
|
||||
->setHelp('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
||||
$userId = $input->getOption('user_id');
|
||||
$userEmail = $input->getOption('user_email');
|
||||
$databaseId = $input->getOption('database_id');
|
||||
$collectionId = $input->getOption('collection_id');
|
||||
$lockStatus = $input->getOption('mail_lock_status');
|
||||
$guest = $input->getOption('guest');
|
||||
$application = $input->getOption('application');
|
||||
$withAdress = $input->getOption('adress');
|
||||
$created = $input->getOption('created');
|
||||
$updated = $input->getOption('updated');
|
||||
$withRight = $input->getOption('right');
|
||||
$models = $input->getOption('models');
|
||||
$jsonformat = $input->getOption('jsonformat');
|
||||
|
||||
$query = $this->container['phraseanet.user-query'];
|
||||
|
||||
if($databaseId) $query->on_base_ids([$databaseId]);
|
||||
if($collectionId) $query->on_sbas_ids([$collectionId]);
|
||||
if($created) $this->addFilterDate($created,'created',$query);
|
||||
if($updated) $this->addFilterDate($updated,'updated',$query);
|
||||
if($userId && !$models) $query->addSqlFilter('Users.id = ?' ,[$userId]);
|
||||
if($userEmail && !$models) $query->addSqlFilter('Users.email = ?' ,[$userEmail]);
|
||||
if($lockStatus && !$models) $query->addSqlFilter('Users.mail_locked = 1');
|
||||
if($guest && !$models) $query->include_invite(true)->addSqlFilter('Users.guest = 1');
|
||||
|
||||
if ($application and !$userId) {
|
||||
$output->writeln('<error>You must provide --user_id when using --application option</error>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @var UserRepository $userRepository */
|
||||
$userRepository = $this->container['repo.users'];
|
||||
|
||||
if ($models && $userId) {
|
||||
$users = $userRepository->findBy(['templateOwner' => $userId]);
|
||||
} elseif ($models) {
|
||||
$users = $userRepository->findTemplate();
|
||||
} else {
|
||||
$users = $query->execute()->get_results();
|
||||
}
|
||||
|
||||
$userList = [];
|
||||
$showApplication = false;
|
||||
foreach ($users as $key => $user) {
|
||||
if ($userId and $application) {
|
||||
$showApplication = true;
|
||||
}
|
||||
$userList[] = $this->listUser($user, $withAdress, $withRight);
|
||||
|
||||
$userListRaw[] = array_combine($this->headerTable($withAdress, $withRight), $this->listUser($user, $withAdress, $withRight));
|
||||
}
|
||||
|
||||
if ($jsonformat) {
|
||||
echo json_encode($userListRaw);
|
||||
} else {
|
||||
$table = $this->getHelperSet()->get('table');
|
||||
$table
|
||||
->setHeaders($this->headerTable($withAdress, $withRight))
|
||||
->setRows($userList)
|
||||
->render($output);
|
||||
;
|
||||
|
||||
|
||||
if ($showApplication) {
|
||||
$applicationTable = $this->getHelperSet()->get('table');
|
||||
$applicationTable->setHeaders(array(
|
||||
array(new TableCell('Applications', array('colspan' => 5))),
|
||||
['name','callback','client_secret','client_id','token'],
|
||||
))->setRows($this->getApplicationOfUser($users[0]))->render($output);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $withAdress
|
||||
* @param $withRight
|
||||
* @return array
|
||||
*/
|
||||
private function headerTable($withAdress,$withRight)
|
||||
{
|
||||
$defaultHeader = ['id', 'login', 'email','last_model','first_name','last_name','gender','created','updated','status','locale'];
|
||||
$adressHeader = [ 'address', 'zip_code', 'city', 'country', 'phone', 'fax', 'job','position', 'company', 'geoname_id'];
|
||||
$rightHeader = [ 'admin', 'guest', 'mail_notification', 'ldap_created', 'mail_locked'];
|
||||
|
||||
return $this->createInformation($withAdress,$withRight,$defaultHeader,['adress' => $adressHeader,'right' =>$rightHeader]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param $withAdress
|
||||
* @param $withRight
|
||||
* @return array
|
||||
*/
|
||||
private function listUser(User $user,$withAdress,$withRight)
|
||||
{
|
||||
switch ($user->getGender()) {
|
||||
case User::GENDER_MRS:
|
||||
$gender = 'Mrs';
|
||||
break;
|
||||
case User::GENDER_MISS:
|
||||
$gender = 'Miss';
|
||||
break;
|
||||
case User::GENDER_MR:
|
||||
default:
|
||||
$gender = 'Mr';
|
||||
}
|
||||
|
||||
$defaultInfo = [
|
||||
$user->getId(),
|
||||
$user->getLogin() ?: '-',
|
||||
$user->getEmail() ?: '-',
|
||||
$user->getLastAppliedTemplate() ? $user->getLastAppliedTemplate()->getLogin() : '-',
|
||||
$user->getFirstName() ?: '-',
|
||||
$user->getLastName() ?: '-',
|
||||
$gender,
|
||||
NullableDateTime::format($user->getCreated(),'Y-m-d H:i:s'),
|
||||
NullableDateTime::format($user->getUpdated(),'Y-m-d H:i:s'),
|
||||
'status',
|
||||
$user->getLocale() ?: '-',
|
||||
];
|
||||
|
||||
return $this->createInformation($withAdress,$withRight,$defaultInfo,['adress' => $this->userAdress($user),'right' => $this->userRight($user)]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return array
|
||||
*/
|
||||
private function userAdress(User $user)
|
||||
{
|
||||
return [
|
||||
$user->getAddress() ?: '-',
|
||||
$user->getZipCode() ?: '-',
|
||||
$user->getCity() ?: '-',
|
||||
$user->getCountry() ?: '-',
|
||||
$user->getPhone() ?: '-',
|
||||
$user->getFax() ?: '-',
|
||||
$user->getJob() ?: '-',
|
||||
$user->getActivity() ?: '-',
|
||||
$user->getCompany() ?: '-',
|
||||
$user->getGeonameId() ?: '-',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return array
|
||||
*/
|
||||
private function userRight(User $user)
|
||||
{
|
||||
return [
|
||||
$user->isAdmin() ?: false,
|
||||
$user->isGuest() ?: false,
|
||||
$user->hasMailNotificationsActivated() ?: false,
|
||||
$user->hasLdapCreated() ?: false,
|
||||
$user->isMailLocked() ?: false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @return array
|
||||
*/
|
||||
private function getApplicationOfUser(User $user)
|
||||
{
|
||||
$apiRepository = $this->container['repo.api-applications'];
|
||||
$applications = $apiRepository->findByUser($user);
|
||||
|
||||
if (empty($applications)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$accountRepository = $this->container['repo.api-accounts'];
|
||||
$apiOauthRepository = $this->container['repo.api-oauth-tokens'];
|
||||
$usersApplication = [];
|
||||
foreach ($applications as $application) {
|
||||
$account = $accountRepository->findByUserAndApplication($user, $application);
|
||||
$token = $account ? $apiOauthRepository->findDeveloperToken($account) : null;
|
||||
$usersApplication[] = [
|
||||
$application->getName(),
|
||||
$application->getRedirectUri(),
|
||||
$application->getClientSecret(),
|
||||
$application->getClientId(),
|
||||
($token) ? $token->getOauthToken() : '-'
|
||||
];
|
||||
}
|
||||
|
||||
return $usersApplication;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $withAdress
|
||||
* @param $withRight
|
||||
* @param $default
|
||||
* @param $infoToMerge
|
||||
* @return array
|
||||
*/
|
||||
private function createInformation($withAdress,$withRight,$default,$infoToMerge)
|
||||
{
|
||||
if ($withAdress && $withRight) {
|
||||
$information = array_merge($default, $infoToMerge['adress'],$infoToMerge['right']);
|
||||
} elseif ($withAdress && !$withRight) {
|
||||
$information = array_merge($default, $infoToMerge['adress']);
|
||||
} elseif(!$withAdress && $withRight) {
|
||||
$information = array_merge($default, $infoToMerge['right']);
|
||||
} else {
|
||||
$information = $default;
|
||||
}
|
||||
|
||||
return $information;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $date
|
||||
* @param $type
|
||||
* @param $query
|
||||
*/
|
||||
private function addFilterDate($date,$type,$query){
|
||||
|
||||
list($operator,$dateAt) = explode(',', $date);
|
||||
|
||||
if (!in_array($operator,['=','>=','<=','>','<'])) {
|
||||
throw new \InvalidArgumentException(" '=' or '<=' or '>=' or '>' or '<'");
|
||||
}
|
||||
|
||||
$query->addSqlFilter($type.$operator.' ?' ,[$dateAt]);
|
||||
}
|
||||
|
||||
}
|
79
lib/Alchemy/Phrasea/Command/User/UserSetPasswordCommand.php
Normal file
79
lib/Alchemy/Phrasea/Command/User/UserSetPasswordCommand.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2016 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Command\User;
|
||||
|
||||
use Alchemy\Phrasea\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
|
||||
class UserSetPasswordCommand extends Command
|
||||
{
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($name = null)
|
||||
{
|
||||
parent::__construct('user:set-password');
|
||||
|
||||
$this->setDescription('Set user password in Phraseanet')
|
||||
->addOption('user_id', null, InputOption::VALUE_REQUIRED, 'The id of user.')
|
||||
->addOption('generate', null, InputOption::VALUE_NONE, 'Generate the password')
|
||||
->addOption('password', null, InputOption::VALUE_OPTIONAL, 'The password')
|
||||
->setHelp('');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function doExecute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
||||
$dialog = $this->getHelperSet()->get('dialog');
|
||||
$userRepository = $this->container['repo.users'];
|
||||
$userManipulator = $this->container['manipulator.user'];
|
||||
$user = $userRepository->find($input->getOption('user_id'));
|
||||
$password = $input->getOption('password');
|
||||
$generate = $input->getOption('generate');
|
||||
|
||||
if ($user === null) {
|
||||
$output->writeln('<info>Not found User.</info>');
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ($generate) {
|
||||
$password = $this->container['random.medium']->generateString(64);
|
||||
} else {
|
||||
if (!$password) {
|
||||
$output->writeln('<error>--password option not specified</error>');
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
$continue = mb_strtolower($dialog->ask($output, '<question>Do you want really set password to this user? (y/N)</question>', 'N'));
|
||||
} while (!in_array($continue, ['y', 'n']));
|
||||
|
||||
if ($continue !== 'y') {
|
||||
$output->writeln('Aborting !');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$userManipulator->setPassword($user,$password);
|
||||
$output->writeln('New password: <info>' . $password . '</info>');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
@@ -13,9 +13,11 @@ namespace Alchemy\Phrasea\Controller\Admin;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchSettingsFormType;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\GlobalStructure;
|
||||
use Symfony\Component\Form\FormInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use databox_descriptionStructure;
|
||||
|
||||
class SearchEngineController extends Controller
|
||||
{
|
||||
@@ -31,7 +33,19 @@ class SearchEngineController extends Controller
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isValid()) {
|
||||
$this->saveElasticSearchOptions($form->getData());
|
||||
/** @var ElasticsearchOptions $data */
|
||||
$data = $form->getData();
|
||||
// $q = $request->request->get('elasticsearch_settings');
|
||||
$facetNames = []; // rebuild the data "_customValues/facets" list following the form order
|
||||
foreach($request->request->get('elasticsearch_settings') as $name=>$value) {
|
||||
$matches = null;
|
||||
if(preg_match('/^facets:(.+):limit$/', $name, $matches) === 1) {
|
||||
$facetNames[] = $matches[1];
|
||||
}
|
||||
}
|
||||
$data->reorderAggregableFields($facetNames);
|
||||
|
||||
$this->saveElasticSearchOptions($data);
|
||||
|
||||
return $this->app->redirectPath('admin_searchengine_form');
|
||||
}
|
||||
@@ -76,6 +90,16 @@ class SearchEngineController extends Controller
|
||||
*/
|
||||
private function saveElasticSearchOptions(ElasticsearchOptions $configuration)
|
||||
{
|
||||
// save to databoxes fields for backward compatibility (useless ?)
|
||||
foreach($configuration->getAggregableFields() as $fname=>$aggregableField) {
|
||||
foreach ($this->app->getDataboxes() as $databox) {
|
||||
if(!is_null($f = $databox->get_meta_structure()->get_element_by_name($fname, databox_descriptionStructure::STRICT_COMPARE))) {
|
||||
$f->set_aggregable($aggregableField['limit'])->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save to conf
|
||||
$this->getConf()->set(['main', 'search-engine', 'options'], $configuration->toArray());
|
||||
}
|
||||
|
||||
@@ -85,7 +109,10 @@ class SearchEngineController extends Controller
|
||||
*/
|
||||
private function getConfigurationForm(ElasticsearchOptions $options)
|
||||
{
|
||||
return $this->app->form(new ElasticsearchSettingsFormType(), $options, [
|
||||
/** @var GlobalStructure $g */
|
||||
$g = $this->app['search_engine.structure'];
|
||||
|
||||
return $this->app->form(new ElasticsearchSettingsFormType($g, $options), $options, [
|
||||
'action' => $this->app->url('admin_searchengine_form'),
|
||||
]);
|
||||
}
|
||||
|
@@ -19,8 +19,10 @@ use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
use Alchemy\Phrasea\Feed\Aggregate;
|
||||
use Alchemy\Phrasea\Feed\Link\AggregateLinkGenerator;
|
||||
use Alchemy\Phrasea\Feed\Link\FeedLinkGenerator;
|
||||
use Alchemy\Phrasea\Model\Entities\Feed;
|
||||
use Alchemy\Phrasea\Model\Entities\FeedEntry;
|
||||
use Alchemy\Phrasea\Model\Entities\FeedItem;
|
||||
use Alchemy\Phrasea\Model\Entities\FeedPublisher;
|
||||
use Alchemy\Phrasea\Model\Repositories\FeedEntryRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\FeedItemRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\FeedPublisherRepository;
|
||||
@@ -46,6 +48,7 @@ class FeedController extends Controller
|
||||
}
|
||||
|
||||
public function createFeedEntryAction(Request $request) {
|
||||
/** @var Feed $feed */
|
||||
$feed = $this->getFeedRepository()->find($request->request->get('feed_id'));
|
||||
|
||||
if (null === $feed) {
|
||||
@@ -53,6 +56,8 @@ class FeedController extends Controller
|
||||
}
|
||||
|
||||
$user = $this->getAuthenticatedUser();
|
||||
|
||||
/** @var FeedPublisher $publisher */
|
||||
$publisher = $this->getFeedPublisherRepository()->findOneBy([
|
||||
'feed' => $feed,
|
||||
'user' => $user,
|
||||
|
@@ -433,24 +433,15 @@ class QueryController extends Controller
|
||||
|
||||
// populates facets (aggregates)
|
||||
$facets = [];
|
||||
// $facetClauses = [];
|
||||
foreach ($result->getFacets() as $facet) {
|
||||
$facetName = $facet['name'];
|
||||
|
||||
if(array_key_exists($facetName, $fieldsInfosByName)) {
|
||||
|
||||
$f = $fieldsInfosByName[$facetName];
|
||||
|
||||
$facet['label'] = $f['trans_label'];
|
||||
$facet['labels'] = $f['labels'];
|
||||
$facet['type'] = strtoupper($f['type']) . "-AGGREGATE";
|
||||
$facets[] = $facet;
|
||||
|
||||
// $facetClauses[] = [
|
||||
// 'type' => strtoupper($f['type']) . "-AGGREGATE",
|
||||
// 'field' => $f['field'],
|
||||
// 'facet' => $facet
|
||||
// ];
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -458,9 +458,9 @@ class AccountController extends Controller
|
||||
->setZipCode($request->request->get("form_zip"))
|
||||
->setPhone($request->request->get("form_phone"))
|
||||
->setFax($request->request->get("form_fax"))
|
||||
->setJob($request->request->get("form_activity"))
|
||||
->setJob($request->request->get("form_function"))
|
||||
->setCompany($request->request->get("form_company"))
|
||||
->setPosition($request->request->get("form_function"))
|
||||
->setPosition($request->request->get("form_activity"))
|
||||
->setNotifications((Boolean) $request->request->get("mail_notifications"));
|
||||
|
||||
$service->updateAccount($command);
|
||||
|
@@ -20,6 +20,7 @@ class DisplaySettingService
|
||||
const ORDER_BY_ADMIN = "ORDER_BY_ADMIN";
|
||||
const ORDER_BY_BCT = "ORDER_BY_BCT";
|
||||
const ORDER_BY_HITS = "ORDER_BY_HITS";
|
||||
const ORDER_BY_HITS_ASC = "ORDER_BY_HITS_ASC";
|
||||
|
||||
/**
|
||||
* The default user settings.
|
||||
@@ -31,7 +32,7 @@ class DisplaySettingService
|
||||
'images_per_page' => '20',
|
||||
'images_size' => '120',
|
||||
'editing_images_size' => '134',
|
||||
'editing_top_box' => '180px',
|
||||
'editing_top_box' => '120px',
|
||||
'editing_right_box' => '400px',
|
||||
'editing_left_box' => '710px',
|
||||
'basket_sort_field' => 'name',
|
||||
|
@@ -13,7 +13,9 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber;
|
||||
|
||||
use Alchemy\Phrasea\Core\Event\FeedEntryEvent;
|
||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\Entities\WebhookEvent;
|
||||
use Alchemy\Phrasea\Model\Manipulator\TokenManipulator;
|
||||
use Alchemy\Phrasea\Notification\Receiver;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoNewPublication;
|
||||
|
||||
@@ -53,36 +55,43 @@ class FeedEntrySubscriber extends AbstractNotificationSubscriber
|
||||
do {
|
||||
$results = $Query->limit($start, $perLoop)->execute()->get_results();
|
||||
|
||||
foreach ($results as $user_to_notif) {
|
||||
$mailed = false;
|
||||
|
||||
if ($params['notify_email'] && $this->shouldSendNotificationFor($user_to_notif, 'eventsmanager_notify_feed')) {
|
||||
$readyToSend = false;
|
||||
try {
|
||||
$token = $this->app['manipulator.token']->createFeedEntryToken($user_to_notif, $entry);
|
||||
$url = $this->app->url('lightbox', ['LOG' => $token->getValue()]);
|
||||
|
||||
$receiver = Receiver::fromUser($user_to_notif);
|
||||
$readyToSend = true;
|
||||
} catch (\Exception $e) {
|
||||
$users_emailed = []; // for all users
|
||||
$users_to_email = []; // list only users who must be emailed (=create tokens)
|
||||
|
||||
/** @var User $user */
|
||||
foreach ($results as $user) {
|
||||
$users_emailed[$user->getId()] = false;
|
||||
if ($params['notify_email'] && $this->shouldSendNotificationFor($user, 'eventsmanager_notify_feed')) {
|
||||
$users_to_email[$user->getId()] = $user;
|
||||
}
|
||||
}
|
||||
|
||||
if ($readyToSend) {
|
||||
// get many tokens in one shot
|
||||
$tokens = $this->getTokenManipulator()->createFeedEntryTokens($users_to_email, $entry);
|
||||
foreach($tokens as $token) {
|
||||
try {
|
||||
$url = $this->app->url('lightbox', ['LOG' => $token->getValue()]);
|
||||
$receiver = Receiver::fromUser($token->getUser());
|
||||
|
||||
$mail = MailInfoNewPublication::create($this->app, $receiver);
|
||||
$mail->setButtonUrl($url);
|
||||
$mail->setAuthor($entry->getAuthorName());
|
||||
$mail->setTitle($entry->getTitle());
|
||||
|
||||
$this->deliver($mail);
|
||||
$mailed = true;
|
||||
$users_emailed[$token->getUser()->getId()] = true;
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
foreach($users_emailed as $id => $emailed) {
|
||||
$this->app['events-manager']->notify($id, 'eventsmanager_notify_feed', $datas, $emailed);
|
||||
}
|
||||
|
||||
$this->app['events-manager']->notify($user_to_notif->getId(), 'eventsmanager_notify_feed', $datas, $mailed);
|
||||
}
|
||||
$start += $perLoop;
|
||||
} while (count($results) > 0);
|
||||
}
|
||||
while (count($results) > 0);
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
@@ -91,4 +100,12 @@ class FeedEntrySubscriber extends AbstractNotificationSubscriber
|
||||
PhraseaEvents::FEED_ENTRY_CREATE => 'onCreate',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TokenManipulator
|
||||
*/
|
||||
private function getTokenManipulator()
|
||||
{
|
||||
return $this->app['manipulator.token'];
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@ use MediaVorus\MediaVorusServiceProvider;
|
||||
use MP4Box\MP4BoxServiceProvider;
|
||||
use Neutron\Silex\Provider\ImagineServiceProvider;
|
||||
use PHPExiftool\PHPExiftoolServiceProvider;
|
||||
use PHPExiftool\Reader;
|
||||
use PHPExiftool\Writer;
|
||||
use Silex\Application;
|
||||
use Silex\ServiceProviderInterface;
|
||||
|
||||
@@ -48,6 +50,21 @@ class MediaUtilitiesMetaServiceProvider implements ServiceProviderInterface
|
||||
|
||||
public function boot(Application $app)
|
||||
{
|
||||
// no-op
|
||||
if(isset($app['exiftool.reader']) && isset($app['conf'])) {
|
||||
try {
|
||||
$timeout = $app['conf']->get(['main', 'binaries', 'exiftool_timeout'], 60);
|
||||
|
||||
/** @var Reader $exiftoolReader */
|
||||
$exiftoolReader = $app['exiftool.reader'];
|
||||
$exiftoolReader->setTimeout($timeout);
|
||||
|
||||
/** @var Writer $exiftoolWriter */
|
||||
$exiftoolWriter = $app['exiftool.writer'];
|
||||
$exiftoolWriter->setTimeout($timeout);
|
||||
}
|
||||
catch(\Exception $e) {
|
||||
// no-nop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -97,7 +97,7 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
|
||||
});
|
||||
|
||||
$app['elasticsearch.facets_response.factory'] = $app->protect(function (array $response) use ($app) {
|
||||
return new FacetsResponse(new Escaper(), $response, $app['search_engine.structure']);
|
||||
return new FacetsResponse($app['elasticsearch.options'], new Escaper(), $response, $app['search_engine.structure']);
|
||||
});
|
||||
|
||||
return $app;
|
||||
@@ -228,7 +228,8 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
|
||||
});
|
||||
|
||||
$app['elasticsearch.options'] = $app->share(function ($app) {
|
||||
$options = ElasticsearchOptions::fromArray($app['conf']->get(['main', 'search-engine', 'options'], []));
|
||||
$conf = $app['conf']->get(['main', 'search-engine', 'options'], []);
|
||||
$options = ElasticsearchOptions::fromArray($conf);
|
||||
|
||||
if (empty($options->getIndexName())) {
|
||||
$options->setIndexName(strtolower(sprintf('phraseanet_%s', str_replace(
|
||||
|
@@ -16,7 +16,8 @@ class Version
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $number = '4.1.0-alpha.19a';
|
||||
|
||||
private $number = '4.1.0-alpha.23a';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@@ -657,8 +657,8 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper
|
||||
->setEmail($parm['email'])
|
||||
->setAddress($parm['address'])
|
||||
->setZipCode($parm['zip'])
|
||||
->setActivity($parm['function'])
|
||||
->setJob($parm['activite'])
|
||||
->setActivity($parm['activite'])
|
||||
->setJob($parm['function'])
|
||||
->setCompany($parm['company'])
|
||||
->setPhone($parm['telephone'])
|
||||
->setFax($parm['fax']);
|
||||
|
@@ -15,7 +15,14 @@ use Doctrine\ORM\Mapping as ORM;
|
||||
use Gedmo\Mapping\Annotation as Gedmo;
|
||||
|
||||
/**
|
||||
* @ORM\Table(name="Tokens")
|
||||
* @ORM\Table(name="Tokens",
|
||||
* indexes={
|
||||
* @ORM\index(name="type", columns={"type"}),
|
||||
* @ORM\index(name="created", columns={"created"}),
|
||||
* @ORM\index(name="updated", columns={"updated"}),
|
||||
* @ORM\index(name="expiration", columns={"expiration"})
|
||||
* }
|
||||
* )
|
||||
* @ORM\Entity(repositoryClass="Alchemy\Phrasea\Model\Repositories\TokenRepository")
|
||||
*/
|
||||
class Token
|
||||
|
@@ -30,7 +30,7 @@ class WebhookEventPayload
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\OneToOne(targetEntity="WebhookEventDelivery")
|
||||
* @ORM\OneToOne(targetEntity="WebhookEventDelivery", inversedBy="payload")
|
||||
* @ORM\JoinColumn(name="delivery_id", referencedColumnName="id")
|
||||
*/
|
||||
private $delivery;
|
||||
|
@@ -22,7 +22,6 @@ use RandomLib\Generator;
|
||||
class TokenManipulator implements ManipulatorInterface
|
||||
{
|
||||
const LETTERS_AND_NUMBERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
const TYPE_FEED_ENTRY = 'FEED_ENTRY';
|
||||
const TYPE_PASSWORD = 'password';
|
||||
const TYPE_ACCOUNT_UNLOCK = 'account-unlock';
|
||||
@@ -126,6 +125,38 @@ class TokenManipulator implements ManipulatorInterface
|
||||
return $this->create($user, self::TYPE_FEED_ENTRY, null, $entry->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create feedEntryTokens for many users in one shot
|
||||
*
|
||||
* @param User[] $users
|
||||
* @param FeedEntry $entry
|
||||
* @return Token[]
|
||||
* @throws \Doctrine\DBAL\DBALException
|
||||
*/
|
||||
public function createFeedEntryTokens($users, FeedEntry $entry)
|
||||
{
|
||||
// $this->removeExpiredTokens();
|
||||
|
||||
$tokens = [];
|
||||
foreach ($users as $user) {
|
||||
$value = $this->random->generateString(32, self::LETTERS_AND_NUMBERS) . $user->getId();
|
||||
|
||||
$token = new Token();
|
||||
$token->setUser($user)
|
||||
->setType(self::TYPE_FEED_ENTRY)
|
||||
->setValue($value)
|
||||
->setExpiration(null)
|
||||
->setData($entry->getId());
|
||||
$tokens[] = $token;
|
||||
|
||||
$this->om->persist($token);
|
||||
}
|
||||
$this->om->flush();
|
||||
$this->om->clear();
|
||||
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param $data
|
||||
|
@@ -72,4 +72,9 @@ class TokenRepository extends EntityRepository
|
||||
|
||||
return $query->getResult();
|
||||
}
|
||||
|
||||
public function getEntityManager()
|
||||
{
|
||||
return parent::getEntityManager();
|
||||
}
|
||||
}
|
||||
|
@@ -122,4 +122,15 @@ class UserRepository extends EntityRepository
|
||||
{
|
||||
return $this->findBy(['templateOwner' => $user->getId()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all templates
|
||||
*/
|
||||
public function findTemplate()
|
||||
{
|
||||
$qb = $this->createQueryBuilder('u');
|
||||
$qb->where('u.templateOwner is NOT NULL');
|
||||
|
||||
return $qb->getQuery()->getResult();
|
||||
}
|
||||
}
|
||||
|
@@ -396,25 +396,25 @@ class PDFRecords extends PDF
|
||||
$this->pdf->SetY($this->pdf->GetY()+10);
|
||||
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, 'B', 12);
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Document generated on : " . " "));
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Document generated on : ") . " ");
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, '', 12);
|
||||
$this->pdf->Write(5, $this->formatDate(new \DateTime('now')));
|
||||
$this->pdf->Write(12, "\n");
|
||||
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, 'B', 12);
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Feedback initiated by : " . " "));
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Feedback initiated by : ") . " ");
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, '', 12);
|
||||
$this->pdf->Write(5, $this->getDisplayName($validation->getInitiator()));
|
||||
$this->pdf->Write(6, "\n");
|
||||
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, 'B', 12);
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Feedback initiated on : " . " "));
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Feedback initiated on : ") . " ");
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, '', 12);
|
||||
$this->pdf->Write(5, $this->formatDate($validation->getCreated()));
|
||||
$this->pdf->Write(6, "\n");
|
||||
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, 'B', 12);
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Feedback expiring on : " . " "));
|
||||
$this->pdf->Write(5, $this->app->trans("print_feedback:: Feedback expiring on : ") . " ");
|
||||
$this->pdf->SetFont(PhraseaPDF::FONT, '', 12);
|
||||
$this->pdf->Write(5, $this->formatDate($validation->getExpires()));
|
||||
$this->pdf->Write(12, "\n");
|
||||
|
@@ -668,18 +668,21 @@ class ElasticSearchEngine implements SearchEngineInterface
|
||||
}
|
||||
// fields aggregates
|
||||
$structure = $this->context_factory->getLimitedStructure($options);
|
||||
foreach ($structure->getFacetFields() as $name => $field) {
|
||||
// 2015-05-26 (mdarse) Removed databox filtering.
|
||||
// It was already done by the ACL filter in the query scope, so no
|
||||
// document that shouldn't be displayed can go this far.
|
||||
foreach($structure->getAllFields() as $name => $field) {
|
||||
$size = $this->options->getAggregableFieldLimit($name);
|
||||
if ($size !== databox_field::FACET_DISABLED) {
|
||||
if ($size === databox_field::FACET_NO_LIMIT) {
|
||||
$size = ESField::FACET_NO_LIMIT;
|
||||
}
|
||||
$agg = [
|
||||
'terms' => [
|
||||
'field' => $field->getIndexField(true),
|
||||
'size' => $field->getFacetValuesLimit()
|
||||
'size' => $size
|
||||
]
|
||||
];
|
||||
$aggs[$name] = AggregationHelper::wrapPrivateFieldAggregation($field, $agg);
|
||||
}
|
||||
}
|
||||
|
||||
return $aggs;
|
||||
}
|
||||
|
@@ -9,6 +9,10 @@
|
||||
*/
|
||||
namespace Alchemy\Phrasea\SearchEngine\Elastic;
|
||||
|
||||
use databox_field;
|
||||
use igorw;
|
||||
|
||||
|
||||
class ElasticsearchOptions
|
||||
{
|
||||
const POPULATE_ORDER_RID = "RECORD_ID";
|
||||
@@ -35,7 +39,7 @@ class ElasticsearchOptions
|
||||
private $populateDirection;
|
||||
|
||||
/** @var int[] */
|
||||
private $_customValues;
|
||||
private $_customValues = [];
|
||||
private $activeTab;
|
||||
|
||||
/**
|
||||
@@ -57,14 +61,10 @@ class ElasticsearchOptions
|
||||
'populate_order' => self::POPULATE_ORDER_RID,
|
||||
'populate_direction' => self::POPULATE_DIRECTION_DESC,
|
||||
'activeTab' => null,
|
||||
'facets' => []
|
||||
];
|
||||
|
||||
foreach(self::getAggregableTechnicalFields() as $k => $f) {
|
||||
$defaultOptions[$k.'_limit'] = 0;
|
||||
}
|
||||
$options = array_replace($defaultOptions, $options);
|
||||
|
||||
|
||||
$self = new self();
|
||||
$self->setHost($options['host']);
|
||||
$self->setPort($options['port']);
|
||||
@@ -76,11 +76,10 @@ class ElasticsearchOptions
|
||||
$self->setPopulateOrder($options['populate_order']);
|
||||
$self->setPopulateDirection($options['populate_direction']);
|
||||
$self->setActiveTab($options['activeTab']);
|
||||
foreach(self::getAggregableTechnicalFields() as $k => $f) {
|
||||
$self->setAggregableFieldLimit($k, $options[$k.'_limit']);
|
||||
foreach($options['facets'] as $fieldname=>$attributes) {
|
||||
$self->setAggregableField($fieldname, $attributes);
|
||||
}
|
||||
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
@@ -99,10 +98,11 @@ class ElasticsearchOptions
|
||||
'highlight' => $this->highlight,
|
||||
'populate_order' => $this->populateOrder,
|
||||
'populate_direction' => $this->populateDirection,
|
||||
'activeTab' => $this->activeTab
|
||||
'activeTab' => $this->activeTab,
|
||||
'facets' => []
|
||||
];
|
||||
foreach(self::getAggregableTechnicalFields() as $k => $f) {
|
||||
$ret[$k.'_limit'] = $this->getAggregableFieldLimit($k);
|
||||
foreach($this->getAggregableFields() as $fieldname=>$attributes) {
|
||||
$ret['facets'][$fieldname] = $attributes;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
@@ -222,12 +222,51 @@ class ElasticsearchOptions
|
||||
|
||||
public function setAggregableFieldLimit($key, $value)
|
||||
{
|
||||
$this->_customValues[$key.'_limit'] = $value;
|
||||
if(is_null($this->getAggregableField($key))) {
|
||||
$this->_customValues['facets'][$key] = [];
|
||||
}
|
||||
$this->_customValues['facets'][$key]['limit'] = $value;
|
||||
}
|
||||
|
||||
public function setAggregableField($key, $attributes)
|
||||
{
|
||||
$this->getAggregableFields(); // ensure facets exists
|
||||
$this->_customValues['facets'][$key] = $attributes;
|
||||
}
|
||||
|
||||
public function getAggregableFieldLimit($key)
|
||||
{
|
||||
return $this->_customValues[$key.'_limit'];
|
||||
$facet = $this->getAggregableField($key);
|
||||
return (is_array($facet) && array_key_exists('limit', $facet)) ? $facet['limit'] : databox_field::FACET_DISABLED;
|
||||
}
|
||||
|
||||
public function getAggregableField($key)
|
||||
{
|
||||
$facets = $this->getAggregableFields();
|
||||
return array_key_exists($key, $facets) ? $facets[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getAggregableFields()
|
||||
{
|
||||
if(!array_key_exists('facets', $this->_customValues) || !is_array($this->_customValues['facets'])) {
|
||||
$this->_customValues['facets'] = [];
|
||||
}
|
||||
return $this->_customValues['facets'];
|
||||
}
|
||||
|
||||
// set to change the facets order during admin/form save
|
||||
public function reorderAggregableFields($facetNames)
|
||||
{
|
||||
$newFacets = [];
|
||||
foreach ($facetNames as $name) {
|
||||
if(($facet = $this->getAggregableField($name)) !== null) {
|
||||
$newFacets[$name] = $facet;
|
||||
}
|
||||
}
|
||||
$this->_customValues['facets'] = $newFacets;
|
||||
}
|
||||
|
||||
public function getActiveTab()
|
||||
@@ -241,56 +280,56 @@ class ElasticsearchOptions
|
||||
|
||||
public function __get($key)
|
||||
{
|
||||
if(!array_key_exists($key, $this->_customValues)) {
|
||||
$this->_customValues[$key] = 0;
|
||||
}
|
||||
return $this->_customValues[$key];
|
||||
$keys = explode(':', $key);
|
||||
|
||||
return igorw\get_in($this->_customValues, $keys);
|
||||
}
|
||||
|
||||
public function __set($key, $value)
|
||||
{
|
||||
$this->_customValues[$key] = $value;
|
||||
$keys = explode(':', $key);
|
||||
$this->_customValues = igorw\assoc_in($this->_customValues, $keys, $value);
|
||||
}
|
||||
|
||||
public static function getAggregableTechnicalFields()
|
||||
{
|
||||
return [
|
||||
'base_aggregate' => [
|
||||
'_base' => [
|
||||
'type' => 'string',
|
||||
'label' => 'prod::facet:base_label',
|
||||
'field' => "database",
|
||||
'esfield' => 'databox_name',
|
||||
'query' => 'database:%s',
|
||||
],
|
||||
'collection_aggregate' => [
|
||||
'_collection' => [
|
||||
'type' => 'string',
|
||||
'label' => 'prod::facet:collection_label',
|
||||
'field' => "collection",
|
||||
'esfield' => 'collection_name',
|
||||
'query' => 'collection:%s',
|
||||
],
|
||||
'doctype_aggregate' => [
|
||||
'_doctype' => [
|
||||
'type' => 'string',
|
||||
'label' => 'prod::facet:doctype_label',
|
||||
'field' => "type",
|
||||
'esfield' => 'type',
|
||||
'query' => 'type:%s',
|
||||
],
|
||||
'camera_model_aggregate' => [
|
||||
'_camera_model' => [
|
||||
'type' => 'string',
|
||||
'label' => 'Camera Model',
|
||||
'field' => "meta.CameraModel",
|
||||
'esfield' => 'metadata_tags.CameraModel',
|
||||
'query' => 'meta.CameraModel:%s',
|
||||
],
|
||||
'iso_aggregate' => [
|
||||
'_iso' => [
|
||||
'type' => 'number',
|
||||
'label' => 'ISO',
|
||||
'field' => "meta.ISO",
|
||||
'esfield' => 'metadata_tags.ISO',
|
||||
'query' => 'meta.ISO=%s',
|
||||
],
|
||||
'aperture_aggregate' => [
|
||||
'_aperture' => [
|
||||
'type' => 'number',
|
||||
'label' => 'Aperture',
|
||||
'field' => "meta.Aperture",
|
||||
@@ -300,7 +339,7 @@ class ElasticsearchOptions
|
||||
return round($value, 1);
|
||||
},
|
||||
],
|
||||
'shutterspeed_aggregate' => [
|
||||
'_shutterspeed' => [
|
||||
'type' => 'number',
|
||||
'label' => 'Shutter speed',
|
||||
'field' => "meta.ShutterSpeed",
|
||||
@@ -313,7 +352,7 @@ class ElasticsearchOptions
|
||||
return $value . ' s.';
|
||||
},
|
||||
],
|
||||
'flashfired_aggregate' => [
|
||||
'_flashfired' => [
|
||||
'type' => 'boolean',
|
||||
'label' => 'FlashFired',
|
||||
'field' => "meta.FlashFired",
|
||||
@@ -327,49 +366,49 @@ class ElasticsearchOptions
|
||||
return array_key_exists($value, $map) ? $map[$value] : $value;
|
||||
},
|
||||
],
|
||||
'framerate_aggregate' => [
|
||||
'_framerate' => [
|
||||
'type' => 'number',
|
||||
'label' => 'FrameRate',
|
||||
'field' => "meta.FrameRate",
|
||||
'esfield' => 'metadata_tags.FrameRate',
|
||||
'query' => 'meta.FrameRate=%s',
|
||||
],
|
||||
'audiosamplerate_aggregate' => [
|
||||
'_audiosamplerate' => [
|
||||
'type' => 'number',
|
||||
'label' => 'Audio Samplerate',
|
||||
'field' => "meta.AudioSamplerate",
|
||||
'esfield' => 'metadata_tags.AudioSamplerate',
|
||||
'query' => 'meta.AudioSamplerate=%s',
|
||||
],
|
||||
'videocodec_aggregate' => [
|
||||
'_videocodec' => [
|
||||
'type' => 'string',
|
||||
'label' => 'Video codec',
|
||||
'field' => "meta.VideoCodec",
|
||||
'esfield' => 'metadata_tags.VideoCodec',
|
||||
'query' => 'meta.VideoCodec:%s',
|
||||
],
|
||||
'audiocodec_aggregate' => [
|
||||
'_audiocodec' => [
|
||||
'type' => 'string',
|
||||
'label' => 'Audio codec',
|
||||
'field' => "meta.AudioCodec",
|
||||
'esfield' => 'metadata_tags.AudioCodec',
|
||||
'query' => 'meta.AudioCodec:%s',
|
||||
],
|
||||
'orientation_aggregate' => [
|
||||
'_orientation' => [
|
||||
'type' => 'string',
|
||||
'label' => 'Orientation',
|
||||
'field' => "meta.Orientation",
|
||||
'esfield' => 'metadata_tags.Orientation',
|
||||
'query' => 'meta.Orientation=%s',
|
||||
],
|
||||
'colorspace_aggregate' => [
|
||||
'_colorspace' => [
|
||||
'type' => 'string',
|
||||
'label' => 'Colorspace',
|
||||
'field' => "meta.ColorSpace",
|
||||
'esfield' => 'metadata_tags.ColorSpace',
|
||||
'query' => 'meta.ColorSpace:%s',
|
||||
],
|
||||
'mimetype_aggregate' => [
|
||||
'_mimetype' => [
|
||||
'type' => 'string',
|
||||
'label' => 'MimeType',
|
||||
'field' => "meta.MimeType",
|
||||
|
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
namespace Alchemy\Phrasea\SearchEngine\Elastic;
|
||||
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\GlobalStructure;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
@@ -17,6 +18,18 @@ use Symfony\Component\Validator\Constraints\Range;
|
||||
|
||||
class ElasticsearchSettingsFormType extends AbstractType
|
||||
{
|
||||
/** @var GlobalStructure */
|
||||
private $globalStructure;
|
||||
|
||||
/** @var ElasticsearchOptions */
|
||||
private $esSettings;
|
||||
|
||||
public function __construct(GlobalStructure $g, ElasticsearchOptions $settings)
|
||||
{
|
||||
$this->globalStructure = $g;
|
||||
$this->esSettings = $settings;
|
||||
}
|
||||
|
||||
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||
{
|
||||
$builder
|
||||
@@ -56,36 +69,7 @@ class ElasticsearchSettingsFormType extends AbstractType
|
||||
->add('minScore', 'integer', [
|
||||
'label' => 'Thesaurus Min score',
|
||||
'constraints' => new Range(['min' => 0]),
|
||||
]);
|
||||
|
||||
foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) {
|
||||
if(array_key_exists('choices', $f)) {
|
||||
// choices[] : choice_key => choice_value
|
||||
$choices = $f['choices'];
|
||||
}
|
||||
else {
|
||||
$choices = [
|
||||
"10 values" => 10,
|
||||
"20 values" => 20,
|
||||
"50 values" => 50,
|
||||
"100 values" => 100,
|
||||
"all values" => -1
|
||||
];
|
||||
}
|
||||
// array_unshift($choices, "not aggregated"); // always as first choice
|
||||
$choices = array_merge(["not aggregated" => 0], $choices);
|
||||
$builder
|
||||
->add($k.'_limit', ChoiceType::class, [
|
||||
// 'label' => $f['label'],// . ' ' . 'aggregate limit',
|
||||
'choices_as_values' => true,
|
||||
'choices' => $choices,
|
||||
'attr' => [
|
||||
'class' => 'aggregate'
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
$builder
|
||||
])
|
||||
->add('highlight', 'checkbox', [
|
||||
'label' => 'Activate highlight',
|
||||
'required' => false
|
||||
@@ -108,7 +92,66 @@ class ElasticsearchSettingsFormType extends AbstractType
|
||||
])
|
||||
->add('activeTab', 'hidden');
|
||||
|
||||
;
|
||||
// keep aggregates in configuration order with this intermediate array
|
||||
$aggs = [];
|
||||
|
||||
// helper fct to add aggregate to a tmp list
|
||||
$addAgg = function($k, $label, $help, $disabled=false, $choices=null) use (&$aggs) {
|
||||
if(!$choices) {
|
||||
$choices = [
|
||||
"10 values" => 10,
|
||||
"50 values" => 50,
|
||||
"100 values" => 100,
|
||||
"all values" => -1
|
||||
];
|
||||
}
|
||||
$choices = array_merge(["not aggregated" => 0], $choices); // add this option always as first choice
|
||||
$aggs[$k] = [ // default value will be replaced by hardcoded tech fields & all databoxes fields
|
||||
'label' => $label,
|
||||
'choices_as_values' => true,
|
||||
'choices' => $choices,
|
||||
'attr' => [
|
||||
'class' => 'aggregate'
|
||||
],
|
||||
'disabled' => $disabled,
|
||||
'help_message' => $help // todo : not displayed ?
|
||||
];
|
||||
};
|
||||
|
||||
// all fields fron conf
|
||||
foreach($this->esSettings->getAggregableFields() as $k=>$f) {
|
||||
// default value will be replaced by hardcoded tech fields & all databoxes fields
|
||||
$addAgg($k, "/?\\ " . $k, "This field does not exists in current databoxes.", true);
|
||||
}
|
||||
|
||||
// add or replace hardcoded tech fields
|
||||
foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) {
|
||||
$choices = array_key_exists('choices', $f) ? $f['choices'] : null; // a tech-field can publish it's own choices
|
||||
$help = null;
|
||||
$label = '#' . $k;
|
||||
if(!array_key_exists($k, $aggs)) {
|
||||
$label = "/!\\ " . $label;
|
||||
$help = "New field, please confirm setting.";
|
||||
}
|
||||
$addAgg($k, $label, $help, false, $choices);
|
||||
}
|
||||
|
||||
// add or replace all databoxes fields (nb: new db field - unknown in conf - will be a the end)
|
||||
foreach($this->globalStructure->getAllFields() as $field) {
|
||||
$k = $label = $field->getName();
|
||||
$help = null;
|
||||
if(!array_key_exists($field->getName(), $aggs)) {
|
||||
$label = "/!\\ " . $label;
|
||||
$help = "New field, please confirm setting.";
|
||||
}
|
||||
$addAgg($k, $label, $help); // default choices
|
||||
}
|
||||
|
||||
// populate aggs to form
|
||||
foreach($aggs as $k=>$agg) {
|
||||
$builder->add('facets:' . $k . ':limit', ChoiceType::class, $agg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function getName()
|
||||
|
@@ -15,7 +15,7 @@ class FacetsResponse
|
||||
private $escaper;
|
||||
private $facets = array();
|
||||
|
||||
public function __construct(Escaper $escaper, array $response, GlobalStructure $structure)
|
||||
public function __construct(ElasticsearchOptions $options, Escaper $escaper, array $response, GlobalStructure $structure)
|
||||
{
|
||||
$this->escaper = $escaper;
|
||||
|
||||
@@ -25,7 +25,13 @@ class FacetsResponse
|
||||
|
||||
$atf = ElasticsearchOptions::getAggregableTechnicalFields();
|
||||
|
||||
foreach ($response['aggregations'] as $name => $aggregation) {
|
||||
// sort facets respecting the order defined in options
|
||||
foreach($options->getAggregableFields() as $name=>$foptions) {
|
||||
if(!array_key_exists($name, $response['aggregations'])) {
|
||||
continue;
|
||||
}
|
||||
$aggregation = $response['aggregations'][$name];
|
||||
|
||||
$tf = null;
|
||||
$valueFormatter = function($v){ return $v; }; // default equality formatter
|
||||
|
||||
@@ -78,6 +84,7 @@ class FacetsResponse
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -35,11 +35,6 @@ final class GlobalStructure implements Structure
|
||||
*/
|
||||
private $private = array();
|
||||
|
||||
/**
|
||||
* @var Field[]
|
||||
*/
|
||||
private $facets = array();
|
||||
|
||||
/**
|
||||
* @var Flag[]
|
||||
*/
|
||||
@@ -145,9 +140,11 @@ final class GlobalStructure implements Structure
|
||||
$this->private[$name] = $field;
|
||||
}
|
||||
|
||||
/*
|
||||
if ($field->isFacet() && $field->isSearchable()) {
|
||||
$this->facets[$name] = $field;
|
||||
}
|
||||
*/
|
||||
|
||||
if ($field->hasConceptInference()) {
|
||||
$this->thesaurus_fields[$name] = $field;
|
||||
@@ -183,14 +180,6 @@ final class GlobalStructure implements Structure
|
||||
return $this->private;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Field[]
|
||||
*/
|
||||
public function getFacetFields()
|
||||
{
|
||||
return $this->facets;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Field[]
|
||||
*/
|
||||
|
@@ -47,14 +47,6 @@ final class LimitedStructure implements Structure
|
||||
return $this->limit($this->structure->getPrivateFields());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Field[]
|
||||
*/
|
||||
public function getFacetFields()
|
||||
{
|
||||
return $this->limit($this->structure->getFacetFields());
|
||||
}
|
||||
|
||||
public function getThesaurusEnabledFields()
|
||||
{
|
||||
return $this->limit($this->structure->getThesaurusEnabledFields());
|
||||
|
@@ -33,11 +33,6 @@ interface Structure
|
||||
*/
|
||||
public function getPrivateFields();
|
||||
|
||||
/**
|
||||
* @return Field[]
|
||||
*/
|
||||
public function getFacetFields();
|
||||
|
||||
/**
|
||||
* @return Field[]
|
||||
*/
|
||||
|
@@ -39,7 +39,6 @@ class eventsmanager_broker
|
||||
],
|
||||
'notify' => [
|
||||
'eventsmanager_notify_autoregister',
|
||||
'eventsmanager_notify_bridgeuploadfail',
|
||||
'eventsmanager_notify_downloadmailfail',
|
||||
'eventsmanager_notify_feed',
|
||||
'eventsmanager_notify_order',
|
||||
|
@@ -42,7 +42,7 @@ class eventsmanager_notify_order extends eventsmanager_notifyAbstract
|
||||
$ret = [
|
||||
'text' => $this->app->trans('%user% a passe une %opening_link% commande %end_link%', [
|
||||
'%user%' => $sender,
|
||||
'%opening_link%' => '<a href="/prod/order/'.$order_id.'/" class="dialog full-dialog" title="'.$this->app->trans('Orders manager').'">',
|
||||
'%opening_link%' => '<a href="#" class="order-notif" data-id="'.$order_id.'" title="'.$this->app->trans('Orders manager').'">',
|
||||
'%end_link%' => '</a>',])
|
||||
, 'class' => ''
|
||||
];
|
||||
|
@@ -62,6 +62,16 @@ class patch_410alpha17a implements patchInterface
|
||||
// $sql = "ALTER TABLE `metadatas_structure` ADD `gui_editable` INT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `readonly`";
|
||||
// $databox->get_connection()->executeQuery($sql);
|
||||
|
||||
foreach ($databox->get_meta_structure() as $databox_field) {
|
||||
if ($databox_field->get_tbranch() != '') {
|
||||
$databox_field->set_generate_cterms(true);
|
||||
} else {
|
||||
$databox_field->set_generate_cterms(false);
|
||||
}
|
||||
|
||||
$databox_field->save();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
111
lib/classes/patch/410alpha21a.php
Normal file
111
lib/classes/patch/410alpha21a.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2019 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
|
||||
class patch_410alpha21a implements patchInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $release = '4.1.0-alpha.21a';
|
||||
|
||||
/** @var array */
|
||||
private $concern = [base::DATA_BOX];
|
||||
|
||||
/**
|
||||
* Returns the release version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_release()
|
||||
{
|
||||
return $this->release;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function concern()
|
||||
{
|
||||
return $this->concern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function require_all_upgrades()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDoctrineMigrations()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(base $databox, Application $app)
|
||||
{
|
||||
// fix the Longitude value
|
||||
|
||||
$sql = 'SELECT id, record_id, name, value FROM technical_datas WHERE trim(name) = "LongitudeRef" ';
|
||||
$stmt = $databox->get_connection()->prepare($sql);
|
||||
$stmt->execute();
|
||||
$rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
foreach ($rs as $row) {
|
||||
if (trim($row['value']) === 'W' ) {
|
||||
$sql = 'UPDATE technical_datas SET value = CONCAT("-", value) WHERE trim(name) = "Longitude" AND record_id =:record_id';
|
||||
$stmt = $databox->get_connection()->prepare($sql);
|
||||
$stmt->execute([':record_id' => $row['record_id']]);
|
||||
}
|
||||
|
||||
$sqlDelete = 'DELETE FROM technical_datas WHERE id =:id';
|
||||
|
||||
$stmt1 = $databox->get_connection()->prepare($sqlDelete);
|
||||
$stmt1->execute([':id' => $row['id']]);
|
||||
$stmt1->closeCursor();
|
||||
}
|
||||
|
||||
$stmt->closeCursor();
|
||||
|
||||
// fix the Latitude value
|
||||
|
||||
$sql = 'SELECT id, record_id, name, value FROM technical_datas WHERE trim(name) = "LatitudeRef" ';
|
||||
$stmt = $databox->get_connection()->prepare($sql);
|
||||
$stmt->execute();
|
||||
$rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$stmt->closeCursor();
|
||||
|
||||
foreach ($rs as $row) {
|
||||
if (trim($row['value']) === 'S' ) {
|
||||
$sql = 'UPDATE technical_datas SET value = CONCAT("-", value) WHERE trim(name) = "Latitude" AND record_id =:record_id';
|
||||
$stmt = $databox->get_connection()->prepare($sql);
|
||||
$stmt->execute([':record_id' => $row['record_id']]);
|
||||
}
|
||||
|
||||
$sqlDelete = 'DELETE FROM technical_datas WHERE id =:id';
|
||||
|
||||
$stmt1 = $databox->get_connection()->prepare($sqlDelete);
|
||||
$stmt1->execute([':id' => $row['id']]);
|
||||
$stmt1->closeCursor();
|
||||
}
|
||||
|
||||
$stmt->closeCursor();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
75
lib/classes/patch/410alpha22a.php
Normal file
75
lib/classes/patch/410alpha22a.php
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2019 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
|
||||
class patch_410alpha22a implements patchInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $release = '4.1.0-alpha.22a';
|
||||
|
||||
/** @var array */
|
||||
private $concern = [base::APPLICATION_BOX];
|
||||
|
||||
/**
|
||||
* Returns the release version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_release()
|
||||
{
|
||||
return $this->release;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function concern()
|
||||
{
|
||||
return $this->concern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function require_all_upgrades()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDoctrineMigrations()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(base $appbox, Application $app)
|
||||
{
|
||||
foreach(['type', 'created', 'updated', 'expiration'] as $t) {
|
||||
$sql = "ALTER TABLE `Tokens` ADD INDEX `".$t."` (`".$t."`);";
|
||||
try {
|
||||
$stmt = $appbox->get_connection()->prepare($sql);
|
||||
$stmt->execute();
|
||||
$stmt->closeCursor();
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
// the inex already exists ?
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
111
lib/classes/patch/410alpha23a.php
Normal file
111
lib/classes/patch/410alpha23a.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
* (c) 2005-2019 Alchemy
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
|
||||
class patch_410alpha23a implements patchInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $release = '4.1.0-alpha.23a';
|
||||
|
||||
/** @var array */
|
||||
private $concern = [base::APPLICATION_BOX];
|
||||
|
||||
/**
|
||||
* Returns the release version.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_release()
|
||||
{
|
||||
return $this->release;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function concern()
|
||||
{
|
||||
return $this->concern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function require_all_upgrades()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDoctrineMigrations()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(base $appbox, Application $app)
|
||||
{
|
||||
// fix embed-bundle keys
|
||||
if ($app['conf']->has(['embed_bundle', 'video', 'available-speeds'])) {
|
||||
$availableSpeed = $app['conf']->get(['embed_bundle', 'video', 'available-speeds']);
|
||||
$app['conf']->remove(['embed_bundle', 'video', 'available-speeds']);
|
||||
$app['conf']->set(['embed_bundle', 'video', 'available_speeds'], $availableSpeed);
|
||||
}
|
||||
|
||||
if ($app['conf']->has(['embed_bundle', 'audio', 'available-speeds'])) {
|
||||
$availableSpeed = $app['conf']->get(['embed_bundle', 'audio', 'available-speeds']);
|
||||
$app['conf']->remove(['embed_bundle', 'audio', 'available-speeds']);
|
||||
$app['conf']->set(['embed_bundle', 'audio', 'available_speeds'], $availableSpeed);
|
||||
}
|
||||
|
||||
if ($app['conf']->has(['embed_bundle', 'document', 'enable-pdfjs'])) {
|
||||
$enablePdfjs = $app['conf']->get(['embed_bundle', 'document', 'enable-pdfjs']);
|
||||
$app['conf']->remove(['embed_bundle', 'document', 'enable-pdfjs']);
|
||||
$app['conf']->set(['embed_bundle', 'document', 'enable_pdfjs'], $enablePdfjs);
|
||||
}
|
||||
|
||||
// geoloc section change replace 'name' to 'map-provider'
|
||||
if ($app['conf']->has(['geocoding-providers', 0, 'name'])) {
|
||||
$geocodingName = $app['conf']->get(['geocoding-providers', 0, 'name']);
|
||||
$app['conf']->remove(['geocoding-providers', 0, 'name']);
|
||||
$app['conf']->set(['geocoding-providers', 0, 'map-provider'], $geocodingName);
|
||||
}
|
||||
|
||||
// video-editor section change, replace 'vttFieldName' to 'ChapterVttFieldName'
|
||||
if ($app['conf']->has(['video-editor', 'vttFieldName'])) {
|
||||
$chapterVttFieldName = $app['conf']->get(['video-editor', 'vttFieldName']);
|
||||
$app['conf']->remove(['video-editor', 'vttFieldName']);
|
||||
$app['conf']->set(['video-editor', 'ChapterVttFieldName'], $chapterVttFieldName);
|
||||
}
|
||||
|
||||
// remove registry classic section if exist
|
||||
if ($app['conf']->has(['registry', 'classic'])) {
|
||||
$app['conf']->remove(['registry', 'classic']);
|
||||
}
|
||||
|
||||
// remove bridge section if exist
|
||||
if ($app['conf']->has(['main', 'bridge'])) {
|
||||
$app['conf']->remove(['main', 'bridge']);
|
||||
}
|
||||
|
||||
// insert RGPD bloc if not exist
|
||||
if (!$app['conf']->has(['user_account', 'deleting_policies', 'email_confirmation'])) {
|
||||
$app['conf']->set(['user_account', 'deleting_policies', 'email_confirmation'], true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -39,21 +39,37 @@ main:
|
||||
populate_order: RECORD_ID
|
||||
populate_direction: DESC
|
||||
activeTab: '#elastic-search'
|
||||
base_aggregate_limit: 10
|
||||
collection_aggregate_limit: 10
|
||||
doctype_aggregate_limit: 0
|
||||
camera_model_aggregate_limit: 0
|
||||
iso_aggregate_limit: 0
|
||||
aperture_aggregate_limit: 0
|
||||
shutterspeed_aggregate_limit: 0
|
||||
flashfired_aggregate_limit: 0
|
||||
framerate_aggregate_limit: 0
|
||||
audiosamplerate_aggregate_limit: 0
|
||||
videocodec_aggregate_limit: 0
|
||||
audiocodec_aggregate_limit: 0
|
||||
orientation_aggregate_limit: 0
|
||||
colorspace_aggregate_limit: 0
|
||||
mimetype_aggregate_limit: 0
|
||||
facets:
|
||||
_base:
|
||||
limit: 10
|
||||
_collection:
|
||||
limit: 10
|
||||
_doctype:
|
||||
limit: 10
|
||||
_camera_model:
|
||||
limit: 0
|
||||
_iso:
|
||||
limit: 0
|
||||
_aperture:
|
||||
limit: 0
|
||||
_shutterspeed:
|
||||
limit: 0
|
||||
_flashfired:
|
||||
limit: 0
|
||||
_framerate:
|
||||
limit: 0
|
||||
_audiosamplerate:
|
||||
limit: 0
|
||||
_videocodec:
|
||||
limit: 0
|
||||
_audiocodec:
|
||||
limit: 0
|
||||
_orientation:
|
||||
limit: 0
|
||||
_colorspace:
|
||||
limit: 0
|
||||
_mimetype:
|
||||
limit: 0
|
||||
task-manager:
|
||||
status: started
|
||||
enabled: true
|
||||
@@ -87,6 +103,7 @@ main:
|
||||
mp4box_timeout: 60
|
||||
swftools_timeout: 60
|
||||
unoconv_timeout: 60
|
||||
exiftool_timeout: 60
|
||||
storage:
|
||||
subdefs: null
|
||||
cache: null
|
||||
@@ -94,6 +111,7 @@ main:
|
||||
download: null
|
||||
lazaret: null
|
||||
caption: null
|
||||
tmp_files: null
|
||||
|
||||
trusted-proxies: []
|
||||
debugger:
|
||||
@@ -241,7 +259,7 @@ embed_bundle:
|
||||
geocoding-providers:
|
||||
-
|
||||
map-provider: 'mapboxWebGL'
|
||||
enabled: true
|
||||
enabled: false
|
||||
public-key: ''
|
||||
map-layers:
|
||||
-
|
||||
@@ -284,7 +302,7 @@ geocoding-providers:
|
||||
provincefields: Province
|
||||
countryfields: 'Country, Pays'
|
||||
video-editor:
|
||||
vttFieldName: VideoTextTrackChapters
|
||||
ChapterVttFieldName: VideoTextTrackChapters
|
||||
seekBackwardStep: 500 # in ms
|
||||
seekForwardStep: 500 # in ms
|
||||
playbackRates:
|
||||
|
@@ -65,7 +65,7 @@
|
||||
"normalize-css": "^2.1.0",
|
||||
"npm": "^6.0.0",
|
||||
"npm-modernizr": "^2.8.3",
|
||||
"phraseanet-production-client": "0.34.116-d",
|
||||
"phraseanet-production-client": "0.34.139-d",
|
||||
"requirejs": "^2.3.5",
|
||||
"tinymce": "^4.0.28",
|
||||
"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
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-01-29T14:29:07Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<file date="2020-02-20T14:37:38Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-01-29T14:29:20Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<file date="2020-02-20T14:37:51Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-01-29T14:29:36Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<file date="2020-02-20T14:38:04Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2020-01-29T14:29:56Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<file date="2020-02-20T14:38:19Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
|
@@ -17,3 +17,157 @@ $mainMenuMarginBottom: 30px;
|
||||
#mainContent {
|
||||
padding-top: $mainMenuHeight;
|
||||
}
|
||||
|
||||
|
||||
/*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;
|
||||
}
|
||||
|
||||
.phraseanet_logo {
|
||||
background: url(../../common/images/logo_phraseanet.png) no-repeat center center /contain;
|
||||
height: 75px;
|
||||
width: 230px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.phraseanet_version {
|
||||
font-size: 15px;
|
||||
font-family: Roboto;
|
||||
font-weight: 500;
|
||||
color: #b7b7b7;
|
||||
padding-left: 58px;
|
||||
a {
|
||||
color: #b7b7b7;
|
||||
&:hover {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.phraseanet_about_top {
|
||||
background: #4e4e4e;
|
||||
padding: 30px 20px;
|
||||
}
|
||||
.phraseanet_about_bottom {
|
||||
padding: 25px 20px;
|
||||
min-height: 150px;
|
||||
background: #c8c8c8;
|
||||
a {
|
||||
font-family: Roboto;
|
||||
line-height: 1.2;
|
||||
font-size: 15px!important;
|
||||
font-weight: 500;
|
||||
color: #000000!important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
.phraseanet_gpl {
|
||||
img {
|
||||
position: absolute;
|
||||
width: 84px;
|
||||
}
|
||||
span {
|
||||
padding-top: 26px;
|
||||
display: inline-block;
|
||||
padding-left: 100px;
|
||||
padding-bottom: 20px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.ui-dialog {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: .2em;
|
||||
outline: 0;
|
||||
}
|
||||
.ui-dialog .ui-dialog-titlebar {
|
||||
padding: .4em 1em;
|
||||
position: relative;
|
||||
}
|
||||
.ui-dialog .ui-dialog-title {
|
||||
float: left;
|
||||
margin: .1em 0;
|
||||
white-space: nowrap;
|
||||
width: 90%;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.ui-dialog .ui-dialog-titlebar-close {
|
||||
position: absolute;
|
||||
right: .3em;
|
||||
top: 50%;
|
||||
width: 21px;
|
||||
margin: -10px 0 0 0;
|
||||
padding: 1px;
|
||||
height: 20px;
|
||||
text-indent: -9999999px;
|
||||
}
|
||||
.ui-dialog .ui-dialog-content {
|
||||
position: relative;
|
||||
border: 0;
|
||||
padding: .5em 1em;
|
||||
background: none;
|
||||
overflow: auto;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane {
|
||||
text-align: left;
|
||||
border-width: 1px 0 0 0;
|
||||
background-image: none;
|
||||
margin-top: .5em;
|
||||
padding: .3em 1em .5em .4em;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
|
||||
float: right;
|
||||
}
|
||||
.ui-dialog .ui-dialog-buttonpane button {
|
||||
margin: .5em .4em .5em 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.overlay,
|
||||
.ui-widget-overlay {
|
||||
background-color: #000;
|
||||
opacity: 0.7;
|
||||
filter: alpha(opacity=70);
|
||||
height: 100%;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
|
||||
.ui-icon, .ui-widget-content .ui-icon {
|
||||
background-image: url(/assets/vendors/jquery-ui/images/ui-lightness/ui-icons_222222_256x240.png)!important;
|
||||
display: block;
|
||||
text-indent: -99999px;
|
||||
overflow: hidden;
|
||||
background-repeat: no-repeat;
|
||||
background-position: -96px -128px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
@@ -325,6 +325,7 @@ div.switch_right.unchecked {
|
||||
.ui-dialog-titlebar-close {
|
||||
border: none;
|
||||
margin-right: 4px;
|
||||
text-indent: -9999999px;
|
||||
}
|
||||
.ui-icon.ui-icon-closethick {
|
||||
background-image: url("/assets/common/images/icons/cross-white.png");
|
||||
@@ -841,6 +842,76 @@ span.simplecolorpicker.picker {
|
||||
}
|
||||
}
|
||||
|
||||
.help-trigger {
|
||||
display:inline-block;
|
||||
cursor:pointer;
|
||||
padding: 0 4px;
|
||||
border:none;
|
||||
margin-left: -12px;
|
||||
}
|
||||
|
||||
.phraseanet_logo {
|
||||
background: url(../../common/images/logo_phraseanet.png) no-repeat center center /contain;
|
||||
height: 75px;
|
||||
width: 230px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.phraseanet_version {
|
||||
font-size: 15px;
|
||||
font-family: Roboto;
|
||||
font-weight: 500;
|
||||
color: #b7b7b7;
|
||||
padding-left: 58px;
|
||||
a {
|
||||
color: #b7b7b7;
|
||||
&:hover {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.phraseanet_about_top {
|
||||
background: #4e4e4e;
|
||||
padding: 30px 20px;
|
||||
}
|
||||
.phraseanet_about_bottom {
|
||||
padding: 25px 20px;
|
||||
min-height: 150px;
|
||||
background: #c8c8c8;
|
||||
a {
|
||||
font-family: Roboto;
|
||||
line-height: 1.2;
|
||||
font-size: 15px!important;
|
||||
font-weight: 500;
|
||||
color: #000000!important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
.phraseanet_gpl {
|
||||
img {
|
||||
position: absolute;
|
||||
width: 84px;
|
||||
}
|
||||
span {
|
||||
padding-top: 26px;
|
||||
display: inline-block;
|
||||
padding-left: 100px;
|
||||
padding-bottom: 20px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
.ui-icon, .ui-widget-content .ui-icon {
|
||||
background-image: url(/assets/vendors/jquery-ui/images/ui-lightness/ui-icons_222222_256x240.png)!important;
|
||||
}
|
||||
.ui-dialog-titlebar-close {
|
||||
text-indent: -9999999px;
|
||||
}
|
||||
@import './databases';
|
||||
@import './fields';
|
||||
@import './tables';
|
||||
|
BIN
resources/www/common/images/GPLv3_Logo.png
Normal file
BIN
resources/www/common/images/GPLv3_Logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 42 KiB |
BIN
resources/www/common/images/logo_phraseanet.png
Normal file
BIN
resources/www/common/images/logo_phraseanet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
@@ -94,7 +94,7 @@ var commonModule = (function ($, p4) {
|
||||
.empty()
|
||||
.append(el.attr('infos'))
|
||||
.dialog({
|
||||
|
||||
title: 'About',
|
||||
autoOpen: false,
|
||||
closeOnEscape: true,
|
||||
resizable: false,
|
||||
@@ -106,7 +106,7 @@ var commonModule = (function ($, p4) {
|
||||
backgroundColor: '#000',
|
||||
opacity: 0.7
|
||||
}
|
||||
}).dialog('open').css({'overflow-x': 'auto', 'overflow-y': 'auto'});
|
||||
}).dialog('open').css({'overflow-x': 'auto', 'overflow-y': 'hidden', 'padding': '0'});
|
||||
}
|
||||
|
||||
|
||||
|
@@ -107,3 +107,60 @@ $mainMenuLinkBackgroundHoverColor: transparent;
|
||||
margin-left: -12px;
|
||||
}
|
||||
|
||||
.phraseanet_logo {
|
||||
background: url(../images/logo_phraseanet.png) no-repeat center center /contain;
|
||||
height: 75px;
|
||||
width: 230px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.phraseanet_version {
|
||||
font-size: 15px;
|
||||
font-family: Roboto;
|
||||
font-weight: 500;
|
||||
color: #b7b7b7;
|
||||
padding-left: 58px;
|
||||
a {
|
||||
color: #b7b7b7;
|
||||
&:hover {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.phraseanet_about_top {
|
||||
background: #4e4e4e;
|
||||
padding: 30px 20px;
|
||||
}
|
||||
.phraseanet_about_bottom {
|
||||
padding: 25px 20px;
|
||||
min-height: 150px;
|
||||
background: #c8c8c8;
|
||||
a {
|
||||
font-family: Roboto;
|
||||
line-height: 1.2;
|
||||
font-size: 15px!important;
|
||||
font-weight: 500;
|
||||
color: #000000!important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
.phraseanet_gpl {
|
||||
img {
|
||||
position: absolute;
|
||||
width: 84px;
|
||||
}
|
||||
span {
|
||||
padding-top: 26px;
|
||||
display: inline-block;
|
||||
padding-left: 100px;
|
||||
padding-bottom: 20px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -360,3 +360,86 @@ $select-height: 26px;
|
||||
#mainMenu li .context-menu-item-inner a:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.ui-dialog-titlebar-close {
|
||||
text-indent: -9999999px;
|
||||
}
|
||||
|
||||
|
||||
/*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;
|
||||
}
|
||||
|
||||
.phraseanet_logo {
|
||||
background: url(../../common/images/logo_phraseanet.png) no-repeat center center /contain;
|
||||
height: 75px;
|
||||
width: 230px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.phraseanet_version {
|
||||
font-size: 15px;
|
||||
font-family: Roboto;
|
||||
font-weight: 500;
|
||||
color: #b7b7b7;
|
||||
padding-left: 58px;
|
||||
a {
|
||||
color: #b7b7b7;
|
||||
&:hover {
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.phraseanet_about_top {
|
||||
background: #4e4e4e;
|
||||
padding: 30px 20px;
|
||||
}
|
||||
.phraseanet_about_bottom {
|
||||
padding: 25px 20px;
|
||||
min-height: 150px;
|
||||
background: #c8c8c8;
|
||||
a {
|
||||
font-family: Roboto;
|
||||
line-height: 1.2;
|
||||
font-size: 15px!important;
|
||||
font-weight: 500;
|
||||
color: #000000!important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
.phraseanet_gpl {
|
||||
img {
|
||||
position: absolute;
|
||||
width: 84px;
|
||||
}
|
||||
span {
|
||||
padding-top: 26px;
|
||||
display: inline-block;
|
||||
padding-left: 100px;
|
||||
padding-bottom: 20px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.ui-icon, .ui-widget-content .ui-icon {
|
||||
background-image: url(/assets/vendors/jquery-ui/images/ui-lightness/ui-icons_222222_256x240.png)!important;
|
||||
}
|
||||
|
@@ -107,7 +107,7 @@
|
||||
<div class="control-group">
|
||||
<label class="form_label control-label" for="form_function"><strong>{{ "admin::compte-utilisateur poste" | trans }}</strong></label>
|
||||
<div class="controls">
|
||||
<input class="input_element input-xlarge" type="text" name="form_function" id="form_function" value="{{ app["authentication"].getUser().getActivity() }}" />
|
||||
<input class="input_element input-xlarge" type="text" name="form_function" id="form_function" value="{{ app["authentication"].getUser().getJob() }}" />
|
||||
<p class="form_alert help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,7 +121,7 @@
|
||||
<div class="control-group">
|
||||
<label class="form_label control-label" for="form_activity"><strong>{{ "admin::compte-utilisateur activite" | trans }}</strong></label>
|
||||
<div class="controls">
|
||||
<input class="input_element input-xlarge" type="text" name="form_activity" id="form_activity" value="{{ app["authentication"].getUser().getJob() }}" />
|
||||
<input class="input_element input-xlarge" type="text" name="form_activity" id="form_activity" value="{{ app["authentication"].getUser().getActivity() }}" />
|
||||
<p class="form_alert help-block"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -27,3 +27,17 @@
|
||||
|
||||
{# bootstrap admin field backbone application #}
|
||||
<script type="text/javascript" src="{{ path('minifier', { 'f' : '/scripts/apps/admin/fields/main.js' }) }}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('#admin-field-app').on('change', '#tbranch', function () {
|
||||
if ($(this).val() === '') {
|
||||
$('#generate_cterms').prop('checked', false);
|
||||
$('.generate-cterms').addClass('hidden');
|
||||
} else {
|
||||
$('.generate-cterms').removeClass('hidden');
|
||||
}
|
||||
return false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
@@ -238,14 +238,12 @@
|
||||
<label for="aggregable">{% trans %}Aggregation{% endtrans %}</label>
|
||||
</td>
|
||||
<td>
|
||||
<select id="aggregable">
|
||||
<option <%= field['aggregable'] == "0" ? 'selected' : '' %> value='0'>{% trans %}Not aggregated{% endtrans %}</option>
|
||||
<option <%= field['aggregable'] == "10" ? 'selected' : '' %> value='10'>10 values</option>
|
||||
<option <%= field['aggregable'] == "20" ? 'selected' : '' %> value='20'>20 values</option>
|
||||
<option <%= field['aggregable'] == "50" ? 'selected' : '' %> value='50'>50 values</option>
|
||||
<option <%= field['aggregable'] == "100" ? 'selected' : '' %> value='100'>100 values</option>
|
||||
<option <%= field['aggregable'] == "-1" ? 'selected' : '' %> value='-1'>{% trans %}All values{% endtrans %}</option>
|
||||
</select>
|
||||
<%= field['aggregable'] == "0" ? '{% trans %}Not aggregated{% endtrans %}' : '' %>
|
||||
<%= field['aggregable'] == "10" ? '10 values' : '' %>
|
||||
<%= field['aggregable'] == "20" ? '20 values' : '' %>
|
||||
<%= field['aggregable'] == "50" ? '50 values' : '' %>
|
||||
<%= field['aggregable'] == "100" ? '100 values' : '' %>
|
||||
<%= field['aggregable'] == "-1" ? 'All values' : '' %>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -261,11 +259,14 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="tbranch">{% trans %}Thesaurus branch{% endtrans %}</label></td>
|
||||
<td><input id="tbranch" type="text" value="<%= field.tbranch %>"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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="tbranch" type="text" value="<%= field.tbranch %>"/>
|
||||
<div style="display: inline-block;" <%= (field.tbranch == "") ? "class='generate-cterms hidden'" : "class='generate-cterms'" %> >
|
||||
<label for="generate_cterms" class="checkbox">
|
||||
<input id="generate_cterms" type="checkbox" <%= field.generate_cterms ? "checked='checked'" : "" %> />
|
||||
{% trans %}Generate-cterms{% endtrans %}</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@@ -1,12 +1,37 @@
|
||||
<div class="general-aggregation-layout">
|
||||
<button type="submit" id="elasticsearch_settings_save_facets" name="elasticsearch_settings[save]"
|
||||
class="btn btn-primary">{{ 'Save' | trans }}</button>
|
||||
<div id="basket-filter" class="facet-filter unstyled" style="float: right; padding-top: 27px;">
|
||||
{#<span class="filter-title">{{ 'See' | trans }} : </span>#}
|
||||
<span class="filter-item">
|
||||
<label id="aggregated-list" class="checkbox inline" for="basketFilter">
|
||||
<input type="checkbox" class="checkbox " value="aggregated" checked
|
||||
style="margin-top: 1px">
|
||||
{{ 'Aggregated' | trans }}
|
||||
</label>
|
||||
</span>
|
||||
<span class="filter-item" style="margin-left: 10px">
|
||||
<label id="not-aggregated-list" class="checkbox inline" for="basketFilter">
|
||||
<input type="checkbox" class="checkbox " value="not-aggregated" checked
|
||||
style="margin-top: 1px">
|
||||
{{ 'Not aggregated' | trans }}
|
||||
</label>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
<ul class="unstyled aggregation-collection">
|
||||
{% for formdata in form %}
|
||||
{% set attr = formdata.vars['attr']|join(',') %}
|
||||
{% set label = formdata.vars['label']|join(',') %}
|
||||
{% if attr == 'aggregate' %}
|
||||
<li>
|
||||
<li id="{{ label }}" class="field-row {% if label starts with '#_' %}lightblue{% endif %}">
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td class="handle">
|
||||
<i class="fa fa-arrows" aria-hidden="true"></i>
|
||||
</td>
|
||||
<td>
|
||||
{{ form_label(formdata, null, {
|
||||
'label_attr': {'class': 'label-aggregation'}
|
||||
@@ -22,6 +47,39 @@
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<button type="submit" id="elasticsearch_settings_save" name="elasticsearch_settings[save]"
|
||||
class="btn btn-primary">{{ 'Save' | trans }}</button>
|
||||
<input type="hidden" id="listValues" name="facet_list_values"/>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
/*Add a sort for the list*/
|
||||
function filterFacet() {
|
||||
$.each($(".aggregate option:selected"), function () {
|
||||
if ($(this).val() == 0) {
|
||||
$(this).closest('.field-row').addClass('not-aggregated')
|
||||
}
|
||||
else {
|
||||
$(this).closest('.field-row').addClass('aggregated')
|
||||
}
|
||||
});
|
||||
$('#aggregated-list input').click(function () {
|
||||
$('.aggregated').toggleClass('hidden');
|
||||
});
|
||||
$('#not-aggregated-list input').click(function () {
|
||||
$('.not-aggregated').toggleClass('hidden');
|
||||
});
|
||||
}
|
||||
/*Get the order of new list*/
|
||||
var sortEventHandler = function (event, ui) {
|
||||
$('#listValues').val(JSON.stringify($('form').serializeArray()));
|
||||
};
|
||||
$(document).ready(function () {
|
||||
$('.lightblue .label-aggregation').css('color','mediumblue');
|
||||
$('.aggregation-collection').sortable({
|
||||
handle: ".handle",
|
||||
stop: sortEventHandler
|
||||
});
|
||||
// sortEventHandler(null, null); // enforce build list
|
||||
filterFacet();
|
||||
$("#elasticsearch_settings_save_facets").click(function(){sortEventHandler(null, null);});
|
||||
});
|
||||
</script>
|
@@ -186,8 +186,8 @@
|
||||
<li class="menu-bar-item">
|
||||
<a href="#">
|
||||
<img src="/assets/common/images/icons/menu-help.png"/>
|
||||
<span style="" class="infoDialog"
|
||||
infos="<div><span style='font-size:18px;'>PHRASEANET</span> {{ app['phraseanet.version'].getName() }} (V{{ app['phraseanet.version'].getNumber() }})</div><div></div><br/><div><a href='http://www.gnu.org/licenses/gpl.html' target='_blank'><img src='http://www.gnu.org/graphics/gplv3-88x31.png' style='vertical-align:middle;'/><span>License GNU GPL v3</span></a></div><br/><div><a href='http://www.phraseanet.com/' target='_blank'> © Copyright Alchemy 2005-{{ "now"|date("Y") }}</a><p style='margin-top: 10px' ><a href='../../gitlog.txt' target='_blank'>gitlog</a></p></div>">{{ 'phraseanet:: a propos' | trans }}</span>
|
||||
<span class="context-menu-item-inner infoDialog"
|
||||
infos="<div class='phraseanet_about'><div class='phraseanet_about_top'><span class='phraseanet_logo'></span><div class='phraseanet_version'> {{ app['phraseanet.version'].getName() }} (V{{ app['phraseanet.version'].getNumber() }}) <a href='../../gitlog.txt' target='_blank'>gitlog</a></div></div><div class='phraseanet_about_bottom'><div class='phraseanet_gpl'><a href='http://www.gnu.org/licenses/gpl.html' target='_blank'><img src='/assets/common/images/GPLv3_Logo.png' width='380' /><span>License GNU GPL v3</span></a></div><p class='phraseanet_copyright'><a href='http://www.phraseanet.com/' target='_blank'> © Copyright Alchemy 2005-{{ "now"|date("Y") }}</a></p></div></div>">{{ 'phraseanet:: a propos' | trans }}</span>
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
@@ -252,7 +252,7 @@
|
||||
{% endif %}
|
||||
<div title="" class="context-menu-item menu3-custom-item">
|
||||
<div style="" class="context-menu-item-inner infoDialog"
|
||||
infos="<div><span style='font-size:18px;'>PHRASEANET</span> {{ app['phraseanet.version'].getName() }} (V{{ app['phraseanet.version'].getNumber() }})</div><div></div><br/><div><a href='http://www.gnu.org/licenses/gpl.html' target='_blank'><img src='http://www.gnu.org/graphics/gplv3-88x31.png' style='vertical-align:middle;'/><span>License GNU GPL v3</span></a></div><br/><div><a href='http://www.phraseanet.com/' target='_blank'> © Copyright Alchemy 2005-{{ "now"|date("Y") }}</a><p style='margin-top: 10px' ><a href='../../gitlog.txt' target='_blank'>gitlog</a></p></div>">{{ 'phraseanet:: a propos' | trans }}</div>
|
||||
infos="<div class='phraseanet_about'><div class='phraseanet_about_top'><span class='phraseanet_logo'></span><div class='phraseanet_version'> {{ app['phraseanet.version'].getName() }} (V{{ app['phraseanet.version'].getNumber() }}) <a href='../../gitlog.txt' target='_blank'>gitlog</a></div></div><div class='phraseanet_about_bottom'><div class='phraseanet_gpl'><a href='http://www.gnu.org/licenses/gpl.html' target='_blank'><img src='/assets/common/images/GPLv3_Logo.png' width='380' /><span>License GNU GPL v3</span></a></div><p class='phraseanet_copyright'><a href='http://www.phraseanet.com/' target='_blank'> © Copyright Alchemy 2005-{{ "now"|date("Y") }}</a></p></div></div>">{{ 'phraseanet:: a propos' | trans }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
|
@@ -45,7 +45,7 @@
|
||||
{% endmacro %}
|
||||
|
||||
{% block content_account %}
|
||||
<form id="form_create" action="{{ path("submit_developers_application") }}" method="POST" class="form-horizontal">
|
||||
<form id="form_create" action="{{ path("submit_developers_application") }}" method="POST" class="form-horizontal" style="padding: 20px; background: #757575;">
|
||||
{% if form is none %}
|
||||
{% set name, description, website, callback = "", "", "", "" %}
|
||||
{% set app_type = "web" %}
|
||||
@@ -74,7 +74,7 @@
|
||||
<div class="control-group">
|
||||
<label for="website" class="control-label"><b>{{ "Site web" | trans }}</b></label>
|
||||
<div class="controls">
|
||||
<select name="scheme-website" class="input-mini">
|
||||
<select name="scheme-website" class="input-mini" style="min-height: 40px;">
|
||||
<option value="http://">http://</option>
|
||||
<option value="https://">https://</option>
|
||||
</select>
|
||||
@@ -101,7 +101,7 @@
|
||||
<div class="control-group callback-control-group">
|
||||
<label for="callback" class="control-label"><b>{{ "URL de callback" | trans }}</b></label>
|
||||
<div class="controls">
|
||||
<select name="scheme-callback" class="input-mini">
|
||||
<select name="scheme-callback" class="input-mini" style="min-height: 40px;">
|
||||
<option value="http://">http://</option>
|
||||
<option value="https://">https://</option>
|
||||
</select>
|
||||
@@ -110,14 +110,18 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="form-actions">
|
||||
<button class="btn btn-info" type="submit">
|
||||
{{ "boutton::valider" | trans }}
|
||||
</button>
|
||||
|
||||
<a class="btn" href="{{ path("developers_applications") }}">
|
||||
<div class="control-group">
|
||||
<div class="col-md-6 controls" style="margin-right: 25px; float: left">
|
||||
<a class="btn btn-warning" href="{{ path("developers_applications") }}">
|
||||
{{ "boutton::retour" | trans }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-md-6" style="width: 50%; float: left">
|
||||
<button class="btn btn-info no-margin" type="submit" style="margin: 0;width: auto;min-width: 200px">
|
||||
{{ "boutton::valider" | trans }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
@@ -66,4 +66,25 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$('a.delete-app').bind('click', function (e) {
|
||||
e.preventDefault();
|
||||
var $this = $(this);
|
||||
var li = $this.closest('li');
|
||||
|
||||
$.ajax({
|
||||
type: 'DELETE',
|
||||
url: $this.attr('href'),
|
||||
dataType: 'json',
|
||||
data: {},
|
||||
success: function success(data) {
|
||||
if (data.success) {
|
||||
li.find('.modal').modal('hide');
|
||||
li.remove();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
@@ -20,7 +20,7 @@
|
||||
<table id="main_wrapper" cellspacing="0" cellpadding="0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="title">
|
||||
<th class="title" id="feed_list">
|
||||
<h1>{{ 'Validations' | trans }}</h1>
|
||||
</th>
|
||||
<th>
|
||||
@@ -29,10 +29,12 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for basket in baskets_collection %}
|
||||
{% for basket in baskets_collection | sort | reverse%}
|
||||
{% if basket.getValidation() %}
|
||||
{% set basket_length = basket.getElements().count() %}
|
||||
<tr>
|
||||
{% set counter = ( counter | default(0) ) + 1 %}
|
||||
|
||||
<tr class="{% if counter >=4 %}other_feed hidden{% endif %}">
|
||||
<td colspan="2">
|
||||
<div class="basket_wrapper ui-corner-all clickable">
|
||||
<table cellspacing="0" cellpadding="0" border="0">
|
||||
@@ -84,20 +86,26 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% if counter == 3 %}<tr><td colspan="2" style="text-align: center"><a href="#see_more_feed" id="see_more_feed" class="see_more_feed btn btn-info">{{ 'lightbox::See_more_feedback' | trans }}</a></td></tr>{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr><td colspan="2" style="text-align: center"><a href="#feed_list" id="see_less_feed" class="see_more_feed hidden btn btn-success">{{ 'lightbox::See_less_feedback' | trans }}</a></td></tr>
|
||||
<tr>
|
||||
<th class="title">
|
||||
<th class="title" id="panier_list">
|
||||
<h1>{{ 'Paniers' | trans }}</h1>
|
||||
</th>
|
||||
<th>
|
||||
<i>{{ 'Voici vos paniers' | trans }}</i>
|
||||
</th>
|
||||
</tr>
|
||||
{% for basket in baskets_collection %}
|
||||
{% for basket in baskets_collection | sort | reverse%}
|
||||
{% if basket.getValidation is null %}
|
||||
{% set basket_length = basket.getElements().count() %}
|
||||
<tr>
|
||||
{% set counter = ( counter | default(0) ) + 1 %}
|
||||
{% set counter_length = baskets_collection.length() %}
|
||||
|
||||
<tr class="{% if counter >=4 %}other_basket hidden{% endif %}">
|
||||
<td colspan="2">
|
||||
<div class="basket_wrapper ui-corner-all clickable">
|
||||
<table cellspacing="0" cellpadding="0" border="0">
|
||||
@@ -140,9 +148,14 @@
|
||||
<input type="hidden" name="ssel_id" value="{{ basket.getId() }}"/>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
{% if counter == 3 %}<tr><td colspan="2" style="text-align: center"><a href="#see_more_basket" id="see_more_basket" class="see_more_basket btn btn-info">{{ 'lightbox::see_more_basket' | trans }}</a></td></tr>{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<tr><td colspan="2" style="text-align: center"><a href="#panier_list" id="see_less_basket" class="see_more_basket hidden btn btn-success">{{ 'lightbox::see_less_basket' | trans }}</a></td></tr>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@@ -126,6 +126,7 @@
|
||||
|
||||
{% set actionable = recordsRequest|length %}
|
||||
{% set not_actionable = recordsRequest.received|length - actionable %}
|
||||
{% set editing_top_box_height = app['settings'].getUserSetting(app.getAuthenticatedUser(), 'editing_top_box') %}
|
||||
|
||||
<div id="EDIT_ALL">
|
||||
|
||||
@@ -135,8 +136,7 @@
|
||||
<input style="font-size:2px; width:5px;" type="text" id="editFakefocus" />
|
||||
</form>
|
||||
</div>
|
||||
<div id="EDIT_TOP" style="height:{{app['settings'].getUserSetting(app.getAuthenticatedUser(), 'editing_top_box')
|
||||
}}%;">
|
||||
<div id="EDIT_TOP" style="height:{{editing_top_box_height}}%; min-height: {{ editing_top_box_height }}">
|
||||
<div id="EDIT_MENU">
|
||||
<div id="EDIT_ZOOMSLIDER" >
|
||||
</div>
|
||||
|
@@ -183,6 +183,55 @@
|
||||
</div>
|
||||
{% if GV_thesaurus %}
|
||||
<div id="proposals" class="PNB thesaurus-from-facets-action">
|
||||
<div class="filter-facet-setting look_box_settings">
|
||||
<div id="accordion">
|
||||
<div class="card">
|
||||
<div class="card-header" id="headingOne">
|
||||
<h5 class="mb-0" style="margin-left: 10px">
|
||||
<button class="btn btn-facet-option collapsed" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
||||
{{ 'prod:workzone:facetstab:search_and_facets_sort_options' | trans }} <span class="icomoon"></span>
|
||||
</button>
|
||||
</h5>
|
||||
</div>
|
||||
<div id="collapseOne" class="collapse show" aria-labelledby="headingOne" data-parent="#accordion">
|
||||
<div class="card-body">
|
||||
<div class="left-facet-filter facet-filter">
|
||||
<h4>{{ 'index::advance_search: facet-order' | trans }}</h4>
|
||||
<form class="form-inline">
|
||||
{% set order_facet = app['settings'].getUserSetting(app.getAuthenticatedUser(), 'order_facet') %}
|
||||
<label class="select" for="orderFacet">
|
||||
<select class="preferences-facet-order" name="orderFacet" style="margin-left: 5px">
|
||||
<option {% if order_facet == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_BCT') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_BCT') }}">{{ 'index::advance_search: facet-tech-order' | trans }}</option>
|
||||
<option {% if order_facet == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') }}">{{ 'Alphabetic asc' | trans }}</option>
|
||||
<option {% if order_facet == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_DESC') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_DESC') }}">{{ 'Alphabetic desc' | trans }}</option>
|
||||
</select>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
<div class="right-facet-filter facet-filter">
|
||||
<h4>{{ 'index::advance_search: facet-values-order' | trans }}</h4>
|
||||
<form class="form-inline">
|
||||
{% set facet_values_order = app['settings'].getUserSetting(app.getAuthenticatedUser(), 'facet_values_order') %}
|
||||
<label class="select" for="facetValuesOrder">
|
||||
<select class="preferences-facet-values-order" name="facetValuesOrder">
|
||||
<option {% if facet_values_order == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_HITS') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_HITS') }}">{{ 'index::advance_search: order-by-hits' | trans }}</option>
|
||||
<option {% if facet_values_order == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_HITS_ASC') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_HITS_ASC') }}">{{ 'index::advance_search: order-by-hits-asc' | trans }}</option>
|
||||
<option {% if facet_values_order == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') }}">{{ 'Alphabetic asc' | trans }}</option>
|
||||
</select>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button id="facets-back-btn" style="display:none;">back</button>
|
||||
</div>
|
||||
{% include 'prod/tab_thesaurus.html.twig' with {has_access_to_module: app.getAclForUser(app.getAuthenticatedUser()).has_access_to_module('thesaurus')} %}
|
||||
@@ -326,6 +375,9 @@
|
||||
</div>
|
||||
<div class="pull-right">
|
||||
<input class="btn btn_lightgrey reset_button search-reset-action" style="display: none;" type="button" value="{{ 'Re-initialiser' | trans }}" />
|
||||
|
||||
<span class="btn btn-info btn-lg reload-search hidden " id="reload-search">{{ 'help::help-search: relaunch search without filter' | trans }}</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -811,30 +863,6 @@
|
||||
</div>
|
||||
<div class="box">
|
||||
<h1>{{ 'index::advance_search: facet' | trans }}</h1>
|
||||
<h1>{{ 'index::advance_search: facet-order' | trans }}</h1>
|
||||
<form class="form-inline">
|
||||
{% set order_facet = app['settings'].getUserSetting(app.getAuthenticatedUser(), 'order_facet') %}
|
||||
<label class="select" for="orderFacet">
|
||||
<select class="preferences-facet-order" name="orderFacet">
|
||||
<option {% if order_facet == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_BCT') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_BCT') }}">{{ 'index::advance_search: facet-tech-order' | trans }}</option>
|
||||
<option {% if order_facet == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') }}">{{ 'Alphabetic asc' | trans }}</option>
|
||||
</select>
|
||||
</label>
|
||||
</form>
|
||||
<h1>{{ 'index::advance_search: facet-values-order' | trans }}</h1>
|
||||
<form class="form-inline">
|
||||
{% set facet_values_order = app['settings'].getUserSetting(app.getAuthenticatedUser(), 'facet_values_order') %}
|
||||
<label class="select" for="facetValuesOrder">
|
||||
<select class="preferences-facet-values-order" name="facetValuesOrder">
|
||||
<option {% if facet_values_order == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_HITS') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_BY_HITS') }}">{{ 'index::advance_search: order-by-hits' | trans }}</option>
|
||||
<option {% if facet_values_order == constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') %} selected="selected" {% endif %}
|
||||
value="{{ constant('Alchemy\\Phrasea\\Core\\Configuration\\DisplaySettingService::ORDER_ALPHA_ASC') }}">{{ 'Alphabetic asc' | trans }}</option>
|
||||
</select>
|
||||
</label>
|
||||
</form>
|
||||
{% set facetFilter = app['settings'].getUserSetting(app.getAuthenticatedUser(), 'facet') %}
|
||||
<label class="checkbox inline" for="ADVSRCH_FILTER_FACET" style="margin-bottom: 1em">
|
||||
<input id="ADVSRCH_FILTER_FACET" type="checkbox" name="filter_facet" {% if facetFilter == 'true' %}checked="checked"{% endif %}>
|
||||
|
@@ -30,63 +30,11 @@
|
||||
<li><p>{{ 'help::help-section-bullet: search-in-a-specific-field' | trans }}</p></li>
|
||||
</ul>
|
||||
</div>
|
||||
{#<h5>{{ 'La recherche s\'effectue grâce à la boîte de dialogue qui se trouve en haut à gauche de l\'écran.' | trans }}#}
|
||||
{#{{ 'Sachez que vous pouvez utiliser les opérateurs ou caractères spéciaux suivants :' | trans }}</h5>#}
|
||||
{#<h5 style="border:#CCCCCC 2px solid">{{ '* , ? , ET , OU , SAUF , DANS , DERNIERS , TOUT (ou AND , OR , EXCEPT , LAST , ALL)' | trans }}</h5>#}
|
||||
|
||||
{#<h5>{{ 'Caractères de troncature' | trans }}</h5>#}
|
||||
|
||||
{#<table>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky">{{ 'auto*' | trans }}</kbd></td>#}
|
||||
{#<td valign="top"> {{ 'retourne "automobile", "automate", "autoroute", ...' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky">{{ 'dé?it' | trans }}</kbd></td>#}
|
||||
{#<td valign="top"> {{ 'retourne "délit", "débit", ...' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#</table>#}
|
||||
|
||||
{#<h5>{{ 'Visualiser tous les enregistrements / les derniers enregistrements' | trans }}</h5>#}
|
||||
{#<table>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky"><b>{{ 'TOUT' | trans }}</b></kbd></td>#}
|
||||
{#<td valign="top">{{ 'retourne tous les enregistrements des collections selectionnees' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky"><b>{{ 'LAST 20' | trans }}</b></kbd></td>#}
|
||||
{#<td valign="top">{{ 'retourne les 20 derniers enregistrements archives dans les collections selectionnees' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#</table>#}
|
||||
|
||||
{#<h5>{{ 'Recherche multicritères' | trans }}</h5>#}
|
||||
{#{{ 'Vous pouvez affiner votre recherche avec les opérateurs : ET, OU, SAUF ou DANS' | trans }}<br>#}
|
||||
{#<table>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky">{{ 'sport' | trans }} <b>ET</b> {{ 'automobile' | trans }}</kbd></td>#}
|
||||
{#<td valign="top">{{ 'retourne les documents comprenant les deux mots.' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky">{{ 'journal OU jt' | trans }}</kbd></td>#}
|
||||
{#<td valign="top">{{ 'retourne les documents comprenant un mot et/ou l\'autre.' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky">{{ 'cannes SAUF festival' | trans }}</kbd></td>#}
|
||||
{#<td valign="top">{{ 'retourne les documents comprenant cannes sans le mot festival.' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#<tr>#}
|
||||
{#<td valign="top"><kbd class="ky">{{ 'thalassa DANS titre' | trans }}</kbd></td>#}
|
||||
{#<td valign="top">{{ 'retourne les documents où le terme est au moins présent dans le titre, en évitant par exemple celles où le terme est uniquement cité dans la légende.' | trans }}</td>#}
|
||||
{#</tr>#}
|
||||
{#</table>#}
|
||||
|
||||
{#<center>#}
|
||||
{#<h3 style="background-color:#CCCCCC; color:#000000">{{ 'Attention' | trans }}</h3>#}
|
||||
{#<h4> {{ 'pour chercher une phrase contenant un des mots-clé ci-dessus, utilisez les guillemets :' | trans }}</h4>#}
|
||||
{#<kbd class='tx'><i>"</i>{{ 'C dans l\'air' | trans }}<i>"</i></kbd>#}
|
||||
{#, <kbd class='tx'><i>"</i>{{ 'Et Dieu créa la femme' | trans }}<i>"</i></kbd>#}
|
||||
{#, <kbd class='tx'><i>"</i>{{ 'bijou en or' | trans }}<i>"</i></kbd>#}
|
||||
{#, <kbd class='tx'><i>"</i>{{ 'tout le sport' | trans }}<i>"</i></kbd>#}
|
||||
{#</center>#}
|
||||
<br>
|
||||
<p class="text-center">{{ 'help::help-search: OR' | trans }}</p>
|
||||
<br>
|
||||
<p class="text-center">
|
||||
<span class="btn btn-info btn-lg trigger-reload-search" onclick="jQuery('.reload-search').trigger('click');">{{ 'help::help-search: relaunch search without filter' | trans }}</span>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
@@ -356,15 +356,20 @@
|
||||
var elements = [];
|
||||
var nbElement = 0;
|
||||
|
||||
if (nbProposals >= 1) {
|
||||
|
||||
|
||||
if (nbProposals > 1) {
|
||||
elements = $(".selected", container);
|
||||
nbElement = elements.length;
|
||||
} else if (nbProposals == 1) {
|
||||
elements = $(".records-subititution > div", container);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nbElement === 0) {
|
||||
if (nbElement === 0 && nbProposals > 1) {
|
||||
alert(language.selectOneRecord);
|
||||
|
||||
return false;
|
||||
} else if (nbElement > 1) {
|
||||
alert(language.onlyOneRecord);
|
||||
|
@@ -20,7 +20,6 @@ class StructureTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEmpty($structure->getAllFields());
|
||||
$this->assertEmpty($structure->getUnrestrictedFields());
|
||||
$this->assertEmpty($structure->getPrivateFields());
|
||||
$this->assertEmpty($structure->getFacetFields());
|
||||
$this->assertEmpty($structure->getThesaurusEnabledFields());
|
||||
$this->assertEmpty($structure->getDateFields());
|
||||
}
|
||||
@@ -95,19 +94,6 @@ class StructureTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertNotContains($unrestricted_field, $private_fields);
|
||||
}
|
||||
|
||||
public function testGetFacetFields()
|
||||
{
|
||||
$facet = new Field('foo', FieldMapping::TYPE_STRING, ['facet' => Field::FACET_NO_LIMIT]);
|
||||
$not_facet = new Field('bar', FieldMapping::TYPE_STRING, ['facet' => Field::FACET_DISABLED]);
|
||||
$structure = new Structure();
|
||||
$structure->add($facet);
|
||||
$this->assertContains($facet, $structure->getFacetFields());
|
||||
$structure->add($not_facet);
|
||||
$facet_fields = $structure->getFacetFields();
|
||||
$this->assertContains($facet, $facet_fields);
|
||||
$this->assertNotContains($not_facet, $facet_fields);
|
||||
}
|
||||
|
||||
public function testGetDateFields()
|
||||
{
|
||||
$string = new Field('foo', FieldMapping::TYPE_STRING);
|
||||
|
@@ -7577,10 +7577,10 @@ phraseanet-common@^0.4.5-d:
|
||||
js-cookie "^2.1.0"
|
||||
pym.js "^1.3.1"
|
||||
|
||||
phraseanet-production-client@0.34.116-d:
|
||||
version "0.34.116-d"
|
||||
resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.116-d.tgz#74d2d3e14e68a66f3a64aeb1f857bad04a4491f0"
|
||||
integrity sha512-x0IB2zQu0L+jQ/TXpHae8CPqCHsv9yanp254hAcnuwEQ88cig4oNU8JLKxPvwt0d3WUQ5J2S0BdshdbfpFxBbw==
|
||||
phraseanet-production-client@0.34.139-d:
|
||||
version "0.34.139-d"
|
||||
resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.139-d.tgz#27edf283275c427ba226ff8b6c9461511dd6c827"
|
||||
integrity sha512-8lOeLbUpa2qBi08d4Tr3FbtKf4TmSvTWhPtwCm7bZxls14TMXnYl7JRFZoYEMGEB1n1tbYozrl/Oz4qV7Pn6Sg==
|
||||
dependencies:
|
||||
"@mapbox/mapbox-gl-language" "^0.9.2"
|
||||
"@turf/turf" "^5.1.6"
|
||||
|
Reference in New Issue
Block a user