Merge branch 'master' of https://github.com/alchemy-fr/Phraseanet into PHRAS-2276-port-template-escape

This commit is contained in:
aina-esokia
2019-03-29 17:09:37 +04:00
143 changed files with 3313 additions and 10651 deletions

View File

@@ -37,7 +37,8 @@ jobs:
- run: git clone https://github.com/alanxz/rabbitmq-c - run: git clone https://github.com/alanxz/rabbitmq-c
- run: cd rabbitmq-c && git checkout 2ca1774489328cde71195f5fa95e17cf3a80cb8a - run: cd rabbitmq-c && git checkout 2ca1774489328cde71195f5fa95e17cf3a80cb8a
- run: cd rabbitmq-c && git submodule init && git submodule update && autoreconf -i && ./configure && make && sudo make install - run: cd rabbitmq-c && git submodule init && git submodule update && autoreconf -i && ./configure && make && sudo make install
- run: pecl channel-update pear.php.net # disabled because pear.php.net is down cause of security failure
#- run: pecl channel-update pear.php.net
- run: yes '' | pecl install amqp-1.9.3 - run: yes '' | pecl install amqp-1.9.3
- run: yes '' | pecl install imagick - run: yes '' | pecl install imagick
- run: sudo apt-get install libzmq-dev - run: sudo apt-get install libzmq-dev

44
AUTHORS
View File

@@ -1,28 +1,40 @@
** Phraseanet is written and maintained by the Phraseanet Developer Team ** ** Phraseanet is written and maintained by the Phraseanet Developer Team **
Benoît Burnichon - Jean-Yves Gaulier
Jean-Yves Gaulier - Milos M
Andrey Kalinovsky - Mike NG
Nicolas Legoff - Xavier Rousset
Romain Neutron - Aina Sitraka
- Filip Vilic
** Proudly Powered by Alchemy ** ** Proudly Powered by Alchemy **
Nicolas Amendola - Aurélie Bachelet
Nathanaël Attar - Laetitia Bianchi
Aurélie Bachelet - Anthony Cabot
Anthony Cabot - Moctar Diouf
Moctar Diouf - Jennifer Guérin
Jennifer Guérin - Félix Noir
Nicolas Honoré - Nicolas Maillat
Nicolas Maillat - Guillaume Maubert
Guillaume Maubert
Jonathan Schneider
** They gave some love to Phraseanet ** ** They gave some love to Phraseanet **
Ysoline Gresille - Nicolas Amendola
- Nathanaël Attar
- Florian Blouet
- Benoît Burnichon
- Thibaud Fabre
- Ysoline Gresille
- Nicolas Honoré
- Andrey Kalinovsky
- Nicolas Legoff
- Romain Neutron
- Jonathan Schneider
Phraseanet c/o Alchemy Phraseanet c/o Alchemy
30 Place Saint Georges 30 Place Saint Georges
75009 Paris - France 75009 Paris - France

View File

@@ -1,3 +1,7 @@
#version 4.0
- Krzysztof Szulski Security
- Ideepix Docker Deploiement
#version 3.7 #version 3.7
- Pieter Demonie (Dutch localization) - Pieter Demonie (Dutch localization)

View File

@@ -5,7 +5,7 @@ install:
make install_assets make install_assets
install_composer: install_composer:
composer install composer install --ignore-platform-reqs
install_asset_dependencies: install_asset_dependencies:
yarn upgrade yarn upgrade

7
Vagrantfile vendored
View File

@@ -35,7 +35,7 @@ else if which('ifconfig')
end end
$php = [ "5.6", "7.0", "7.1", "7.2" ] $php = [ "5.6", "7.0", "7.1", "7.2" ]
$phpVersion = ENV['phpversion'] ? ENV['phpversion'] : "5.6"; $phpVersion = ENV['phpversion'] ? ENV['phpversion'] : "7.0";
unless Vagrant.has_plugin?('vagrant-hostmanager') unless Vagrant.has_plugin?('vagrant-hostmanager')
raise "vagrant-hostmanager is not installed! Please run\n vagrant plugin install vagrant-hostmanager\n\n" raise "vagrant-hostmanager is not installed! Please run\n vagrant plugin install vagrant-hostmanager\n\n"
@@ -70,6 +70,9 @@ def config_net(config)
vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/vagrant", "1"] vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/vagrant", "1"]
end end
end end
config.vm.network :public_network, bridge:"en0: Ethernet"
config.hostmanager.ip_resolver = proc do |vm, resolving_vm| config.hostmanager.ip_resolver = proc do |vm, resolving_vm|
if vm.id if vm.id
if $env == "mac" || $env == "linux" if $env == "mac" || $env == "linux"
@@ -163,4 +166,4 @@ Vagrant.configure("2") do |config|
config.vm.synced_folder "./", "/vagrant" config.vm.synced_folder "./", "/vagrant"
end end
end end

View File

@@ -50,7 +50,7 @@
"alchemy/embed-bundle": "^0.3.4", "alchemy/embed-bundle": "^0.3.4",
"alchemy/geonames-api-consumer": "~0.1.0", "alchemy/geonames-api-consumer": "~0.1.0",
"alchemy/mediavorus": "^0.4.4", "alchemy/mediavorus": "^0.4.4",
"alchemy/oauth2php": "1.0.0", "alchemy/oauth2php": "1.1.0",
"alchemy/phlickr": "0.2.9", "alchemy/phlickr": "0.2.9",
"alchemy/phpexiftool": "^0.7.0", "alchemy/phpexiftool": "^0.7.0",
"alchemy/rest-bundle": "^0.0.5", "alchemy/rest-bundle": "^0.0.5",

75
composer.lock generated
View File

@@ -1,10 +1,10 @@
{ {
"_readme": [ "_readme": [
"This file locks the dependencies of your project to a known state", "This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "253990d4c81f9ae5f78c6c1221d6cf29", "content-hash": "adf4074eb26ea80d414430d4f7b61311",
"packages": [ "packages": [
{ {
"name": "alchemy-fr/tcpdf-clone", "name": "alchemy-fr/tcpdf-clone",
@@ -131,16 +131,16 @@
}, },
{ {
"name": "alchemy/embed-bundle", "name": "alchemy/embed-bundle",
"version": "0.3.7", "version": "0.3.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/embed-bundle.git", "url": "https://github.com/alchemy-fr/embed-bundle.git",
"reference": "ce7408c7a47387eed3df2a743577d6e0e25f991f" "reference": "8a9699bc51e2b2997ccfd357bb2892f3702c33ef"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/ce7408c7a47387eed3df2a743577d6e0e25f991f", "url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/8a9699bc51e2b2997ccfd357bb2892f3702c33ef",
"reference": "ce7408c7a47387eed3df2a743577d6e0e25f991f", "reference": "8a9699bc51e2b2997ccfd357bb2892f3702c33ef",
"shasum": "" "shasum": ""
}, },
"require-dev": { "require-dev": {
@@ -178,10 +178,10 @@
], ],
"description": "Embed resources bundle", "description": "Embed resources bundle",
"support": { "support": {
"source": "https://github.com/alchemy-fr/embed-bundle/tree/0.3.7", "source": "https://github.com/alchemy-fr/embed-bundle/tree/0.3.8",
"issues": "https://github.com/alchemy-fr/embed-bundle/issues" "issues": "https://github.com/alchemy-fr/embed-bundle/issues"
}, },
"time": "2017-05-30T13:18:21+00:00" "time": "2019-01-11T10:35:41+00:00"
}, },
{ {
"name": "alchemy/geonames-api-consumer", "name": "alchemy/geonames-api-consumer",
@@ -275,16 +275,16 @@
}, },
{ {
"name": "alchemy/mediavorus", "name": "alchemy/mediavorus",
"version": "0.4.8", "version": "0.4.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/MediaVorus.git", "url": "https://github.com/alchemy-fr/MediaVorus.git",
"reference": "6a50c397211dfdf6da108ea1ebc7527c37419ab7" "reference": "1a96dc4142ff8474c11285cab9eab11df9683255"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/6a50c397211dfdf6da108ea1ebc7527c37419ab7", "url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/1a96dc4142ff8474c11285cab9eab11df9683255",
"reference": "6a50c397211dfdf6da108ea1ebc7527c37419ab7", "reference": "1a96dc4142ff8474c11285cab9eab11df9683255",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -333,20 +333,20 @@
"keywords": [ "keywords": [
"metadata" "metadata"
], ],
"time": "2018-05-03T14:17:10+00:00" "time": "2019-01-22T11:23:34+00:00"
}, },
{ {
"name": "alchemy/oauth2php", "name": "alchemy/oauth2php",
"version": "1.0.0", "version": "1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/oauth2-php.git", "url": "https://github.com/alchemy-fr/oauth2-php.git",
"reference": "cb4fcb73e30ab54e0fb85a65b4d57147f7a0df15" "reference": "801510972240555fa182813851efd96659d37a68"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/oauth2-php/zipball/cb4fcb73e30ab54e0fb85a65b4d57147f7a0df15", "url": "https://api.github.com/repos/alchemy-fr/oauth2-php/zipball/801510972240555fa182813851efd96659d37a68",
"reference": "cb4fcb73e30ab54e0fb85a65b4d57147f7a0df15", "reference": "801510972240555fa182813851efd96659d37a68",
"shasum": "" "shasum": ""
}, },
"type": "library", "type": "library",
@@ -356,7 +356,7 @@
] ]
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"time": "2013-07-01T09:46:59+00:00" "time": "2019-01-17T14:34:10+00:00"
}, },
{ {
"name": "alchemy/phlickr", "name": "alchemy/phlickr",
@@ -1898,12 +1898,12 @@
"version": "v2.5.6", "version": "v2.5.6",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/doctrine2.git", "url": "https://github.com/doctrine/orm.git",
"reference": "e6c434196c8ef058239aaa0724b4aadb0107940b" "reference": "e6c434196c8ef058239aaa0724b4aadb0107940b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/doctrine2/zipball/e6c434196c8ef058239aaa0724b4aadb0107940b", "url": "https://api.github.com/repos/doctrine/orm/zipball/e6c434196c8ef058239aaa0724b4aadb0107940b",
"reference": "e6c434196c8ef058239aaa0724b4aadb0107940b", "reference": "e6c434196c8ef058239aaa0724b4aadb0107940b",
"shasum": "" "shasum": ""
}, },
@@ -2304,12 +2304,12 @@
"version": "v2.2.1", "version": "v2.2.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/google/google-api-php-client.git", "url": "https://github.com/googleapis/google-api-php-client.git",
"reference": "b69b8ac4bf6501793c389d4e013a79d09c85c5f2" "reference": "b69b8ac4bf6501793c389d4e013a79d09c85c5f2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/google/google-api-php-client/zipball/b69b8ac4bf6501793c389d4e013a79d09c85c5f2", "url": "https://api.github.com/repos/googleapis/google-api-php-client/zipball/b69b8ac4bf6501793c389d4e013a79d09c85c5f2",
"reference": "b69b8ac4bf6501793c389d4e013a79d09c85c5f2", "reference": "b69b8ac4bf6501793c389d4e013a79d09c85c5f2",
"shasum": "" "shasum": ""
}, },
@@ -2363,12 +2363,12 @@
"version": "v0.36", "version": "v0.36",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/google/google-api-php-client-services.git", "url": "https://github.com/googleapis/google-api-php-client-services.git",
"reference": "2fd7d2876fbc0174faddba3241956a1393536159" "reference": "2fd7d2876fbc0174faddba3241956a1393536159"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/google/google-api-php-client-services/zipball/2fd7d2876fbc0174faddba3241956a1393536159", "url": "https://api.github.com/repos/googleapis/google-api-php-client-services/zipball/2fd7d2876fbc0174faddba3241956a1393536159",
"reference": "2fd7d2876fbc0174faddba3241956a1393536159", "reference": "2fd7d2876fbc0174faddba3241956a1393536159",
"shasum": "" "shasum": ""
}, },
@@ -2400,12 +2400,12 @@
"version": "v1.1.0", "version": "v1.1.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/google/google-auth-library-php.git", "url": "https://github.com/googleapis/google-auth-library-php.git",
"reference": "548d27d670f0236dc5258fa4cdde6e7b63464cfd" "reference": "548d27d670f0236dc5258fa4cdde6e7b63464cfd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/google/google-auth-library-php/zipball/548d27d670f0236dc5258fa4cdde6e7b63464cfd", "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/548d27d670f0236dc5258fa4cdde6e7b63464cfd",
"reference": "548d27d670f0236dc5258fa4cdde6e7b63464cfd", "reference": "548d27d670f0236dc5258fa4cdde6e7b63464cfd",
"shasum": "" "shasum": ""
}, },
@@ -4334,16 +4334,16 @@
}, },
{ {
"name": "media-alchemyst/media-alchemyst", "name": "media-alchemyst/media-alchemyst",
"version": "0.5.1", "version": "0.5.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/Media-Alchemyst.git", "url": "https://github.com/alchemy-fr/Media-Alchemyst.git",
"reference": "b82bb891640cb1ce5d5523235047c34c64194514" "reference": "5d2fe6dd95215804202ecf0466fd9cfaeedd0140"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/Media-Alchemyst/zipball/b82bb891640cb1ce5d5523235047c34c64194514", "url": "https://api.github.com/repos/alchemy-fr/Media-Alchemyst/zipball/5d2fe6dd95215804202ecf0466fd9cfaeedd0140",
"reference": "b82bb891640cb1ce5d5523235047c34c64194514", "reference": "5d2fe6dd95215804202ecf0466fd9cfaeedd0140",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -4404,7 +4404,7 @@
"video", "video",
"video processing" "video processing"
], ],
"time": "2016-03-16T13:11:52+00:00" "time": "2019-01-25T12:09:11+00:00"
}, },
{ {
"name": "monolog/monolog", "name": "monolog/monolog",
@@ -5766,17 +5766,6 @@
{ {
"name": "roave/security-advisories", "name": "roave/security-advisories",
"version": "dev-master", "version": "dev-master",
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "3db4b0df21d1f527304650e717c66af48981f1c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/3db4b0df21d1f527304650e717c66af48981f1c4",
"reference": "3db4b0df21d1f527304650e717c66af48981f1c4",
"shasum": ""
},
"conflict": { "conflict": {
"adodb/adodb-php": "<5.20.6", "adodb/adodb-php": "<5.20.6",
"amphp/artax": ">=2,<2.0.4|>0.7.1,<1.0.4", "amphp/artax": ">=2,<2.0.4|>0.7.1,<1.0.4",
@@ -6015,6 +6004,7 @@
"keywords": [ "keywords": [
"microframework" "microframework"
], ],
"abandoned": "symfony/flex",
"time": "2016-01-06T14:59:35+00:00" "time": "2016-01-06T14:59:35+00:00"
}, },
{ {
@@ -6060,6 +6050,7 @@
], ],
"description": "A WebProfiler for Silex", "description": "A WebProfiler for Silex",
"homepage": "http://silex.sensiolabs.org/", "homepage": "http://silex.sensiolabs.org/",
"abandoned": true,
"time": "2016-01-10T11:39:13+00:00" "time": "2016-01-10T11:39:13+00:00"
}, },
{ {

View File

@@ -7,6 +7,7 @@ main:
languages: [] languages: []
key: '' key: ''
api_require_ssl: true api_require_ssl: true
api_token_header: false
database: database:
host: 127.0.0.1 host: 127.0.0.1
port: 3306 port: 3306

View File

@@ -65,8 +65,6 @@ class RouteLoader
'/prod/upload/' => Providers\Prod\Upload::class, '/prod/upload/' => Providers\Prod\Upload::class,
'/prod/WorkZone' => Providers\Prod\WorkZone::class, '/prod/WorkZone' => Providers\Prod\WorkZone::class,
'/prod/' => Providers\Prod\Root::class, '/prod/' => Providers\Prod\Root::class,
'/report/activity' => Providers\Report\Activity::class,
'/report/informations' => Providers\Report\Information::class,
'/report/' => Providers\Report\Root::class, '/report/' => Providers\Report\Root::class,
'/session/' => Providers\Root\Session::class, '/session/' => Providers\Root\Session::class,
'/setup' => Providers\Setup::class, '/setup' => Providers\Setup::class,

View File

@@ -145,6 +145,7 @@ class SubdefsController extends Controller
$options[Audio::OPTION_AUDIOBITRATE] = $config["audio"]["definitions"][$preset][Audio::OPTION_AUDIOBITRATE]; $options[Audio::OPTION_AUDIOBITRATE] = $config["audio"]["definitions"][$preset][Audio::OPTION_AUDIOBITRATE];
$options[Audio::OPTION_AUDIOSAMPLERATE] = $config["audio"]["definitions"][$preset][Audio::OPTION_AUDIOSAMPLERATE]; $options[Audio::OPTION_AUDIOSAMPLERATE] = $config["audio"]["definitions"][$preset][Audio::OPTION_AUDIOSAMPLERATE];
$options[Audio::OPTION_ACODEC] = $config["audio"]["definitions"][$preset][Audio::OPTION_ACODEC]; $options[Audio::OPTION_ACODEC] = $config["audio"]["definitions"][$preset][Audio::OPTION_ACODEC];
$options[Audio::OPTION_AUDIOCHANNEL] = $config["audio"]["definitions"][$preset][Audio::OPTION_AUDIOCHANNEL];
foreach ($config["audio"]["definitions"][$preset][Subdef::OPTION_DEVICE] as $devices) { foreach ($config["audio"]["definitions"][$preset][Subdef::OPTION_DEVICE] as $devices) {
$options[Subdef::OPTION_DEVICE][] = $devices; $options[Subdef::OPTION_DEVICE][] = $devices;
} }
@@ -211,7 +212,7 @@ class SubdefsController extends Controller
{ {
$mapping = [ $mapping = [
Type::TYPE_IMAGE => [Subdef::TYPE_IMAGE, Subdef::TYPE_PDF], Type::TYPE_IMAGE => [Subdef::TYPE_IMAGE, Subdef::TYPE_PDF],
Type::TYPE_VIDEO => [Subdef::TYPE_IMAGE, Subdef::TYPE_VIDEO, Subdef::TYPE_ANIMATION], Type::TYPE_VIDEO => [Subdef::TYPE_IMAGE, Subdef::TYPE_VIDEO, Subdef::TYPE_ANIMATION, Subdef::TYPE_AUDIO],
Type::TYPE_AUDIO => [Subdef::TYPE_IMAGE, Subdef::TYPE_AUDIO], Type::TYPE_AUDIO => [Subdef::TYPE_IMAGE, Subdef::TYPE_AUDIO],
Type::TYPE_DOCUMENT => [Subdef::TYPE_IMAGE, Subdef::TYPE_FLEXPAPER, Subdef::TYPE_PDF], Type::TYPE_DOCUMENT => [Subdef::TYPE_IMAGE, Subdef::TYPE_FLEXPAPER, Subdef::TYPE_PDF],
Type::TYPE_FLASH => [Subdef::TYPE_IMAGE] Type::TYPE_FLASH => [Subdef::TYPE_IMAGE]
@@ -525,29 +526,44 @@ class SubdefsController extends Controller
], ],
Subdef::TYPE_AUDIO => [ Subdef::TYPE_AUDIO => [
"definitions" => [ "definitions" => [
"Low AAC 96 kbit/s" => [ "Low MP3 96 kbit/s" => [
Audio::OPTION_AUDIOBITRATE => "100", Audio::OPTION_AUDIOBITRATE => "100",
Audio::OPTION_AUDIOSAMPLERATE => "8000", Audio::OPTION_AUDIOSAMPLERATE => "8000",
Audio::OPTION_ACODEC => "libmp3lame", Audio::OPTION_ACODEC => "libmp3lame",
Subdef::OPTION_DEVICE => ["all"] Subdef::OPTION_DEVICE => ["all"]
], ],
"Normal AAC 128 kbit/s" => [ "Normal MP3 128 kbit/s" => [
Audio::OPTION_AUDIOBITRATE => "180", Audio::OPTION_AUDIOBITRATE => "180",
Audio::OPTION_AUDIOSAMPLERATE => "44100", Audio::OPTION_AUDIOSAMPLERATE => "44100",
Audio::OPTION_ACODEC => "libmp3lame", Audio::OPTION_ACODEC => "libmp3lame",
Subdef::OPTION_DEVICE => ["all"] Subdef::OPTION_DEVICE => ["all"]
], ],
"High AAC 320 kbit/s" => [ "High MP3 320 kbit/s" => [
Audio::OPTION_AUDIOBITRATE => "230", Audio::OPTION_AUDIOBITRATE => "230",
Audio::OPTION_AUDIOSAMPLERATE => "50000", Audio::OPTION_AUDIOSAMPLERATE => "50000",
Audio::OPTION_ACODEC => "libmp3lame", Audio::OPTION_ACODEC => "libmp3lame",
Subdef::OPTION_DEVICE => ["all"] Subdef::OPTION_DEVICE => ["all"]
], ],
"Wave Mono 16 kHz" => [
Audio::OPTION_AUDIOBITRATE => "256",
Audio::OPTION_AUDIOSAMPLERATE => "16000",
Audio::OPTION_ACODEC => "pcm_s16le",
Audio::OPTION_AUDIOCHANNEL => "mono",
Subdef::OPTION_DEVICE => ["all"]
],
"Wave Mono 8 kHz" => [
Audio::OPTION_AUDIOBITRATE => "128",
Audio::OPTION_AUDIOSAMPLERATE => "8000",
Audio::OPTION_ACODEC => "pcm_s16le",
Audio::OPTION_AUDIOCHANNEL => "mono",
Subdef::OPTION_DEVICE => ["all"]
],
], ],
"form" => [ "form" => [
Audio::OPTION_AUDIOBITRATE => "slide", Audio::OPTION_AUDIOBITRATE => "slide",
Audio::OPTION_AUDIOSAMPLERATE => "select", Audio::OPTION_AUDIOSAMPLERATE => "select",
Audio::OPTION_ACODEC => "select", Audio::OPTION_ACODEC => "select",
Audio::OPTION_AUDIOCHANNEL => "select",
Subdef::OPTION_DEVICE => "checkbox", Subdef::OPTION_DEVICE => "checkbox",
], ],
], ],

View File

@@ -323,9 +323,14 @@ class QueryController extends Controller
// add technical fields // add technical fields
$fieldLabels = []; $fieldsInfosByName = [];
foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) { foreach(ElasticsearchOptions::getAggregableTechnicalFields() as $k => $f) {
$fieldLabels[$k] = $this->app->trans($f['label']); $fieldsInfosByName[$k] = $f;
$fieldsInfosByName[$k]['trans_label'] = $this->app->trans($f['label']);
$fieldsInfosByName[$k]['labels'] = [];
foreach($this->app->getAvailableLanguages() as $locale => $lng) {
$fieldsInfosByName[$k]['labels'][$locale] = $this->app->trans($f['label'], [], "messages", $locale);
}
} }
// add databox fields // add databox fields
@@ -337,13 +342,25 @@ class QueryController extends Controller
foreach ($databox->get_meta_structure() as $field) { foreach ($databox->get_meta_structure() as $field) {
$name = $field->get_name(); $name = $field->get_name();
$fieldsInfos[$sbasId][$name] = [ $fieldsInfos[$sbasId][$name] = [
'label' => $field->get_label($this->app['locale']), 'label' => $field->get_label($this->app['locale']),
'type' => $field->get_type(), 'labels' => $field->get_labels(),
'type' => $field->get_type(),
'business' => $field->isBusiness(), 'business' => $field->isBusiness(),
'multi' => $field->is_multi(), 'multi' => $field->is_multi(),
]; ];
if (!isset($fieldLabels[$name])) {
$fieldLabels[$name] = $field->get_label($this->app['locale']); // infos on the "same" field (by name) on multiple databoxes !!!
// label(s) can be inconsistants : the first databox wins
if (!isset($fieldsInfosByName[$name])) {
$fieldsInfosByName[$name] = [
'label' => $field->get_label($this->app['locale']),
'labels' => $field->get_labels(),
'type' => $field->get_type(),
'field' => $field->get_name(),
'query' => "field." . $field->get_name() . ":%s",
'trans_label' => $field->get_label($this->app['locale']),
];
$field->get_label($this->app['locale']);
} }
} }
} }
@@ -382,14 +399,29 @@ class QueryController extends Controller
// populates facets (aggregates) // populates facets (aggregates)
$facets = []; $facets = [];
// $facetClauses = [];
foreach ($result->getFacets() as $facet) { foreach ($result->getFacets() as $facet) {
$facetName = $facet['name']; $facetName = $facet['name'];
$facet['label'] = isset($fieldLabels[$facetName]) ? $fieldLabels[$facetName] : $facetName; if(array_key_exists($facetName, $fieldsInfosByName)) {
$facets[] = $facet; $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
// ];
}
} }
// $json['jsq'] = $facetClauses;
$json['facets'] = $facets; $json['facets'] = $facets;
$json['phrasea_props'] = $proposals; $json['phrasea_props'] = $proposals;
$json['total_answers'] = (int) $result->getAvailable(); $json['total_answers'] = (int) $result->getAvailable();

View File

@@ -1,802 +0,0 @@
<?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\Controller\Report;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Core\Response\CSVFileResponse;
use Goodby\CSV\Export\Standard\Collection\CallbackCollection;
use Goodby\CSV\Export\Standard\Exporter;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ActivityController extends Controller
{
/**
* Display connexions report group by user
*
* @param Request $request
* @return JsonResponse
*/
public function doReportConnexionsByUsers(Request $request)
{
$activity = new \module_report_activity(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
$activity->setBound("user", true);
//set Limit
if ($activity->getEnableLimit()
&& ('' !== $page = $request->request->get('page', ''))
&& ('' !== $limit = $request->request->get('limit', ''))) {
$activity->setLimit($page, $limit);
} else {
$activity->setLimit(false, false);
}
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->getConnexionBase(false, $request->request->get('on', 'user'));
return $this->getCSVResponse($activity, 'activity_connection_base');
}
$report = $activity->getConnexionBase(false, $request->request->get('on', 'user'));
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => false,
'title' => false,
]);
}
/**
* Display download report group by user
*
* @param Request $request
* @return JsonResponse
*/
public function doReportDownloadsByUsers(Request $request)
{
$conf = [
'user' => [$this->app->trans('report:: utilisateur'), 0, 1, 0, 0],
'nbdoc' => [$this->app->trans('report:: nombre de documents'), 0, 0, 0, 0],
'nbprev' => [$this->app->trans('report:: nombre de preview'), 0, 0, 0, 0],
];
$activity = new \module_report_activity(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
//set Limit
if ($activity->getEnableLimit()
&& ('' !== $page = $request->request->get('page', ''))
&& ('' !== $limit = $request->request->get('limit', ''))) {
$activity->setLimit($page, $limit);
} else {
$activity->setLimit(false, false);
}
$report = $activity->getDetailDownload($conf, $request->request->get('on'));
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
return $this->getCSVResponse($activity, 'activity_detail_download');
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => false,
'title' => false,
]);
}
/**
* Display the most asked question
*
* @param Request $request
* @return JsonResponse
*/
public function doReportBestOfQuestions(Request $request)
{
$conf = [
'search' => [$this->app->trans('report:: question'), 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0],
'nb_rep' => [$this->app->trans('report:: nombre de reponses'), 0, 0, 0, 0]
];
$activity = new \module_report_activity(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setLimit(1, $request->request->get('limit', 20));
$activity->setTop(20);
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$activity->getTopQuestion($conf);
return $this->getCSVResponse($activity, 'activity_questions_best_of');
}
$report = $activity->getTopQuestion($conf);
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => false,
'title' => false
]);
}
/**
* Display report about questions that return no result
*
* @param Request $request
* @return JsonResponse
*/
public function doReportNoBestOfQuestions(Request $request)
{
$conf = [
'search' => [$this->app->trans('report:: question'), 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0],
'nb_rep' => [$this->app->trans('report:: nombre de reponses'), 0, 0, 0, 0]
];
$activity = new \module_report_activity(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
//set Limit
if ($activity->getEnableLimit()
&& ('' !== $page = $request->request->get('page', ''))
&& ('' !== $limit = $request->request->get('limit', ''))) {
$activity->setLimit($page, $limit);
} else {
$activity->setLimit(false, false);
}
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$activity->getTopQuestion($conf, true);
return $this->getCSVResponse($activity, 'activity_top_ten_questions');
}
$report = $activity->getTopQuestion($conf, true);
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => false,
'title' => false
]);
}
/**
* Display an overview of connexion among hours of the da
*
* @param Request $request
* @return JsonResponse
*/
public function doReportSiteActiviyPerHours(Request $request)
{
$activity = new \module_report_activity(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$activity->getActivityPerHours();
return $this->getCSVResponse($activity, 'activity_per_hours');
}
$report = $activity->getActivityPerHours();
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => true,
'is_doc' => false
]),
'display_nav' => false,
'title' => false
]);
}
/**
* Display an overview of downloaded document grouped by day
*
* @param Request $request
* @return JsonResponse
*/
public function doReportSiteActivityPerDays(Request $request)
{
$conf = [
'ddate' => [$this->app->trans('report:: jour'), 0, 0, 0, 0],
'total' => [$this->app->trans('report:: total des telechargements'), 0, 0, 0, 0],
'preview' => [$this->app->trans('report:: preview'), 0, 0, 0, 0],
'document' => [$this->app->trans('report:: document'), 0, 0, 0, 0]
];
$activity = new \module_report_activity(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
//set Limit
if ($activity->getEnableLimit()
&& ('' !== $page = $request->request->get('page', ''))
&& ('' !== $limit = $request->request->get('limit', ''))) {
$activity->setLimit($page, $limit);
} else {
$activity->setLimit(false, false);
}
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$activity->getDownloadByBaseByDay($conf);
return $this->getCSVResponse($activity, 'activity_db_by_base_by_day');
}
$report = $activity->getDownloadByBaseByDay($conf);
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => false,
'title' => false,
]);
}
/**
* Display report about pushed documents
*
* @param Request $request
* @return JsonResponse
*/
public function doReportPushedDocuments(Request $request)
{
$conf = [
'user' => ['', 1, 0, 1, 1],
'getter' => ["Destinataire", 1, 0, 1, 1],
'date' => ['', 1, 0, 1, 1],
'record_id' => ['', 1, 1, 1, 1],
'file' => ['', 1, 0, 1, 1],
'mime' => ['', 1, 0, 1, 1],
];
$activity = new \module_report_push(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$this->doReport($request, $activity, $conf);
return $this->getCSVResponse($activity, 'activity_pushed_documents');
}
$report = $this->doReport($request, $activity, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record'],
]);
}
/**
* Display report about added documents
*
* @param Request $request
* @return JsonResponse
*/
public function doReportAddedDocuments(Request $request)
{
$conf = [
'user' => ['', 1, 0, 1, 1],
'date' => ['', 1, 0, 1, 1],
'record_id' => ['', 1, 1, 1, 1],
'file' => ['', 1, 0, 1, 1],
'mime' => ['', 1, 0, 1, 1],
];
$activity = new \module_report_add(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$this->doReport($request, $activity, $conf);
return $this->getCSVResponse($activity, 'activity_added_documents');
}
$report = $this->doReport($request, $activity, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record'],
]);
}
/**
* Display report about edited documents
*
* @param Request $request
* @return JsonResponse
*/
public function doReportEditedDocuments(Request $request)
{
$conf = [
'user' => ['', 1, 0, 1, 1],
'date' => ['', 1, 0, 1, 1],
'record_id' => ['', 1, 1, 1, 1],
'file' => ['', 1, 0, 1, 1],
'mime' => ['', 1, 0, 1, 1],
];
$activity = new \module_report_edit(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$this->doReport($request, $activity, $conf);
return $this->getCSVResponse($activity, 'activity_edited_documents');
}
$report = $this->doReport($request, $activity, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record'],
]);
}
/**
* Display report about validated documents
*
* @param Request $request
* @return JsonResponse
*/
public function doReportValidatedDocuments(Request $request)
{
$conf = [
'user' => ['', 1, 0, 1, 1],
'getter' => ["Destinataire", 1, 0, 1, 1],
'date' => ['', 1, 0, 1, 1],
'record_id' => ['', 1, 1, 1, 1],
'file' => ['', 1, 0, 1, 1],
'mime' => ['', 1, 0, 1, 1],
];
$activity = new \module_report_validate(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$this->doReport($request, $activity, $conf);
return $this->getCSVResponse($activity, 'activity_validated_documents');
}
$report = $this->doReport($request, $activity, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record'],
]);
}
/**
* Display report about documents sent by mail
*
* @param Request $request
* @return JsonResponse
*/
public function doReportSentDocuments(Request $request)
{
$conf = [
'user' => ['', 1, 0, 1, 1],
'date' => ['', 1, 0, 1, 1],
'record_id' => ['', 1, 1, 1, 1],
'file' => ['', 1, 0, 1, 1],
'mime' => ['', 1, 0, 1, 1],
'comment' => [$this->app->trans('Receiver'), 1, 0, 1, 1],
];
$activity = new \module_report_sent(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$activity->setConfig(false);
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
$this->doReport($request, $activity, $conf);
return $this->getCSVResponse($activity, 'activity_send_documents');
}
$report = $this->doReport($request, $activity, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record'],
]);
}
/**
* Set Report configuration according to request parameters
*
* @param Request $request A request instance
* @param \module_report $report A report instance
* @param Array $conf A report column configuration
* @param Boolean $what Whether to group on a particular field or not
* @return Array
*/
private function doReport(Request $request, \module_report $report, $conf, $what = false)
{
if ($this->getConf()->get(['registry', 'modules', 'anonymous-report'])) {
if (isset($conf['user'])) {
unset($conf['user']);
}
if (isset($conf['ip'])) {
unset($conf['ip']);
}
}
//save initial conf
$base_conf = $conf;
//format conf according user preferences
if ('' !== $columnsList = $request->request->get('list_column', '')) {
$new_conf = $conf;
$columns = explode(",", $columnsList);
foreach (array_keys($conf) as $col) {
if (!in_array($col, $columns)) {
unset($new_conf[$col]);
}
}
$conf = $new_conf;
}
//display content of a table column when user click on it
if ($request->request->get('conf') == 'on') {
return $this->app->json(['liste' => $this->render('report/listColumn.html.twig', [
'conf' => $base_conf
]), "title" => $this->app->trans("configuration")]);
}
//set order
if (('' !== $order = $request->request->get('order', '')) && ('' !== $field = $request->request->get('champ', ''))) {
$report->setOrder($field, $order);
}
//work on filters
$mapColumnTitleToSqlField = $report->getTransQueryString();
$currentfilter = [];
if ('' !== $serializedFilter = $request->request->get('liste_filter', '')) {
$currentfilter = @unserialize(urldecode($serializedFilter));
}
$filter = new \module_report_filter($this->app, $currentfilter, $mapColumnTitleToSqlField);
if ('' !== $filterColumn = $request->request->get('filter_column', '')) {
$field = current(explode(' ', $filterColumn));
$value = $request->request->get('filter_value', '');
if ($request->request->get('liste') == 'on') {
return $this->app->json(['diag' => $this->render('report/colFilter.html.twig', [
'result' => $report->colFilter($field),
'field' => $field
]), "title" => $this->app->trans('filtrer les resultats sur la colonne %colonne%', ['%colonne%' => $field])]);
}
if ($field === $value) {
$filter->removeFilter($field);
} else {
$filter->addFilter($field, '=', $value);
}
}
//set new request filter if user asking for them
if ($request->request->get('precise') == 1) {
$filter->addFilter('xml', 'LIKE', $request->request->get('word', ''));
} elseif ($request->request->get('precise') == 2) {
$filter->addFilter('record_id', '=', $request->request->get('word', ''));
}
//set filters to current report
$report->setFilter($filter->getTabFilter());
$report->setActiveColumn($filter->getActiveColumn());
$report->setPostingFilter($filter->getPostingFilter());
// display a new arraywhere results are group
if ('' !== $groupby = $request->request->get('groupby', '')) {
$report->setConfig(false);
$groupby = current(explode(' ', $groupby));
$reportArray = $report->buildReport(false, $groupby);
if (count($reportArray['allChamps']) > 0 && count($reportArray['display']) > 0) {
$groupField = isset($reportArray['display'][$reportArray['allChamps'][0]]['title']) ? $reportArray['display'][$reportArray['allChamps'][0]]['title'] : '';
} else {
$groupField = isset($conf[strtolower($groupby)]['title']) ? $conf[strtolower($groupby)]['title'] : '';
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($reportArray['report']) ? $reportArray['report'] : $reportArray,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => true,
'is_plot' => false,
'is_doc' => false,
]),
'display_nav' => false,
'title' => $this->app->trans('Groupement des resultats sur le champ %name%', ['%name%' => $groupField]),
]);
}
//set Limit
if ($report->getEnableLimit()
&& ('' !== $page = $request->request->get('page', ''))
&& ('' !== $limit = $request->request->get('limit', ''))) {
$report->setLimit($page, $limit);
} else {
$report->setLimit(false, false);
}
//time to build our report
if (false === $what) {
$reportArray = $report->buildReport($conf);
} else {
$reportArray = $report->buildReport($conf, $what, $request->request->get('tbl', false));
}
return $reportArray;
}
private function getCSVResponse(\module_report $report, $type)
{
// set headers
$headers = [];
foreach (array_keys($report->getDisplay()) as $k) {
$headers[$k] = $k;
}
// set headers as first row
$result = $report->getResult();
array_unshift($result, $headers);
$collection = new CallbackCollection($result, function ($row) use ($report) {
// restrict to displayed fields
return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
});
$filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
/** @var Exporter $exporter */
$exporter = $this->app['csv.exporter'];
$response = new CSVFileResponse($filename, function () use ($exporter, $collection) {
$exporter->export('php://output', $collection);
});
return $response;
}
}

View File

@@ -1,502 +0,0 @@
<?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\Controller\Report;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Core\Response\CSVFileResponse;
use Goodby\CSV\Export\Standard\Collection\CallbackCollection;
use Goodby\CSV\Export\Standard\Exporter;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
class InformationController extends Controller
{
/**
* Display information about a user
*
* @param Request $request
* @return JsonResponse
*/
public function doReportInformationUser(Request $request)
{
$conf = [
'config' => [
'photo' => [$this->app->trans('report:: document'), 0, 0, 0, 0],
'record_id' => [$this->app->trans('report:: record id'), 0, 0, 0, 0],
'date' => [$this->app->trans('report:: date'), 0, 0, 0, 0],
'type' => [$this->app->trans('phrseanet:: sous definition'), 0, 0, 0, 0],
'titre' => [$this->app->trans('report:: titre'), 0, 0, 0, 0],
'taille' => [$this->app->trans('report:: poids'), 0, 0, 0, 0]
],
'conf' => [
'identifiant' => [$this->app->trans('report:: identifiant'), 0, 0, 0, 0],
'nom' => [$this->app->trans('report:: nom'), 0, 0, 0, 0],
'mail' => [$this->app->trans('report:: email'), 0, 0, 0, 0],
'adresse' => [$this->app->trans('report:: adresse'), 0, 0, 0, 0],
'tel' => [$this->app->trans('report:: telephone'), 0, 0, 0, 0]
],
'config_cnx' => [
'ddate' => [$this->app->trans('report:: date'), 0, 0, 0, 0],
'appli' => [$this->app->trans('report:: modules'), 0, 0, 0, 0],
],
'config_dl' => [
'ddate' => [$this->app->trans('report:: date'), 0, 0, 0, 0],
'record_id' => [$this->app->trans('report:: record id'), 0, 1, 0, 0],
'final' => [$this->app->trans('phrseanet:: sous definition'), 0, 0, 0, 0],
'coll_id' => [$this->app->trans('report:: collections'), 0, 0, 0, 0],
'comment' => [$this->app->trans('report:: commentaire'), 0, 0, 0, 0],
],
'config_ask' => [
'search' => [$this->app->trans('report:: question'), 0, 0, 0, 0],
'ddate' => [$this->app->trans('report:: date'), 0, 0, 0, 0]
]
];
$report = null;
$html = $html_info = '';
$from = $request->request->get('from', '');
$on = $request->request->get('on', '');
$selectValue = $request->request->get('user', '');
if ('' === $selectValue) {
$this->app->abort(400);
}
if ('' !== $on && $this->getConf()->get(['registry', 'modules', 'anonymous-report']) == true) {
$conf['conf'] = [
$on => [$on, 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0]
];
}
if ($from == 'CNXU' || $from == 'CNX') {
$report = new \module_report_connexion(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf_array = $conf['config_cnx'];
$title = $this->app->trans('report:: historique des connexions');
} elseif ($from == 'USR' || $from == 'GEN') {
$report = new \module_report_download(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf_array = $conf['config_dl'];
$title = $this->app->trans('report:: historique des telechargements');
} elseif ($from == 'ASK') {
$report = new \module_report_question(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf_array = $conf['config_ask'];
$title = $this->app->trans('report:: historique des questions');
}
if ($report) {
$mapColumnTitleToSqlField = $report->getTransQueryString();
$currentfilter = [];
if ('' !== $serializedFilter = $request->request->get('liste_filter', '')) {
$currentfilter = @unserialize(urldecode($serializedFilter));
}
$filter = new \module_report_filter($this->app, $currentfilter, $mapColumnTitleToSqlField);
if ('' !== $filterColumn = $request->request->get('filter_column', '')) {
$field = current(explode(' ', $filterColumn));
$value = $request->request->get('filter_value', '');
if ($request->request->get('liste') == 'on') {
return $this->app->json([
'diag' => $this->render('report/colFilter.html.twig', [
'result' => $report->colFilter($field),
'field' => $field
]),
'title' => $this->app->trans('filtrer les resultats sur la colonne %colonne%', ['%colonne%' => $field])]);
}
if ($field === $value) {
$filter->removeFilter($field);
} else {
$filter->addFilter($field, '=', $value);
}
}
if ('' !== $selectValue && '' !== $from) {
$filter->addfilter('usrid', '=', $selectValue);
} elseif ('' !== $on && '' !== $selectValue) {
$filter->addfilter($on, '=', $selectValue);
}
if ($report instanceof \module_report_download) {
$report->setIsInformative(true);
}
$report->setFilter($filter->getTabFilter());
$report->setOrder('ddate', 'DESC');
$report->setConfig(false);
$report->setTitle($title);
$report->setHasLimit(false);
$reportArray = $report->buildReport($conf_array);
if ($request->request->get('printcsv') == 'on') {
$report->setPrettyString(false);
return $this->getCSVResponse($report, 'info_user');
}
$html = $this->render('report/ajax_data_content.html.twig', [
'result' => isset($reportArray['report']) ? $reportArray['report'] : $reportArray,
'is_infouser' => $report instanceof \module_report_download,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]);
}
$info = new \module_report_nav(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$info->setPeriode('');
$info->setCsv(false);
$infoArray = $info->buildTabGrpInfo(
null !== $report ? $report->getReq() : '',
null !== $report ? $report->getParams() : [],
$selectValue,
$conf['conf'],
$on
);
if (false == $this->app['conf']->get(['registry', 'modules', 'anonymous-report'])) {
$html_info = $this->render('report/ajax_data_content.html.twig', [
'result' => isset($infoArray['report']) ? $infoArray['report'] : $infoArray,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]);
$title = ('' === $on && isset($infoArray['result'])) ? $infoArray['result'][0]['identifiant'] : $selectValue;
} else {
$title = $selectValue;
}
return $this->app->json([
'rs' => sprintf('%s%s', $html_info, $html),
'display_nav' => false,
'title' => $title
]);
}
/**
* Display a browser version
*
* @param Request $request
* @return JsonResponse
*/
public function doReportInformationBrowser(Request $request)
{
$conf = [
'version' => [$this->app->trans('report::version'), 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0]
];
$info = new \module_report_nav(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$info->setCsv(false);
$info->setConfig(false);
if ('' === $browser = $request->request->get('user', '')) {
$this->app->abort(400);
}
$reportArray = $info->buildTabInfoNav($conf, $browser);
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($reportArray['report']) ? $reportArray['report'] : $reportArray,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => false,
'title' => $browser
]);
}
/**
* Display information about a document
*
* @param Request $request
* @return JsonResponse
*/
public function doReportInformationDocument(Request $request)
{
$config = [
'photo' => [$this->app->trans('report:: document'), 0, 0, 0, 0],
'record_id' => [$this->app->trans('report:: record id'), 0, 0, 0, 0],
'date' => [$this->app->trans('report:: date'), 0, 0, 0, 0],
'type' => [$this->app->trans('phrseanet:: sous definition'), 0, 0, 0, 0],
'titre' => [$this->app->trans('report:: titre'), 0, 0, 0, 0],
'taille' => [$this->app->trans('report:: poids'), 0, 0, 0, 0]
];
$config_dl = [
'ddate' => [$this->app->trans('report:: date'), 0, 0, 0, 0],
'user' => [$this->app->trans('report:: utilisateurs'), 0, 0, 0, 0],
'final' => [$this->app->trans('phrseanet:: sous definition'), 0, 0, 0, 0],
'coll_id' => [$this->app->trans('report:: collections'), 0, 0, 0, 0],
'comment' => [$this->app->trans('report:: commentaire'), 0, 0, 0, 0],
'fonction' => [$this->app->trans('report:: fonction'), 0, 0, 0, 0],
'activite' => [$this->app->trans('report:: activite'), 0, 0, 0, 0],
'pays' => [$this->app->trans('report:: pays'), 0, 0, 0, 0],
'societe' => [$this->app->trans('report:: societe'), 0, 0, 0, 0]
];
//format conf according user preferences
if ('' !== $columnsList = $request->request->get('list_column', '')) {
$new_conf = $config_dl;
$columns = explode(',', $columnsList);
foreach (array_keys($config_dl) as $col) {
if (!in_array($col, $columns)) {
unset($new_conf[$col]);
}
}
$config_dl = $new_conf;
}
try {
$record = new \record_adapter(
$this->app,
$request->request->get('sbasid'),
$request->request->get('rid')
);
} catch (\Exception $e) {
$this->app->abort(404);
}
$what = new \module_report_nav(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$what->setPeriode('');
$what->setCsv(false);
$what->setPrint(false);
/** @var \record_adapter $record */
$reportArray = $what->buildTabUserWhat(
$record->getBaseId(),
$record->getRecordId(),
$config
);
$title = $what->getTitle();
$html = $this->render('report/ajax_data_content.html.twig', [
'result' => isset($reportArray['report']) ? $reportArray['report'] : $reportArray,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]);
$from = $request->request->get('from', '');
if ('TOOL' === $from) {
$what->setTitle('');
return $this->app->json([
'rs' => $html,
'display_nav' => false,
'title' => $title
]);
}
if ('DASH' !== $from && 'PUSHDOC' !== $from) {
$download = new \module_report_download(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$mapColumnTitleToSqlField = $download->getTransQueryString();
$currentfilter = [];
if ('' !== $serializedFilter = $request->request->get('liste_filter', '')) {
$currentfilter = @unserialize(urldecode($serializedFilter));
}
$filter = new \module_report_filter($this->app, $currentfilter, $mapColumnTitleToSqlField);
if ('' !== $filterColumn = $request->request->get('filter_column', '')) {
$field = current(explode(' ', $filterColumn));
$value = $request->request->get('filter_value', '');
if ($request->request->get('liste') == 'on') {
return $this->app->json([
'diag' => $this->render('report/colFilter.html.twig', [
'result' => $download->colFilter($field),
'field' => $field
]),
'title' => $this->app->trans('filtrer les resultats sur la colonne %colonne%', ['%colonne%' => $field])
]);
}
if ($field === $value) {
$filter->removeFilter($field);
} else {
$filter->addFilter($field, '=', $value);
}
}
$filter->addfilter('record_id', '=', $record->getRecordId());
$download->setFilter($filter->getTabFilter());
$download->setOrder('ddate', 'DESC');
$download->setTitle($this->app->trans('report:: historique des telechargements'));
$download->setConfig(false);
$reportArray = $download->buildReport($config_dl);
if ($request->request->get('printcsv') == 'on') {
$download->setPrettyString(false);
return $this->getCSVResponse($download, 'info_document');
}
$html .= $this->render('report/ajax_data_content.html.twig', [
'result' => isset($reportArray['report']) ? $reportArray['report'] : $reportArray,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]);
return $this->app->json([
'rs' => $html,
'display_nav' => false,
'title' => $title
]);
}
if ($this->getConf()->get(['registry', 'modules', 'anonymous-report']) == false && $from !== 'DOC' && $from !== 'DASH' && $from !== 'GEN' && $from !== 'PUSHDOC') {
$conf = [
'identifiant' => [$this->app->trans('report:: identifiant'), 0, 0, 0, 0],
'nom' => [$this->app->trans('report:: nom'), 0, 0, 0, 0],
'mail' => [$this->app->trans('report:: email'), 0, 0, 0, 0],
'adresse' => [$this->app->trans('report:: adresse'), 0, 0, 0, 0],
'tel' => [$this->app->trans('report:: telephone'), 0, 0, 0, 0]
];
$info = new \module_report_nav(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$info->setPeriode('');
$info->setConfig(false);
$info->setTitle($this->app->trans('report:: utilisateur'));
$reportArray = $info->buildTabGrpInfo(false, [], $request->request->get('user'), $conf, false);
if ($request->request->get('printcsv') == 'on' && isset($download)) {
return $this->getCSVResponse($this->app, $info, 'info_user');
}
$html .= $this->render('report/ajax_data_content.html.twig', [
'result' => isset($reportArray['report']) ? $reportArray['report'] : $reportArray,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]);
return $this->app->json([
'rs' => $html,
'display_nav' => false,
'title' => $title
]);
}
return $this->app->json([
'rs' => $html,
'display_nav' => false,
'title' => $title
]);
}
private function getCSVResponse(\module_report $report, $type)
{
// set headers
$headers = [];
foreach (array_keys($report->getDisplay()) as $k) {
$headers[$k] = $k;
}
// set headers as first row
$result = $report->getResult();
array_unshift($result, $headers);
$collection = new CallbackCollection($result, function ($row) use ($report) {
// restrict fields to the displayed ones
return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
});
/** @var Exporter $exporter */
$exporter = $this->app['csv.exporter'];
$filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
$response = new CSVFileResponse($filename, function () use ($exporter, $collection) {
$exporter->export('php://output', $collection);
});
return $response;
}
}

View File

@@ -10,12 +10,8 @@
namespace Alchemy\Phrasea\Controller\Report; namespace Alchemy\Phrasea\Controller\Report;
use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Core\Response\CSVFileResponse;
use Goodby\CSV\Export\Standard\Collection\CallbackCollection;
use Goodby\CSV\Export\Standard\Exporter;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class RootController extends Controller class RootController extends Controller
{ {
@@ -53,22 +49,34 @@ class RootController extends Controller
$granted = []; $granted = [];
foreach ($this->getAclForUser()->get_granted_base([\ACL::CANREPORT]) as $collection) { $acl = $this->getAclForUser();
if (!isset($granted[$collection->get_sbas_id()])) { foreach ($acl->get_granted_base([\ACL::CANREPORT]) as $collection) {
$granted[$collection->get_sbas_id()] = [ $sbas_id = $collection->get_sbas_id();
'id' => $collection->get_sbas_id(), if (!isset($granted[$sbas_id])) {
'name' => $collection->get_databox()->get_viewname(), $granted[$sbas_id] = [
'collections' => [] 'id' => $sbas_id,
'name' => $collection->get_databox()->get_viewname(),
'collections' => [],
'metas' => []
]; ];
foreach ($collection->get_databox()->get_meta_structure() as $meta) {
// skip the fields that can't be reported
if (!$meta->is_report() || ($meta->isBusiness() && !$acl->can_see_business_fields($collection->get_databox()))) {
continue;
}
$granted[$sbas_id]['metas'][] = $meta->get_name();
}
} }
$granted[$collection->get_sbas_id()]['collections'][] = [ $granted[$sbas_id]['collections'][] = [
'id' => $collection->get_coll_id(), 'id' => $collection->get_coll_id(),
'base_id' => $collection->get_base_id(), 'base_id' => $collection->get_base_id(),
'name' => $collection->get_name() 'name' => $collection->get_name(),
]; ];
} }
$conf = $this->getConf(); $conf = $this->getConf();
return $this->render('report/report_layout_child.html.twig', [ return $this->render('report/report_layout_child.html.twig', [
'ajax_dash' => true, 'ajax_dash' => true,
'dashboard' => null, 'dashboard' => null,
@@ -82,594 +90,4 @@ class RootController extends Controller
'ajax_chart' => false 'ajax_chart' => false
]); ]);
} }
/**
* Gets available collections where current user can see report and
* format date
*
* @param Request $request
* @return JsonResponse
*/
public function initReport(Request $request)
{
$popbases = $request->request->get('popbases', []);
if ('' === $dmin = $request->request->get('dmin', '')) {
$dmin = date('Y') . '-' . date('m') . '-01';
}
if ('' === $dmax = $request->request->get('dmax', '')) {
$dmax = date('Y') . '-' . date('m') . '-' . date('d');
}
$dmin = \DateTime::createFromFormat('Y-m-d H:i:s', sprintf('%s 00:00:00', $dmin));
$dmax = \DateTime::createFromFormat('Y-m-d H:i:s', sprintf('%s 23:59:59', $dmax));
//get user's sbas & collections selection from popbases
$selection = [];
$liste = $id_sbas = '';
$i = 0;
foreach (array_fill_keys($popbases, 0) as $key => $val) {
$exp = explode('_', $key);
if ($exp[0] != $id_sbas && $i != 0) {
$selection[$id_sbas]['liste'] = $liste;
$liste = '';
}
$selection[$exp[0]][] = $exp[1];
$liste .= (empty($liste) ? '' : ',') . $exp[1];
$id_sbas = $exp[0];
$i ++;
}
//fill the last entry
$selection[$id_sbas]['liste'] = $liste;
return $this->render('report/ajax_report_content.html.twig', [
'selection' => $selection,
'anonymous' => $this->getConf()->get(['registry', 'modules', 'anonymous-report']),
'ajax' => true,
'dmin' => $dmin->format('Y-m-d H:i:s'),
'dmax' => $dmax->format('Y-m-d H:i:s'),
]);
}
/**
* Display instance connexion report
*
* @param Request $request
* @return JsonResponse
*/
public function doReportConnexions(Request $request)
{
$cnx = new \module_report_connexion(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf = [
'user' => [$this->app->trans('phraseanet::utilisateurs'), 1, 1, 1, 1],
'ddate' => [$this->app->trans('report:: date'), 1, 0, 1, 1],
'ip' => [$this->app->trans('report:: IP'), 1, 0, 0, 0],
'appli' => [$this->app->trans('report:: modules'), 1, 0, 0, 0],
'fonction' => [$this->app->trans('report::fonction'), 1, 1, 1, 1],
'activite' => [$this->app->trans('report::activite'), 1, 1, 1, 1],
'pays' => [$this->app->trans('report::pays'), 1, 1, 1, 1],
'societe' => [$this->app->trans('report::societe'), 1, 1, 1, 1]
];
if ($request->request->get('printcsv') == 'on') {
$cnx->setHasLimit(false);
$cnx->setPrettyString(false);
$this->doReport($request, $cnx, $conf);
return $this->getCSVResponse($cnx, 'connections');
}
$report = $this->doReport($request, $cnx, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record']
]);
}
/**
* Display instance questions report
*
* @param Request $request
* @return JsonResponse
*/
public function doReportQuestions(Request $request)
{
$questions = new \module_report_question(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf = [
'user' => [$this->app->trans('report:: utilisateur'), 1, 1, 1, 1],
'search' => [$this->app->trans('report:: question'), 1, 0, 1, 1],
'ddate' => [$this->app->trans('report:: date'), 1, 0, 1, 1],
'fonction' => [$this->app->trans('report:: fonction'), 1, 1, 1, 1],
'activite' => [$this->app->trans('report:: activite'), 1, 1, 1, 1],
'pays' => [$this->app->trans('report:: pays'), 1, 1, 1, 1],
'societe' => [$this->app->trans('report:: societe'), 1, 1, 1, 1]
];
if ($request->request->get('printcsv') == 'on') {
$questions->setHasLimit(false);
$questions->setPrettyString(false);
$this->doReport($request, $questions, $conf);
return $this->getCSVResponse($questions, 'questions');
}
$report = $this->doReport($request, $questions, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record']
]);
}
/**
* Display instance download report
*
* @param Request $request
* @return JsonResponse
*/
public function doReportDownloads(Request $request)
{
$download = new \module_report_download(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf_pref = [];
foreach (\module_report::getPreff($this->app, $request->request->get('sbasid')) as $field) {
$conf_pref[strtolower($field)] = [$field, 0, 0, 0, 0];
}
$conf = array_merge([
'user' => [$this->app->trans('report:: utilisateurs'), 1, 1, 1, 1],
'ddate' => [$this->app->trans('report:: date'), 1, 0, 1, 1],
'record_id' => [$this->app->trans('report:: record id'), 1, 1, 1, 1],
'final' => [$this->app->trans('phrseanet:: sous definition'), 1, 0, 1, 1],
'coll_id' => [$this->app->trans('report:: collections'), 1, 0, 1, 1],
'comment' => [$this->app->trans('report:: commentaire'), 1, 0, 0, 0],
'fonction' => [$this->app->trans('report:: fonction'), 1, 1, 1, 1],
'activite' => [$this->app->trans('report:: activite'), 1, 1, 1, 1],
'pays' => [$this->app->trans('report:: pays'), 1, 1, 1, 1],
'societe' => [$this->app->trans('report:: societe'), 1, 1, 1, 1]
], $conf_pref);
if ($request->request->get('printcsv') == 'on') {
$download->setHasLimit(false);
$download->setPrettyString(false);
$this->doReport($request, $download, $conf);
$r = $this->getCSVResponse($download, 'download');
return $r;
}
$report = $this->doReport($request, $download, $conf);
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record']
]);
}
/**
* Display instance document report
*
* @param Request $request
* @return JsonResponse
*/
public function doReportDocuments(Request $request)
{
$document = new \module_report_download(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf_pref = [];
foreach (\module_report::getPreff($this->app, $request->request->get('sbasid')) as $field) {
$conf_pref[$field] = array($field, 0, 0, 0, 0);
}
$conf = array_merge([
'telechargement' => [$this->app->trans('report:: telechargements'), 1, 0, 0, 0],
'record_id' => [$this->app->trans('report:: record id'), 1, 1, 1, 0],
'final' => [$this->app->trans('phraseanet:: sous definition'), 1, 0, 1, 1],
'file' => [$this->app->trans('report:: fichier'), 1, 0, 0, 1],
'mime' => [$this->app->trans('report:: type'), 1, 0, 1, 1],
'size' => [$this->app->trans('report:: taille'), 1, 0, 1, 1]
], $conf_pref);
if ($request->request->get('printcsv') == 'on') {
$document->setHasLimit(false);
$document->setPrettyString(false);
$this->doReport($request, $document, $conf, 'record_id');
$r = $this->getCSVResponse($document, 'documents');
return $r;
}
$report = $this->doReport($request, $document, $conf, 'record_id');
if ($report instanceof Response) {
return $report;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => true
]),
'display_nav' => $report['display_nav'], // do we display the prev and next button ?
'next' => $report['next_page'], //Number of the next page
'prev' => $report['previous_page'], //Number of the previoous page
'page' => $report['page'], //The current page
'filter' => ((sizeof($report['filter']) > 0) ? serialize($report['filter']) : ''), //the serialized filters
'col' => $report['active_column'], //all the columns where a filter is applied
'limit' => $report['nb_record']
]);
}
/**
* Display information about client (browser, resolution etc ...)
*
* @param Request $request
* @return JsonResponse
*/
public function doReportClients(Request $request)
{
$nav = new \module_report_nav(
$this->app,
$request->request->get('dmin'),
$request->request->get('dmax'),
$request->request->get('sbasid'),
$request->request->get('collection')
);
$conf_nav = [
'nav' => [$this->app->trans('report:: navigateur'), 0, 1, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0],
'pourcent' => [$this->app->trans('report:: pourcentage'), 0, 0, 0, 0]
];
$conf_combo = [
'combo' => [$this->app->trans('report:: navigateurs et plateforme'), 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0],
'pourcent' => [$this->app->trans('report:: pourcentage'), 0, 0, 0, 0]
];
$conf_os = [
'os' => [$this->app->trans('report:: plateforme'), 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0],
'pourcent' => [$this->app->trans('report:: pourcentage'), 0, 0, 0, 0]
];
$conf_res = [
'res' => [$this->app->trans('report:: resolution'), 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0],
'pourcent' => [$this->app->trans('report:: pourcentage'), 0, 0, 0, 0]
];
$conf_mod = [
'appli' => [$this->app->trans('report:: module'), 0, 0, 0, 0],
'nb' => [$this->app->trans('report:: nombre'), 0, 0, 0, 0],
'pourcent' => [$this->app->trans('report:: pourcentage'), 0, 0, 0, 0]
];
$report = [
'nav' => $nav->buildTabNav($conf_nav),
'os' => $nav->buildTabOs($conf_os),
'res' => $nav->buildTabRes($conf_res),
'mod' => $nav->buildTabModule($conf_mod),
'combo' => $nav->buildTabCombo($conf_combo)
];
if ($request->request->get('printcsv') == 'on') {
$result = [];
$result[] = array_keys($conf_nav);
foreach ($report['nav']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_os);
foreach ($report['os']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_res);
foreach ($report['res']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_mod);
foreach ($report['mod']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_combo);
foreach ($report['combo']['result'] as $row) {
$result[] = array_values($row);
};
/** @var Exporter $exporter */
$exporter = $this->app['csv.exporter'];
$filename = sprintf('report_export_info_%s.csv', date('Ymd'));
$response = new CSVFileResponse($filename, function () use ($exporter, $result) {
$exporter->export('php://output', $result);
});
return $response;
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($report['report']) ? $report['report'] : $report,
'is_infouser' => false,
'is_nav' => true,
'is_groupby' => false,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => false,
'title' => false
]);
}
/**
* Set Report configuration according to request parameters
*
* @param Request $request A request instance
* @param \module_report $report A report instance
* @param Array $conf A report column configuration
* @param Boolean $what Whether to group on a particular field or not
* @return Array
*/
private function doReport(Request $request, \module_report $report, $conf, $what = false)
{
if ($this->getConf()->get(['registry', 'modules', 'anonymous-report']) == true) {
if (isset($conf['user'])) {
unset($conf['user']);
}
if (isset($conf['ip'])) {
unset($conf['ip']);
}
}
//save initial conf
$base_conf = $conf;
//format conf according user preferences
if ('' !== $columnsList = $request->request->get('list_column', '')) {
$new_conf = $conf;
$columns = explode(',', $columnsList);
foreach (array_keys($conf) as $col) {
if (!in_array($col, $columns)) {
unset($new_conf[$col]);
}
}
$conf = $new_conf;
}
//display content of a table column when user click on it
if ($request->request->get('conf') == 'on') {
return $this->app->json(['liste' => $this->render('report/listColumn.html.twig', [
'conf' => $base_conf
]), 'title' => $this->app->trans('configuration')]);
}
//set order
if (('' !== $order = $request->request->get('order', '')) && ('' !== $field = $request->request->get('champ', ''))) {
$report->setOrder($field, $order);
}
//work on filters
$mapColumnTitleToSqlField = $report->getTransQueryString();
$currentfilter = [];
if ('' !== $serializedFilter = $request->request->get('liste_filter', '')) {
$currentfilter = @unserialize(urldecode($serializedFilter));
}
$filter = new \module_report_filter($this->app, $currentfilter, $mapColumnTitleToSqlField);
if ('' !== $filterColumn = $request->request->get('filter_column', '')) {
$field = current(explode(' ', $filterColumn));
$value = $request->request->get('filter_value', '');
if ($request->request->get('liste') == 'on') {
return $this->app->json(['diag' => $this->render('report/colFilter.html.twig', [
'result' => $report->colFilter($field),
'field' => $field
]), 'title' => $this->app->trans('filtrer les resultats sur la colonne %colonne%', ['%colonne%' => $field])]);
}
if ($field === $value) {
$filter->removeFilter($field);
} else {
$filter->addFilter($field, '=', $value);
}
}
//set new request filter if user asking for them
if ($request->request->get('precise') == 1) {
$filter->addFilter('xml', 'LIKE', $request->request->get('word', ''));
} elseif ($request->request->get('precise') == 2) {
$filter->addFilter('record_id', '=', $request->request->get('word', ''));
}
//set filters to current report
$report->setFilter($filter->getTabFilter());
$report->setActiveColumn($filter->getActiveColumn());
$report->setPostingFilter($filter->getPostingFilter());
// display a new arraywhere results are group
if ('' !== $groupby = $request->request->get('groupby', '')) {
$report->setConfig(false);
$groupby = current(explode(' ', $groupby));
$reportArray = $report->buildReport(false, $groupby);
if (count($reportArray['allChamps']) > 0 && count($reportArray['display']) > 0) {
$groupField = isset($reportArray['display'][$reportArray['allChamps'][0]]['title']) ? $reportArray['display'][$reportArray['allChamps'][0]]['title'] : '';
} else {
$groupField = isset($conf[strtolower($groupby)]['title']) ? $conf[strtolower($groupby)]['title'] : '';
}
return $this->app->json([
'rs' => $this->render('report/ajax_data_content.html.twig', [
'result' => isset($reportArray['report']) ? $reportArray['report'] : $reportArray,
'is_infouser' => false,
'is_nav' => false,
'is_groupby' => true,
'is_plot' => false,
'is_doc' => false
]),
'display_nav' => false,
'title' => $this->app->trans('Groupement des resultats sur le champ %name%', ['%name%' => $groupField])
]);
}
//set Limit
if ($report->getEnableLimit()
&& ('' !== $page = $request->request->get('page', ''))
&& ('' !== $limit = $request->request->get('limit', ''))) {
$report->setLimit($page, $limit);
} else {
$report->setLimit(false, false);
}
//time to build our report
if (false === $what) {
$reportArray = $report->buildReport($conf);
} else {
$reportArray = $report->buildReport($conf, $what, $request->request->get('tbl', false));
}
return $reportArray;
}
/**
* Prefix the method to call with the controller class name
*
* @param string $method The method to call
* @return string
*/
private function call($method)
{
return sprintf('%s::%s', __CLASS__, $method);
}
private function getCSVResponse(\module_report $report, $type)
{
// set headers
$headers = [];
foreach (array_keys($report->getDisplay()) as $k) {
$headers[$k] = $k;
}
// set headers as first row
$result = $report->getResult();
array_unshift($result, $headers);
$collection = new CallbackCollection($result, function ($row) use ($headers) {
// restrict fields to the displayed ones
// return array_map("strip_tags", array_intersect_key($row, $report->getDisplay()));
$ret = array();
foreach($headers as $f) {
$ret[$f] = array_key_exists($f, $row) ? strip_tags($row[$f]) : '';
}
return $ret;
});
$filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
/** @var Exporter $exporter */
$exporter = $this->app['csv.exporter'];
$cb = function () use ($exporter, $collection) {
$exporter->export('php://output', $collection);
};
$response = new CSVFileResponse($filename, $cb);
return $response;
}
} }

View File

@@ -1426,12 +1426,7 @@ class ThesaurusXmlHttpController extends Controller
public function searchTermJson(Request $request) public function searchTermJson(Request $request)
{ {
if (null === $lng = $request->get('lng')) { $lng = $request->get('lng');
$data = explode('_', $this->app['locale']);
if (count($data) > 0) {
$lng = $data[0];
}
}
$html = ''; $html = '';
$sbid = (int) $request->get('sbid'); $sbid = (int) $request->get('sbid');
@@ -1485,7 +1480,10 @@ class ThesaurusXmlHttpController extends Controller
$q2 .= ' and starts-with(@k, \'' . \thesaurus::xquery_escape($unicode->remove_indexer_chars($t[1])) . '\')'; $q2 .= ' and starts-with(@k, \'' . \thesaurus::xquery_escape($unicode->remove_indexer_chars($t[1])) . '\')';
} }
$q2 .= ' and @lng=\'' . \thesaurus::xquery_escape($lng) . '\''; if($lng != null){
$q2 .= ' and @lng=\'' . \thesaurus::xquery_escape($lng) . '\'';
}
$q .= ('//sy[' . $q2 . ']'); $q .= ('//sy[' . $q2 . ']');
$nodes = $xpath->query($q); $nodes = $xpath->query($q);

View File

@@ -88,8 +88,6 @@ class ControllerProviderServiceProvider implements ServiceProviderInterface
Prod\Upload::class => [], Prod\Upload::class => [],
Prod\UsrLists::class => [], Prod\UsrLists::class => [],
Prod\WorkZone::class => [], Prod\WorkZone::class => [],
Report\Activity::class => [],
Report\Information::class => [],
Report\Root::class => [], Report\Root::class => [],
Root\Account::class => [], Root\Account::class => [],
Root\Developers::class => [], Root\Developers::class => [],

View File

@@ -1,81 +0,0 @@
<?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\ControllerProvider\Report;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\Report\ActivityController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Silex\ServiceProviderInterface;
class Activity implements ControllerProviderInterface, ServiceProviderInterface
{
use ControllerProviderTrait;
public function register(Application $app)
{
$app['controller.report.activity'] = $app->share(function (PhraseaApplication $app) {
return new ActivityController($app);
});
}
public function boot(Application $app)
{
// no-op
}
public function connect(Application $app)
{
$controllers = $this->createAuthenticatedCollection($app);
$firewall = $this->getFirewall($app);
$controllers->before(function () use ($firewall) {
$firewall->requireAccessToModule('report');
});
$controllers->post('/users/connexions', 'controller.report.activity:doReportConnexionsByUsers')
->bind('report_activity_users_connexions');
$controllers->post('/users/downloads', 'controller.report.activity:doReportDownloadsByUsers')
->bind('report_activity_users_downloads');;
$controllers->post('/questions/best-of', 'controller.report.activity:doReportBestOfQuestions')
->bind('report_activity_questions_bestof');
$controllers->post('/questions/no-best-of', 'controller.report.activity:doReportNoBestOfQuestions')
->bind('report_activity_questions_nobestof');
$controllers->post('/instance/hours', 'controller.report.activity:doReportSiteActiviyPerHours')
->bind('report_activity_instance_hours');
$controllers->post('/instance/days', 'controller.report.activity:doReportSiteActivityPerDays')
->bind('report_activity_instance_days');
$controllers->post('/documents/pushed', 'controller.report.activity:doReportPushedDocuments')
->bind('report_activity_documents_pushed');
$controllers->post('/documents/added', 'controller.report.activity:doReportAddedDocuments')
->bind('report_activity_documents_added');
$controllers->post('/documents/edited', 'controller.report.activity:doReportEditedDocuments')
->bind('report_activity_documents_edited');
$controllers->post('/documents/validated', 'controller.report.activity:doReportValidatedDocuments')
->bind('report_activity_documents_validated');
$controllers->post('/documents/sent', 'controller.report.activity:doReportSentDocuments')
->bind('report_activity_documents_sent');
return $controllers;
}
}

View File

@@ -1,57 +0,0 @@
<?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\ControllerProvider\Report;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\Report\InformationController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Silex\ServiceProviderInterface;
class Information implements ControllerProviderInterface, ServiceProviderInterface
{
use ControllerProviderTrait;
public function register(Application $app)
{
$app['controller.report.information'] = $app->share(function (PhraseaApplication $app) {
return new InformationController($app);
});
}
public function boot(Application $app)
{
// no-op
}
public function connect(Application $app)
{
$controllers = $this->createAuthenticatedCollection($app);
$firewall = $this->getFirewall($app);
$controllers->before(function () use ($firewall) {
$firewall->requireAccessToModule('report');
});
$controllers->post('/user', 'controller.report.information:doReportInformationUser')
->bind('report_infomations_user');
$controllers->post('/browser', 'controller.report.information:doReportInformationBrowser')
->bind('report_infomations_browser');
$controllers->post('/document', 'controller.report.information:doReportInformationDocument')
->bind('report_infomations_document');
return $controllers;
}
}

View File

@@ -16,7 +16,7 @@ class Version
/** /**
* @var string * @var string
*/ */
private $number = '4.1.0-alpha.13'; private $number = '4.1.0-alpha.14a';
/** /**
* @var string * @var string

View File

@@ -201,6 +201,8 @@ class FilesystemService
return 'ogg'; return 'ogg';
case 'libmp3lame': case 'libmp3lame':
return 'mp3'; return 'mp3';
case 'pcm_s16le':
return 'wav';
} }
return null; return null;

View File

@@ -19,6 +19,7 @@ class Audio extends Provider
const OPTION_THREADS = 'threads'; const OPTION_THREADS = 'threads';
const OPTION_ACODEC = 'acodec'; const OPTION_ACODEC = 'acodec';
const OPTION_AUDIOSAMPLERATE = 'audiosamplerate'; const OPTION_AUDIOSAMPLERATE = 'audiosamplerate';
const OPTION_AUDIOCHANNEL = 'audiochannel';
public function __construct(TranslatorInterface $translator) public function __construct(TranslatorInterface $translator)
{ {
@@ -29,9 +30,12 @@ class Audio extends Provider
47250, 48000, 50000, 50400, 88200, 96000 47250, 48000, 50000, 50400, 88200, 96000
]; ];
$audioChannel = ['mono', 'stereo'];
$this->registerOption(new OptionType\Range($this->translator->trans('Audio Birate'), self::OPTION_AUDIOBITRATE, 32, 320, 128, 32)); $this->registerOption(new OptionType\Range($this->translator->trans('Audio Birate'), self::OPTION_AUDIOBITRATE, 32, 320, 128, 32));
$this->registerOption(new OptionType\Enum($this->translator->trans('AudioSamplerate'), self::OPTION_AUDIOSAMPLERATE, $AVaudiosamplerate)); $this->registerOption(new OptionType\Enum($this->translator->trans('AudioSamplerate'), self::OPTION_AUDIOSAMPLERATE, $AVaudiosamplerate));
$this->registerOption(new OptionType\Enum($this->translator->trans('Audio Codec'), self::OPTION_ACODEC, ['libmp3lame', 'flac'], 'libmp3lame')); $this->registerOption(new OptionType\Enum($this->translator->trans('Audio Codec'), self::OPTION_ACODEC, ['libmp3lame', 'flac', 'pcm_s16le'], 'libmp3lame'));
$this->registerOption(new OptionType\Enum($this->translator->trans('Audio channel'), self::OPTION_AUDIOCHANNEL, $audioChannel));
} }
public function getType() public function getType()
@@ -53,7 +57,21 @@ class Audio extends Provider
$this->spec->setAudioCodec($this->getOption(self::OPTION_ACODEC)->getValue()); $this->spec->setAudioCodec($this->getOption(self::OPTION_ACODEC)->getValue());
$this->spec->setAudioSampleRate($this->getOption(self::OPTION_AUDIOSAMPLERATE)->getValue()); $this->spec->setAudioSampleRate($this->getOption(self::OPTION_AUDIOSAMPLERATE)->getValue());
$this->spec->setAudioKiloBitrate($this->getOption(self::OPTION_AUDIOBITRATE)->getValue()); $this->spec->setAudioKiloBitrate($this->getOption(self::OPTION_AUDIOBITRATE)->getValue());
$this->spec->setAudioChannels($this->getChannelNumber($this->getOption(self::OPTION_AUDIOCHANNEL)->getValue()));
return $this->spec; return $this->spec;
} }
private function getChannelNumber($audioChannel)
{
switch($audioChannel)
{
case 'mono':
return 1;
case 'stereo':
return 2;
default:
return null;
}
}
} }

View File

@@ -9,6 +9,7 @@
*/ */
namespace Alchemy\Phrasea\Report\Controller; namespace Alchemy\Phrasea\Report\Controller;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Report\Report; use Alchemy\Phrasea\Report\Report;
use Alchemy\Phrasea\Report\ReportConnections; use Alchemy\Phrasea\Report\ReportConnections;
use Alchemy\Phrasea\Report\ReportDownloads; use Alchemy\Phrasea\Report\ReportDownloads;
@@ -16,10 +17,11 @@ use Alchemy\Phrasea\Report\ReportFactory;
use Alchemy\Phrasea\Report\ReportRecords; use Alchemy\Phrasea\Report\ReportRecords;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse; use Symfony\Component\HttpFoundation\StreamedResponse;
class ProdReportController class ProdReportController extends Controller
{ {
private static $mapFromExtension = [ private static $mapFromExtension = [
'csv' => [ 'csv' => [
@@ -55,6 +57,19 @@ class ProdReportController
$this->acl = $acl; $this->acl = $acl;
} }
/**
* route prod/report/connections
*
* @param Request $request
* @return Response
*/
public function indexAction(Request $request)
{
return new Response($this->render('prod/report/index.html.twig', [
'truc' => "hello"
]));
}
/** /**
* route prod/report/connections * route prod/report/connections
* *

View File

@@ -85,22 +85,26 @@ class ApiReportControllerProvider extends Api implements ControllerProviderInter
$controllers->before(new OAuthListener()); $controllers->before(new OAuthListener());
$controllers $controllers
->get('/', 'controller.api.v2.report:rootAction') ->match('/', 'controller.api.v2.report:rootAction')
->method('GET|POST')
; ;
$controllers $controllers
->get('/connections/{sbasId}/', 'controller.api.v2.report:connectionsAction') ->match('/connections/{sbasId}/', 'controller.api.v2.report:connectionsAction')
->assert('sbasId', '\d+') ->assert('sbasId', '\d+')
->method('GET|POST')
; ;
$controllers $controllers
->get('/downloads/{sbasId}/', 'controller.api.v2.report:downloadsAction') ->match('/downloads/{sbasId}/', 'controller.api.v2.report:downloadsAction')
->assert('sbasId', '\d+') ->assert('sbasId', '\d+')
->method('GET|POST')
; ;
$controllers $controllers
->get('/records/{sbasId}/', 'controller.api.v2.report:recordsAction') ->match('/records/{sbasId}/', 'controller.api.v2.report:recordsAction')
->assert('sbasId', '\d+') ->assert('sbasId', '\d+')
->method('GET|POST')
; ;
return $controllers; return $controllers;

View File

@@ -58,20 +58,26 @@ class ProdReportControllerProvider implements ControllerProviderInterface, Servi
public function connect(Application $app) public function connect(Application $app)
{ {
$controllers = $this->createAuthenticatedCollection($app); $controllers = $this->createAuthenticatedCollection($app);
$controllers $controllers
->get('/connections/{sbasId}/', 'controller.prod.report:connectionsAction') ->match('/connections/{sbasId}/', 'controller.prod.report:connectionsAction')
->assert('sbasId', '\d+') ->assert('sbasId', '\d+')
->bind('report2_connections')
->method('GET|POST')
; ;
$controllers $controllers
->get('/downloads/{sbasId}/', 'controller.prod.report:downloadsAction') ->match('/downloads/{sbasId}/', 'controller.prod.report:downloadsAction')
->assert('sbasId', '\d+') ->assert('sbasId', '\d+')
->bind('report2_downloads')
->method('GET|POST')
; ;
$controllers $controllers
->get('/records/{sbasId}/', 'controller.prod.report:recordsAction') ->match('/records/{sbasId}/', 'controller.prod.report:recordsAction')
->assert('sbasId', '\d+') ->assert('sbasId', '\d+')
->bind('report2_records')
->method('GET|POST')
; ;
return $controllers; return $controllers;

View File

@@ -72,8 +72,6 @@ class ReportRecords extends Report
. " AND r.record_id >= " . $row['from'] . " AND r.record_id <= " . $row['to'] . "\n" . " AND r.record_id >= " . $row['from'] . " AND r.record_id <= " . $row['to'] . "\n"
. "GROUP BY `record_id`\n"; . "GROUP BY `record_id`\n";
// file_put_contents("/tmp/phraseanet-log.txt", sprintf("%s (%d) %s\n", __FILE__, __LINE__, var_export($sql, true)), FILE_APPEND);
$stmt = $this->databox->get_connection()->executeQuery($sql, []); $stmt = $this->databox->get_connection()->executeQuery($sql, []);
$rows = $stmt->fetchAll(); $rows = $stmt->fetchAll();
$stmt->closeCursor(); $stmt->closeCursor();

View File

@@ -619,6 +619,8 @@ class ElasticSearchEngine implements SearchEngineInterface
foreach ($context->getHighlightedFields() as $field) { foreach ($context->getHighlightedFields() as $field) {
switch ($field->getType()) { switch ($field->getType()) {
case FieldMapping::TYPE_STRING: case FieldMapping::TYPE_STRING:
case FieldMapping::TYPE_DOUBLE:
case FieldMapping::TYPE_DATE:
$index_field = $field->getIndexField(); $index_field = $field->getIndexField();
$raw_index_field = $field->getIndexField(true); $raw_index_field = $field->getIndexField(true);
$highlighted_fields[$index_field . ".light"] = [ $highlighted_fields[$index_field . ".light"] = [
@@ -628,13 +630,10 @@ class ElasticSearchEngine implements SearchEngineInterface
]; ];
break; break;
case FieldMapping::TYPE_FLOAT: case FieldMapping::TYPE_FLOAT:
case FieldMapping::TYPE_DOUBLE:
case FieldMapping::TYPE_INTEGER: case FieldMapping::TYPE_INTEGER:
case FieldMapping::TYPE_LONG: case FieldMapping::TYPE_LONG:
case FieldMapping::TYPE_SHORT: case FieldMapping::TYPE_SHORT:
case FieldMapping::TYPE_BYTE: case FieldMapping::TYPE_BYTE:
continue;
case FieldMapping::TYPE_DATE:
default: default:
continue; continue;
} }
@@ -660,7 +659,7 @@ class ElasticSearchEngine implements SearchEngineInterface
} }
$agg = [ $agg = [
'terms' => [ 'terms' => [
'field' => $f['field'], 'field' => $f['esfield'],
'size' => $size 'size' => $size
] ]
]; ];

View File

@@ -256,42 +256,56 @@ class ElasticsearchOptions
{ {
return [ return [
'base_aggregate' => [ 'base_aggregate' => [
'label' => 'prod::facet:base_label', 'type' => 'string',
'field' => 'databox_name', 'label' => 'prod::facet:base_label',
'query' => 'database:%s', 'field' => "database",
'esfield' => 'databox_name',
'query' => 'database:%s',
], ],
'collection_aggregate' => [ 'collection_aggregate' => [
'label' => 'prod::facet:collection_label', 'type' => 'string',
'field' => 'collection_name', 'label' => 'prod::facet:collection_label',
'query' => 'collection:%s', 'field' => "collection",
'esfield' => 'collection_name',
'query' => 'collection:%s',
], ],
'doctype_aggregate' => [ 'doctype_aggregate' => [
'label' => 'prod::facet:doctype_label', 'type' => 'string',
'field' => 'type', 'label' => 'prod::facet:doctype_label',
'query' => 'type:%s', 'field' => "type",
'esfield' => 'type',
'query' => 'type:%s',
], ],
'camera_model_aggregate' => [ 'camera_model_aggregate' => [
'label' => 'Camera Model', 'type' => 'string',
'field' => 'metadata_tags.CameraModel', 'label' => 'Camera Model',
'query' => 'meta.CameraModel:%s', 'field' => "meta.CameraModel",
'esfield' => 'metadata_tags.CameraModel',
'query' => 'meta.CameraModel:%s',
], ],
'iso_aggregate' => [ 'iso_aggregate' => [
'label' => 'ISO', 'type' => 'number',
'field' => 'metadata_tags.ISO', 'label' => 'ISO',
'query' => 'meta.ISO=%s', 'field' => "meta.ISO",
'esfield' => 'metadata_tags.ISO',
'query' => 'meta.ISO=%s',
], ],
'aperture_aggregate' => [ 'aperture_aggregate' => [
'label' => 'Aperture', 'type' => 'number',
'field' => 'metadata_tags.Aperture', 'label' => 'Aperture',
'query' => 'meta.Aperture=%s', 'field' => "meta.Aperture",
'esfield' => 'metadata_tags.Aperture',
'query' => 'meta.Aperture=%s',
'output_formatter' => function($value) { 'output_formatter' => function($value) {
return round($value, 1); return round($value, 1);
}, },
], ],
'shutterspeed_aggregate' => [ 'shutterspeed_aggregate' => [
'label' => 'Shutter speed', 'type' => 'number',
'field' => 'metadata_tags.ShutterSpeed', 'label' => 'Shutter speed',
'query' => 'meta.ShutterSpeed=%s', 'field' => "meta.ShutterSpeed",
'esfield' => 'metadata_tags.ShutterSpeed',
'query' => 'meta.ShutterSpeed=%s',
'output_formatter' => function($value) { 'output_formatter' => function($value) {
if($value < 1.0 && $value != 0) { if($value < 1.0 && $value != 0) {
$value = '1/' . round(1.0 / $value); $value = '1/' . round(1.0 / $value);
@@ -300,9 +314,11 @@ class ElasticsearchOptions
}, },
], ],
'flashfired_aggregate' => [ 'flashfired_aggregate' => [
'label' => 'FlashFired', 'type' => 'boolean',
'field' => 'metadata_tags.FlashFired', 'label' => 'FlashFired',
'query' => 'meta.FlashFired=%s', 'field' => "meta.FlashFired",
'esfield' => 'metadata_tags.FlashFired',
'query' => 'meta.FlashFired=%s',
'choices' => [ 'choices' => [
"aggregated (2 values: fired = 0 or 1)" => -1, "aggregated (2 values: fired = 0 or 1)" => -1,
], ],
@@ -312,39 +328,53 @@ class ElasticsearchOptions
}, },
], ],
'framerate_aggregate' => [ 'framerate_aggregate' => [
'label' => 'FrameRate', 'type' => 'number',
'field' => 'metadata_tags.FrameRate', 'label' => 'FrameRate',
'query' => 'meta.FrameRate=%s', 'field' => "meta.FrameRate",
'esfield' => 'metadata_tags.FrameRate',
'query' => 'meta.FrameRate=%s',
], ],
'audiosamplerate_aggregate' => [ 'audiosamplerate_aggregate' => [
'label' => 'Audio Samplerate', 'type' => 'number',
'field' => 'metadata_tags.AudioSamplerate', 'label' => 'Audio Samplerate',
'query' => 'meta.AudioSamplerate=%s', 'field' => "meta.AudioSamplerate",
'esfield' => 'metadata_tags.AudioSamplerate',
'query' => 'meta.AudioSamplerate=%s',
], ],
'videocodec_aggregate' => [ 'videocodec_aggregate' => [
'label' => 'Video codec', 'type' => 'string',
'field' => 'metadata_tags.VideoCodec', 'label' => 'Video codec',
'query' => 'meta.VideoCodec:%s', 'field' => "meta.VideoCodec",
'esfield' => 'metadata_tags.VideoCodec',
'query' => 'meta.VideoCodec:%s',
], ],
'audiocodec_aggregate' => [ 'audiocodec_aggregate' => [
'label' => 'Audio codec', 'type' => 'string',
'field' => 'metadata_tags.AudioCodec', 'label' => 'Audio codec',
'query' => 'meta.AudioCodec:%s', 'field' => "meta.AudioCodec",
'esfield' => 'metadata_tags.AudioCodec',
'query' => 'meta.AudioCodec:%s',
], ],
'orientation_aggregate' => [ 'orientation_aggregate' => [
'label' => 'Orientation', 'type' => 'string',
'field' => 'metadata_tags.Orientation', 'label' => 'Orientation',
'query' => 'meta.Orientation=%s', 'field' => "meta.Orientation",
'esfield' => 'metadata_tags.Orientation',
'query' => 'meta.Orientation=%s',
], ],
'colorspace_aggregate' => [ 'colorspace_aggregate' => [
'label' => 'Colorspace', 'type' => 'string',
'field' => 'metadata_tags.ColorSpace', 'label' => 'Colorspace',
'query' => 'meta.ColorSpace:%s', 'field' => "meta.ColorSpace",
'esfield' => 'metadata_tags.ColorSpace',
'query' => 'meta.ColorSpace:%s',
], ],
'mimetype_aggregate' => [ 'mimetype_aggregate' => [
'label' => 'MimeType', 'type' => 'string',
'field' => 'metadata_tags.MimeType', 'label' => 'MimeType',
'query' => 'meta.MimeType:%s', 'field' => "meta.MimeType",
'esfield' => 'metadata_tags.MimeType',
'query' => 'meta.MimeType:%s',
], ],
]; ];
} }

View File

@@ -127,20 +127,21 @@ class Fetcher
private function getExecutedStatement() private function getExecutedStatement()
{ {
if (!$this->statement) { if (!$this->statement) {
$sql = "SELECT r.record_id" $sql = "SELECT r.*, c.asciiname AS collection_name, subdef.width, subdef.height, subdef.size\n"
. ", r.coll_id AS collection_id" . " FROM ((\n"
. ", c.asciiname AS collection_name" . " SELECT r.record_id, r.coll_id AS collection_id, r.uuid, r.status AS flags_bitfield, r.sha256,\n"
. ", r.uuid" . " r.originalname AS original_name, r.mime, r.type, r.parent_record_id,\n"
. ", r.status AS flags_bitfield" . " r.credate AS created_on, r.moddate AS updated_on, r.coll_id\n"
. ", r.sha256" // -- TODO rename in "hash" . " FROM record r\n"
. ", r.originalname AS original_name" . " -- WHERE\n"
. ", r.mime, r.type, r.parent_record_id, r.credate AS created_on, r.moddate AS updated_on" . " ORDER BY " . $this->options->getPopulateOrderAsSQL() . " " . $this->options->getPopulateDirectionAsSQL() . "\n"
. ", subdef.width, subdef.height, subdef.size" . " LIMIT :offset, :limit\n"
. " FROM (record r INNER JOIN coll c ON (c.coll_id = r.coll_id))" . " ) AS r\n"
. " LEFT JOIN subdef ON subdef.record_id=r.record_id AND subdef.name='document'" . " INNER JOIN coll c ON (c.coll_id = r.coll_id)\n"
. " -- WHERE" . " )\n"
. " ORDER BY " . $this->options->getPopulateOrderAsSQL() . " " . $this->options->getPopulateDirectionAsSQL() . " LEFT JOIN\n"
. " LIMIT :offset, :limit"; . " subdef ON subdef.record_id=r.record_id AND subdef.name='document'\n"
. " ORDER BY " . $this->options->getPopulateOrderAsSQL() . " " . $this->options->getPopulateDirectionAsSQL() . "";
$where = $this->delegate->buildWhereClause(); $where = $this->delegate->buildWhereClause();
$sql = str_replace('-- WHERE', $where, $sql); $sql = str_replace('-- WHERE', $where, $sql);

View File

@@ -0,0 +1,75 @@
<?php
/*
* This file is part of phrasea-4.0.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
class DoubleFieldMapping extends ComplexFieldMapping
{
/**
* @var bool
*/
private $enableAnalysis = true;
/**
* @var string|null
*/
private $analyzer = null;
/**
* @var string|null
*/
private $termVector = null;
/**
* @param string $name
*/
public function __construct($name)
{
parent::__construct($name, self::TYPE_DOUBLE);
}
public function disableAnalysis()
{
$this->enableAnalysis = false;
return $this;
}
public function enableAnalysis()
{
$this->enableAnalysis = true;
return $this;
}
/**
* @return array
*/
protected function getProperties()
{
$properties = [];
if ($this->analyzer) {
$properties['analyzer'] = $this->analyzer;
}
if (! $this->enableAnalysis) {
$properties['index'] = 'not_analyzed';
}
if ($this->termVector) {
$properties['term_vector'] = $this->termVector;
}
return array_replace(parent::getProperties(), $properties);
}
}

View File

@@ -19,28 +19,55 @@ class FieldToFieldMappingConverter
public function convertField(Field $field, array $locales) public function convertField(Field $field, array $locales)
{ {
if ($field->getType() === FieldMapping::TYPE_DATE) { $ret = null;
return new DateFieldMapping($field->getName(), FieldMapping::DATE_FORMAT_CAPTION); switch($field->getType()) {
case FieldMapping::TYPE_DATE:
$ret = new DateFieldMapping($field->getName(), FieldMapping::DATE_FORMAT_MYSQL_OR_CAPTION);
if (! $field->isFacet() && ! $field->isSearchable()) {
$ret->disableIndexing();
}
else {
$ret->addChild(
(new StringFieldMapping('light'))
->setAnalyzer('general_light')
->enableTermVectors()
);
}
break;
case FieldMapping::TYPE_STRING:
$ret = new StringFieldMapping($field->getName());
if (! $field->isFacet() && ! $field->isSearchable()) {
$ret->disableIndexing();
}
else {
$ret->addChild(
(new StringFieldMapping('raw'))
->enableRawIndexing());
$ret->addAnalyzedChildren($locales);
$ret->enableTermVectors(true);
}
break;
case FieldMapping::TYPE_DOUBLE:
$ret = new DoubleFieldMapping($field->getName());
if (! $field->isFacet() && ! $field->isSearchable()) {
$ret->disableIndexing();
}
else {
$ret->addChild(
(new StringFieldMapping('light'))
->setAnalyzer('general_light')
->enableTermVectors()
);
}
break;
default:
$ret = new FieldMapping($field->getName(), $field->getType());
break;
} }
if ($field->getType() === FieldMapping::TYPE_STRING) { return $ret;
$fieldMapping = new StringFieldMapping($field->getName());
if (! $field->isFacet() && ! $field->isSearchable()) {
$fieldMapping->disableIndexing();
} else {
$fieldMapping->addChild((new StringFieldMapping('raw'))->enableRawIndexing());
$child = new CompletionFieldMapping('suggest');
$fieldMapping->addChild($child);
$fieldMapping->addAnalyzedChildren($locales);
$fieldMapping->enableTermVectors(true);
}
return $fieldMapping;
}
return new FieldMapping($field->getName(), $field->getType());
} }
} }

View File

@@ -4,6 +4,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Exception\RuntimeException;
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions; use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\GlobalStructure;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure; use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion; use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
@@ -14,28 +15,72 @@ class FacetsResponse
private $escaper; private $escaper;
private $facets = array(); private $facets = array();
public function __construct(Escaper $escaper, array $response) public function __construct(Escaper $escaper, array $response, GlobalStructure $structure)
{ {
$this->escaper = $escaper; $this->escaper = $escaper;
if (!isset($response['aggregations'])) { if (!isset($response['aggregations'])) {
return; return;
} }
$atf = ElasticsearchOptions::getAggregableTechnicalFields();
foreach ($response['aggregations'] as $name => $aggregation) { foreach ($response['aggregations'] as $name => $aggregation) {
$tf = null;
$valueFormatter = function($v){ return $v; }; // default equality formatter
if(array_key_exists($name, $atf)) {
$tf = $atf[$name];
if(array_key_exists('output_formatter', $tf)) {
$valueFormatter = $tf['output_formatter'];
}
}
$aggregation = AggregationHelper::unwrapPrivateFieldAggregation($aggregation); $aggregation = AggregationHelper::unwrapPrivateFieldAggregation($aggregation);
if (!isset($aggregation['buckets'])) { if (!isset($aggregation['buckets'])) {
$this->throwAggregationResponseError(); $this->throwAggregationResponseError();
} }
$values = $this->buildBucketsValues($name, $aggregation['buckets']);
if ($values) { $values = [];
$this->facets[] = array( foreach ($aggregation['buckets'] as $bucket) {
if (!isset($bucket['key']) || !isset($bucket['doc_count'])) {
$this->throwAggregationResponseError();
}
if($tf) {
// the field is one of the hardcoded tech fields
$value = [
'value' => $valueFormatter($bucket['key']),
'raw_value' => $bucket['key'],
'count' => $bucket['doc_count'],
'query' => sprintf($tf['query'], $this->escaper->escapeWord($bucket['key']))
];
}
else {
// the field is a normal field
$value = [
'value' => $bucket['key'],
'raw_value' => $bucket['key'],
'count' => $bucket['doc_count'],
'query' => sprintf('field.%s:%s', $this->escaper->escapeWord($name), $this->escaper->escapeWord($bucket['key']))
];
}
$values[] = $value;
}
if (count($values) > 0) {
$this->facets[] = [
// 'type' => $tf ? $tf['type'] : null,
'name' => $name, 'name' => $name,
'field' => $tf ? $tf['field'] : sprintf('field.%s', $name),
'values' => $values, 'values' => $values,
); ];
} }
} }
} }
/** /**
* @return ArrayCollection * @return ArrayCollection
*/ */
@@ -53,44 +98,6 @@ class FacetsResponse
return $suggestions; return $suggestions;
} }
private function buildBucketsValues($name, $buckets)
{
$values = array();
// does this aggregate has an output_formatter ? if not use a equality formatter
/** @var callable $formatter */
$formatter = igorw\get_in(
ElasticsearchOptions::getAggregableTechnicalFields(), [$name, 'output_formatter'],
function($v){return $v;}
);
foreach ($buckets as $bucket) {
if (!isset($bucket['key']) || !isset($bucket['doc_count'])) {
$this->throwAggregationResponseError();
}
$values[] = array(
'value' => $formatter($bucket['key']),
'count' => $bucket['doc_count'],
'query' => $this->buildQuery($name, $bucket['key']),
);
}
return $values;
}
private function buildQuery($name, $value)
{
if(array_key_exists($name, ElasticsearchOptions::getAggregableTechnicalFields())) {
$q = ElasticsearchOptions::getAggregableTechnicalFields()[$name]['query'];
$ret = sprintf($q, $this->escaper->escapeWord($value));
}
else {
$ret = sprintf('field.%s:%s', $this->escaper->escapeWord($name), $this->escaper->escapeWord($value));
}
return $ret;
}
private function throwAggregationResponseError() private function throwAggregationResponseError()
{ {
throw new RuntimeException('Invalid aggregation response'); throw new RuntimeException('Invalid aggregation response');

View File

@@ -107,13 +107,28 @@ class QueryContext
*/ */
public function localizeField(Field $field) public function localizeField(Field $field)
{ {
$ret = null;
$index_field = $field->getIndexField(); $index_field = $field->getIndexField();
if ($field->getType() === FieldMapping::TYPE_STRING) { switch($field->getType()) {
return $this->localizeFieldName($index_field); case FieldMapping::TYPE_STRING:
} else { $ret = $this->localizeFieldName($index_field);
return [$index_field]; break;
case FieldMapping::TYPE_DATE:
case FieldMapping::TYPE_DOUBLE:
$ret = [
$index_field . '.light',
$index_field
];
break;
default:
$ret = [$index_field];
break;
} }
return $ret;
} }
private function localizeFieldName($field) private function localizeFieldName($field)

View File

@@ -89,7 +89,6 @@ class Field implements Typed
case databox_field::TYPE_NUMBER: case databox_field::TYPE_NUMBER:
return FieldMapping::TYPE_DOUBLE; return FieldMapping::TYPE_DOUBLE;
case databox_field::TYPE_STRING: case databox_field::TYPE_STRING:
case databox_field::TYPE_TEXT:
return FieldMapping::TYPE_STRING; return FieldMapping::TYPE_STRING;
} }

View File

@@ -30,14 +30,14 @@ class ValueChecker
case FieldMapping::TYPE_LONG: case FieldMapping::TYPE_LONG:
case FieldMapping::TYPE_SHORT: case FieldMapping::TYPE_SHORT:
case FieldMapping::TYPE_BYTE: case FieldMapping::TYPE_BYTE:
if ($is_numeric) { // if ($is_numeric) {
$filtered[] = $item; $filtered[] = $item;
} // }
break; break;
case FieldMapping::TYPE_DATE: case FieldMapping::TYPE_DATE:
if ($is_valid_date) { // if ($is_valid_date) {
$filtered[] = $item; $filtered[] = $item;
} // }
break; break;
case FieldMapping::TYPE_STRING: case FieldMapping::TYPE_STRING:
default: default:

View File

@@ -60,7 +60,7 @@ class Thesaurus
// TODO Use bulk queries for performance // TODO Use bulk queries for performance
$concepts = array(); $concepts = array();
foreach ($terms as $index => $term) { foreach ($terms as $index => $term) {
$strict = ($term instanceof AST\TermNode); // a "term" node is [strict group of words] $strict |= ($term instanceof AST\TermNode); // a "term" node is [strict group of words]
$concepts[] = $this->findConcepts($term, $lang, $filters[$index], $strict); $concepts[] = $this->findConcepts($term, $lang, $filters[$index], $strict);
} }

View File

@@ -88,7 +88,7 @@ class PhraseanetExtension extends \Twig_Extension
$highlightValue = $highlights[$field]; $highlightValue = $highlights[$field];
// if field is multivalued, merge highlighted values with captions ones // if field is multivalued, merge highlighted values with captions ones
if (is_array($value)) { if (is_array($value) && count($value) > 1) {
$highlightValue = array_merge($highlightValue, array_diff($value, array_map(function($value) { $highlightValue = array_merge($highlightValue, array_diff($value, array_map(function($value) {
return str_replace(array('[[em]]', '[[/em]]'), array('', ''), $value); return str_replace(array('[[em]]', '[[/em]]'), array('', ''), $value);
}, $highlightValue))); }, $highlightValue)));

View File

@@ -537,7 +537,11 @@ class API_OAuth2_Adapter extends OAuth2
public function verifyAccessToken($scope = null, $exit_not_present = true, $exit_invalid = true, $exit_expired = true, $exit_scope = true, $realm = null) public function verifyAccessToken($scope = null, $exit_not_present = true, $exit_invalid = true, $exit_expired = true, $exit_scope = true, $realm = null)
{ {
$token_param = $this->getAccessTokenParams(); $apiTokenHeader = $this->app['conf']->get(['main', 'api_token_header']);
$useTokenHeader = $this->useTokenHeaderChoice($apiTokenHeader);
$token_param = $this->getAccessTokenParams($useTokenHeader);
// Access token was not provided // Access token was not provided
if ($token_param === false) { if ($token_param === false) {
@@ -808,4 +812,21 @@ class API_OAuth2_Adapter extends OAuth2
return false; return false;
} }
} }
/**
* Get the correct constante to call on Oauth2
*
* @param $apiTokenHeader
* @return string
*/
private function useTokenHeaderChoice($apiTokenHeader)
{
if ($apiTokenHeader === true) {
return Oauth2::TOKEN_ONLY_IN_HEADER;
} elseif ($apiTokenHeader === false) {
return Oauth2::TOKEN_ONLY_IN_GETPOST;
} else {
return Oauth2::TOKEN_AUTO_FIND;
}
}
} }

View File

@@ -446,7 +446,6 @@ class databox extends base implements ThumbnailedElement
databox_field::TYPE_DATE databox_field::TYPE_DATE
, databox_field::TYPE_NUMBER , databox_field::TYPE_NUMBER
, databox_field::TYPE_STRING , databox_field::TYPE_STRING
, databox_field::TYPE_TEXT
] ]
) ? $type : databox_field::TYPE_STRING; ) ? $type : databox_field::TYPE_STRING;

View File

@@ -100,7 +100,6 @@ class databox_field implements cache_cacheableInterface
protected $original_dces; protected $original_dces;
protected $aggregable; protected $aggregable;
const TYPE_TEXT = "text";
const TYPE_DATE = "date"; const TYPE_DATE = "date";
const TYPE_STRING = "string"; const TYPE_STRING = "string";
const TYPE_NUMBER = "number"; const TYPE_NUMBER = "number";
@@ -440,6 +439,16 @@ class databox_field implements cache_cacheableInterface
return isset($this->labels[$code]) && '' !== $this->labels[$code] ? $this->labels[$code] : $this->name; return isset($this->labels[$code]) && '' !== $this->labels[$code] ? $this->labels[$code] : $this->name;
} }
/**
* get all localized labels
*
* @return string[]
*/
public function get_labels()
{
return $this->labels;
}
/** /**
* @param string $name * @param string $name
* @return databox_field * @return databox_field

View File

@@ -44,7 +44,7 @@ class databox_subdef
SubdefType::TYPE_DOCUMENT => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_FLEXPAPER, SubdefSpecs::TYPE_PDF], SubdefType::TYPE_DOCUMENT => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_FLEXPAPER, SubdefSpecs::TYPE_PDF],
SubdefType::TYPE_FLASH => [SubdefSpecs::TYPE_IMAGE], SubdefType::TYPE_FLASH => [SubdefSpecs::TYPE_IMAGE],
SubdefType::TYPE_IMAGE => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_PDF], SubdefType::TYPE_IMAGE => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_PDF],
SubdefType::TYPE_VIDEO => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_VIDEO, SubdefSpecs::TYPE_ANIMATION], SubdefType::TYPE_VIDEO => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_VIDEO, SubdefSpecs::TYPE_ANIMATION, SubdefSpecs::TYPE_AUDIO],
SubdefType::TYPE_UNKNOWN => [SubdefSpecs::TYPE_IMAGE], SubdefType::TYPE_UNKNOWN => [SubdefSpecs::TYPE_IMAGE],
]; ];
const CLASS_THUMBNAIL = 'thumbnail'; const CLASS_THUMBNAIL = 'thumbnail';
@@ -156,6 +156,10 @@ class databox_subdef
if ($sd->audiosamplerate) { if ($sd->audiosamplerate) {
$audio->setOptionValue(Audio::OPTION_AUDIOSAMPLERATE, (int) $sd->audiosamplerate); $audio->setOptionValue(Audio::OPTION_AUDIOSAMPLERATE, (int) $sd->audiosamplerate);
} }
if ($sd->audiochannel) {
$audio->setOptionValue(Audio::OPTION_AUDIOCHANNEL, (string) $sd->audiochannel);
}
return $audio; return $audio;
} }
/** /**

View File

@@ -89,6 +89,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
const TYPE_AUDIO_MP3 = 'AUDIO_MP3'; const TYPE_AUDIO_MP3 = 'AUDIO_MP3';
const TYPE_IMAGE = 'IMAGE'; const TYPE_IMAGE = 'IMAGE';
const TYPE_NO_PLAYER = 'UNKNOWN'; const TYPE_NO_PLAYER = 'UNKNOWN';
const TYPE_PDF = 'PDF';
/* /*
* Technical datas types constants * Technical datas types constants
@@ -407,6 +408,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
{ {
static $types = [ static $types = [
'application/x-shockwave-flash' => self::TYPE_FLEXPAPER, 'application/x-shockwave-flash' => self::TYPE_FLEXPAPER,
'application/pdf' => self::TYPE_PDF,
'audio/mp3' => self::TYPE_AUDIO_MP3, 'audio/mp3' => self::TYPE_AUDIO_MP3,
'audio/mpeg' => self::TYPE_AUDIO_MP3, 'audio/mpeg' => self::TYPE_AUDIO_MP3,
'image/gif' => self::TYPE_IMAGE, 'image/gif' => self::TYPE_IMAGE,

View File

@@ -50,6 +50,21 @@ class patch_380alpha3a extends patchAbstract
{ {
$conn = $databox->get_connection(); $conn = $databox->get_connection();
$sql = "CREATE TABLE IF NOT EXISTS `log_colls` (\n"
. " `id` int(11) unsigned NOT NULL AUTO_INCREMENT,\n"
. " `log_id` int(11) unsigned NOT NULL,\n"
. " `coll_id` int(11) unsigned NOT NULL,\n"
. " PRIMARY KEY (`id`),\n"
. " UNIQUE KEY `couple` (`log_id`,`coll_id`),\n"
. " KEY `log_id` (`log_id`),\n"
. " KEY `coll_id` (`coll_id`)\n"
. ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;";
$stmt = $conn->prepare($sql);
$stmt->execute();
$stmt->closeCursor();
unset($stmt);
$removeProc = "DROP PROCEDURE IF EXISTS explode_log_table"; $removeProc = "DROP PROCEDURE IF EXISTS explode_log_table";
$stmt = $conn->prepare($removeProc); $stmt = $conn->prepare($removeProc);

View File

@@ -60,8 +60,14 @@ class patch_410alpha13a implements patchInterface
*/ */
public function apply(base $databox, Application $app) public function apply(base $databox, Application $app)
{ {
// @see : https://phraseanet.atlassian.net/browse/PHRAS-2468
// to be able to migrate from 3.5 to 4.0.8, we must not delete the table anymore
// so the cli "bin/setup patch:log_coll_id" can be executed.
/*
$sql = "DROP TABLE IF EXISTS `log_colls`"; $sql = "DROP TABLE IF EXISTS `log_colls`";
$databox->get_connection()->prepare($sql)->execute(); $databox->get_connection()->prepare($sql)->execute();
*/
/* /*
* no need to do those ops, it's done by system:upgrade after fixing the xml scheme * no need to do those ops, it's done by system:upgrade after fixing the xml scheme

View File

@@ -0,0 +1,64 @@
<?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.
*/
use Alchemy\Phrasea\Application;
class patch_410alpha13b implements patchInterface
{
/** @var string */
private $release = '4.1.0-alpha.13b';
/** @var array */
private $concern = [base::DATA_BOX];
/**
* {@inheritdoc}
*/
public function get_release()
{
return $this->release;
}
/**
* {@inheritdoc}
*/
public function getDoctrineMigrations()
{
return [];
}
/**
* {@inheritdoc}
*/
public function require_all_upgrades()
{
return false;
}
/**
* {@inheritdoc}
*/
public function concern()
{
return $this->concern;
}
/**
* {@inheritdoc}
*/
public function apply(base $databox, Application $app)
{
$sql = "UPDATE `log_docs` SET `coll_id`=`final` WHERE `action`='collection'";
$databox->get_connection()->prepare($sql)->execute();
return true;
}
}

View File

@@ -0,0 +1,64 @@
<?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.
*/
use Alchemy\Phrasea\Application;
class patch_410alpha14a implements patchInterface
{
/** @var string */
private $release = '4.1.0-alpha.14a';
/** @var array */
private $concern = [base::DATA_BOX];
/**
* {@inheritdoc}
*/
public function get_release()
{
return $this->release;
}
/**
* {@inheritdoc}
*/
public function getDoctrineMigrations()
{
return [];
}
/**
* {@inheritdoc}
*/
public function require_all_upgrades()
{
return false;
}
/**
* {@inheritdoc}
*/
public function concern()
{
return $this->concern;
}
/**
* {@inheritdoc}
*/
public function apply(base $databox, Application $app)
{
$sql = "UPDATE metadatas_structure SET type = 'string' where type = 'text' OR type = '' ";
$databox->get_connection()->executeQuery($sql);
return true;
}
}

View File

@@ -530,11 +530,12 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
} }
$coll_id_from = $this->getCollectionId(); $coll_id_from = $this->getCollectionId();
$coll_id_to = $collection->get_coll_id();
$sql = "UPDATE record SET moddate = NOW(), coll_id = :coll_id WHERE record_id =:record_id"; $sql = "UPDATE record SET moddate = NOW(), coll_id = :coll_id WHERE record_id =:record_id";
$params = [ $params = [
':coll_id' => $collection->get_coll_id(), ':coll_id' => $coll_id_to,
':record_id' => $this->getRecordId(), ':record_id' => $this->getRecordId(),
]; ];
@@ -543,12 +544,13 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
$stmt->closeCursor(); $stmt->closeCursor();
$this->base_id = $collection->get_base_id(); $this->base_id = $collection->get_base_id();
$this->collection_id = $coll_id_to;
$this->delete_data_from_cache();
$this->app['phraseanet.logger']($this->getDatabox()) $this->app['phraseanet.logger']($this->getDatabox())
->log($this, Session_Logger::EVENT_MOVE, $collection->get_coll_id(), '', $coll_id_from); ->log($this, Session_Logger::EVENT_MOVE, $collection->get_coll_id(), '', $coll_id_from);
$this->delete_data_from_cache();
$this->dispatch(RecordEvents::COLLECTION_CHANGED, new CollectionChangedEvent($this)); $this->dispatch(RecordEvents::COLLECTION_CHANGED, new CollectionChangedEvent($this));
return $this; return $this;

View File

@@ -1901,7 +1901,7 @@
</field> </field>
<field> <field>
<name>type</name> <name>type</name>
<type>enum('string','text','date','number')</type> <type>enum('string','date','number')</type>
<null></null> <null></null>
<extra></extra> <extra></extra>
<default></default> <default></default>

View File

@@ -148,7 +148,7 @@
</subdef> </subdef>
<subdef class="preview" name="preview" downloadable="false"> <subdef class="preview" name="preview" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path> <path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>flexpaper</mediatype> <mediatype>pdf</mediatype>
<writeDatas>no</writeDatas> <writeDatas>no</writeDatas>
<devices>screen</devices> <devices>screen</devices>
<label lang="fr">Prévisualisation</label> <label lang="fr">Prévisualisation</label>
@@ -198,7 +198,7 @@
<Coverage src="XMP-dc:Coverage" report="1" /> <Coverage src="XMP-dc:Coverage" report="1" />
<Rights src="XMP-dc:Rights" report="0" /> <Rights src="XMP-dc:Rights" report="0" />
<Comments src="" business="1" report="0" /> <Comments src="" business="1" report="0" />
<Filename src="Phraseanet:tf-basename" readonly="1" type="text" report="1"/> <Filename src="Phraseanet:tf-basename" readonly="1" type="string" report="1"/>
<CameraDevice src="IFD0:Model" readonly="1" report="0" /> <CameraDevice src="IFD0:Model" readonly="1" report="0" />
<Latitude src="GPS:GPSLatitude" readonly="1" report="0" /> <Latitude src="GPS:GPSLatitude" readonly="1" report="0" />
<Longitude src="GPS:GPSLongitude" readonly="1" report="0"/> <Longitude src="GPS:GPSLongitude" readonly="1" report="0"/>

View File

@@ -148,7 +148,7 @@
</subdef> </subdef>
<subdef class="preview" name="preview" downloadable="false"> <subdef class="preview" name="preview" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path> <path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>flexpaper</mediatype> <mediatype>pdf</mediatype>
<writeDatas>no</writeDatas> <writeDatas>no</writeDatas>
<devices>screen</devices> <devices>screen</devices>
<label lang="fr">Prévisualisation</label> <label lang="fr">Prévisualisation</label>
@@ -202,7 +202,7 @@
<Longitude src="GPS:GPSLongitude" readonly="1"/> <Longitude src="GPS:GPSLongitude" readonly="1"/>
<Latitude src="GPS:GPSLatitude" readonly="1"/> <Latitude src="GPS:GPSLatitude" readonly="1"/>
<CameraModel src="IFD0:Model" readonly="1"/> <CameraModel src="IFD0:Model" readonly="1"/>
<FileName src="Phraseanet:tf-basename" readonly="1" type="text" /> <FileName src="Phraseanet:tf-basename" readonly="1" type="string" />
</description> </description>
<statbits> <statbits>

View File

@@ -148,7 +148,7 @@
</subdef> </subdef>
<subdef class="preview" name="preview" downloadable="false"> <subdef class="preview" name="preview" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path> <path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>flexpaper</mediatype> <mediatype>pdf</mediatype>
<writeDatas>no</writeDatas> <writeDatas>no</writeDatas>
<devices>screen</devices> <devices>screen</devices>
<label lang="fr">Prévisualisation</label> <label lang="fr">Prévisualisation</label>
@@ -202,7 +202,7 @@
<Longitude src="GPS:GPSLongitude" readonly="1"/> <Longitude src="GPS:GPSLongitude" readonly="1"/>
<Latitude src="GPS:GPSLatitude" readonly="1"/> <Latitude src="GPS:GPSLatitude" readonly="1"/>
<AppareilPhoto src="IFD0:Model" readonly="1"/> <AppareilPhoto src="IFD0:Model" readonly="1"/>
<NomDeFichier src="Phraseanet:tf-basename" readonly="1" type="text" /> <NomDeFichier src="Phraseanet:tf-basename" readonly="1" type="string" />
</description> </description>
<statbits> <statbits>

View File

@@ -66,7 +66,7 @@
"normalize-css": "^2.1.0", "normalize-css": "^2.1.0",
"npm": "^6.0.0", "npm": "^6.0.0",
"npm-modernizr": "^2.8.3", "npm-modernizr": "^2.8.3",
"phraseanet-production-client": "^0.33.0", "phraseanet-production-client": "0.33.84",
"requirejs": "^2.3.5", "requirejs": "^2.3.5",
"tinymce": "^4.0.28", "tinymce": "^4.0.28",
"underscore": "^1.8.3", "underscore": "^1.8.3",

View File

@@ -60,7 +60,7 @@
chdir: /vagrant/ chdir: /vagrant/
- name: Create ElasticSearch indexes - name: Create ElasticSearch indexes
shell: php bin/console s:i:c shell: php bin/console searchengine:index -c
args: args:
chdir: /vagrant/ chdir: /vagrant/

View File

@@ -28,3 +28,13 @@
lineinfile: dest=/etc/php/{{ phpversion }}/apache2/php.ini lineinfile: dest=/etc/php/{{ phpversion }}/apache2/php.ini
regexp=';?max_input_vars\s*=\s*' regexp=';?max_input_vars\s*=\s*'
line='max_input_vars = 12000' line='max_input_vars = 12000'
- name: set session.hash_bits_per_character apache2
lineinfile: dest=/etc/php/{{ phpversion }}/apache2/php.ini
regexp=';?session.hash_bits_per_character\s*=\s*'
line='session.hash_bits_per_character = 6'
- name: set session.hash_function apache2
lineinfile: dest=/etc/php/{{ phpversion }}/apache2/php.ini
regexp=';?session.hash_function\s*=\s*'
line='session.hash_function = 1'

View File

@@ -28,3 +28,13 @@
lineinfile: dest=/etc/php/{{ phpversion }}/cli/php.ini lineinfile: dest=/etc/php/{{ phpversion }}/cli/php.ini
regexp=';?max_input_vars\s*=\s*' regexp=';?max_input_vars\s*=\s*'
line='max_input_vars = 12000' line='max_input_vars = 12000'
- name: set session.hash_function cli
lineinfile: dest=/etc/php/{{ phpversion }}/cli/php.ini
regexp=';?session.hash_function\s*=\s*'
line='session.hash_function = 1'
- name: set session.hash_bits_per_character cli
lineinfile: dest=/etc/php/{{ phpversion }}/cli/php.ini
regexp=';?session.hash_bits_per_character\s*=\s*'
line='session.hash_bits_per_character = 6'

View File

@@ -46,3 +46,16 @@
regexp=';?max_input_vars\s*=\s*' regexp=';?max_input_vars\s*=\s*'
line='max_input_vars = 12000' line='max_input_vars = 12000'
notify: restart php{{ phpversion }}-fpm notify: restart php{{ phpversion }}-fpm
- name: set session.hash_function fpm
lineinfile: dest=/etc/php/{{ phpversion }}/fpm/php.ini
regexp=';?session.hash_function\s*=\s*'
line='session.hash_function = 1'
notify: restart php{{ phpversion }}-fpm
- name: set session.hash_bits_per_character fpm
lineinfile: dest=/etc/php/{{ phpversion }}/fpm/php.ini
regexp=';?session.hash_bits_per_character\s*=\s*'
line='session.hash_bits_per_character = 6'
notify: restart php{{ phpversion }}-fpm

View File

@@ -18,6 +18,10 @@
with_items: '{{ server.packages }}' with_items: '{{ server.packages }}'
when: server.packages is defined when: server.packages is defined
- name: Pip install ndg-httpsclient
shell: pip install ndg-httpsclient
sudo: yes
- name: Configure the timezone - name: Configure the timezone
sudo: yes sudo: yes
template: src=timezone.j2 dest=/etc/timezone template: src=timezone.j2 dest=/etc/timezone

View File

@@ -21,6 +21,13 @@ server:
- xpdf - xpdf
- libav-tools - libav-tools
- gpac - gpac
- python
- python-urllib3
- python3-openssl
- python-pyasn1
- python-pyasn1-modules
- python3-pyasn1
- python-pip
timezone: UTC timezone: UTC
locales: locales:
- en_GB.UTF-8 - en_GB.UTF-8

View File

@@ -8,13 +8,7 @@ gulp.task('copy-report-images', function(){
.pipe(gulp.dest( config.paths.build + 'report/images')); .pipe(gulp.dest( config.paths.build + 'report/images'));
}); });
gulp.task('build-report-print-css', function(){ gulp.task('build-report-css', function(){
return utils.buildCssGroup([
config.paths.src + 'report/styles/main-print.scss'
], 'print', 'report/css/', debugMode);
});
gulp.task('build-report-css', ['build-report-print-css'], function(){
return utils.buildCssGroup([ return utils.buildCssGroup([
config.paths.src + 'report/styles/main.scss' config.paths.src + 'report/styles/main.scss'
], 'report', 'report/css/', debugMode); ], 'report', 'report/css/', debugMode);
@@ -22,10 +16,6 @@ gulp.task('build-report-css', ['build-report-print-css'], function(){
gulp.task('build-report-js', function(){ gulp.task('build-report-js', function(){
var reportGroup = [ var reportGroup = [
config.paths.src + 'report/js/jquery.print.js',
config.paths.src + 'report/js/jquery.cluetip.js',
config.paths.src + 'report/js/jquery.nicoslider.js',
config.paths.src + 'report/js/jquery.gvChart-0.1.js',
config.paths.src + 'report/js/report.js' config.paths.src + 'report/js/report.js'
]; ];
return utils.buildJsGroup(reportGroup, 'report', 'report/js', debugMode); return utils.buildJsGroup(reportGroup, 'report', 'report/js', debugMode);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2018-11-07T11:48:26Z" source-language="en" target-language="de" datatype="plaintext" original="not.available"> <file date="2018-12-11T12:17:04Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note> <note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2018-11-07T11:49:58Z" source-language="en" target-language="en" datatype="plaintext" original="not.available"> <file date="2018-12-11T12:19:04Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note> <note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2018-11-07T11:51:34Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available"> <file date="2018-12-11T12:20:50Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note> <note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2"> <xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2018-11-07T11:53:36Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available"> <file date="2018-12-11T12:22:28Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
<header> <header>
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/> <tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note> <note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 817 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 254 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 892 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 276 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 992 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Some files were not shown because too many files have changed in this diff Show More