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: cd rabbitmq-c && git checkout 2ca1774489328cde71195f5fa95e17cf3a80cb8a
- 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 imagick
- run: sudo apt-get install libzmq-dev

44
AUTHORS
View File

@@ -1,27 +1,39 @@
** Phraseanet is written and maintained by the Phraseanet Developer Team **
Benoît Burnichon
Jean-Yves Gaulier
Andrey Kalinovsky
Nicolas Legoff
Romain Neutron
- Jean-Yves Gaulier
- Milos M
- Mike NG
- Xavier Rousset
- Aina Sitraka
- Filip Vilic
** Proudly Powered by Alchemy **
Nicolas Amendola
Nathanaël Attar
Aurélie Bachelet
Anthony Cabot
Moctar Diouf
Jennifer Guérin
Nicolas Honoré
Nicolas Maillat
Guillaume Maubert
Jonathan Schneider
- Aurélie Bachelet
- Laetitia Bianchi
- Anthony Cabot
- Moctar Diouf
- Jennifer Guérin
- Félix Noir
- Nicolas Maillat
- Guillaume Maubert
** 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
30 Place Saint Georges

View File

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

View File

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

5
Vagrantfile vendored
View File

@@ -35,7 +35,7 @@ else if which('ifconfig')
end
$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')
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"]
end
end
config.vm.network :public_network, bridge:"en0: Ethernet"
config.hostmanager.ip_resolver = proc do |vm, resolving_vm|
if vm.id
if $env == "mac" || $env == "linux"

View File

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

75
composer.lock generated
View File

@@ -1,10 +1,10 @@
{
"_readme": [
"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"
],
"content-hash": "253990d4c81f9ae5f78c6c1221d6cf29",
"content-hash": "adf4074eb26ea80d414430d4f7b61311",
"packages": [
{
"name": "alchemy-fr/tcpdf-clone",
@@ -131,16 +131,16 @@
},
{
"name": "alchemy/embed-bundle",
"version": "0.3.7",
"version": "0.3.8",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/embed-bundle.git",
"reference": "ce7408c7a47387eed3df2a743577d6e0e25f991f"
"reference": "8a9699bc51e2b2997ccfd357bb2892f3702c33ef"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/ce7408c7a47387eed3df2a743577d6e0e25f991f",
"reference": "ce7408c7a47387eed3df2a743577d6e0e25f991f",
"url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/8a9699bc51e2b2997ccfd357bb2892f3702c33ef",
"reference": "8a9699bc51e2b2997ccfd357bb2892f3702c33ef",
"shasum": ""
},
"require-dev": {
@@ -178,10 +178,10 @@
],
"description": "Embed resources bundle",
"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"
},
"time": "2017-05-30T13:18:21+00:00"
"time": "2019-01-11T10:35:41+00:00"
},
{
"name": "alchemy/geonames-api-consumer",
@@ -275,16 +275,16 @@
},
{
"name": "alchemy/mediavorus",
"version": "0.4.8",
"version": "0.4.9",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/MediaVorus.git",
"reference": "6a50c397211dfdf6da108ea1ebc7527c37419ab7"
"reference": "1a96dc4142ff8474c11285cab9eab11df9683255"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/6a50c397211dfdf6da108ea1ebc7527c37419ab7",
"reference": "6a50c397211dfdf6da108ea1ebc7527c37419ab7",
"url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/1a96dc4142ff8474c11285cab9eab11df9683255",
"reference": "1a96dc4142ff8474c11285cab9eab11df9683255",
"shasum": ""
},
"require": {
@@ -333,20 +333,20 @@
"keywords": [
"metadata"
],
"time": "2018-05-03T14:17:10+00:00"
"time": "2019-01-22T11:23:34+00:00"
},
{
"name": "alchemy/oauth2php",
"version": "1.0.0",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/oauth2-php.git",
"reference": "cb4fcb73e30ab54e0fb85a65b4d57147f7a0df15"
"reference": "801510972240555fa182813851efd96659d37a68"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/oauth2-php/zipball/cb4fcb73e30ab54e0fb85a65b4d57147f7a0df15",
"reference": "cb4fcb73e30ab54e0fb85a65b4d57147f7a0df15",
"url": "https://api.github.com/repos/alchemy-fr/oauth2-php/zipball/801510972240555fa182813851efd96659d37a68",
"reference": "801510972240555fa182813851efd96659d37a68",
"shasum": ""
},
"type": "library",
@@ -356,7 +356,7 @@
]
},
"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",
@@ -1898,12 +1898,12 @@
"version": "v2.5.6",
"source": {
"type": "git",
"url": "https://github.com/doctrine/doctrine2.git",
"url": "https://github.com/doctrine/orm.git",
"reference": "e6c434196c8ef058239aaa0724b4aadb0107940b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/doctrine2/zipball/e6c434196c8ef058239aaa0724b4aadb0107940b",
"url": "https://api.github.com/repos/doctrine/orm/zipball/e6c434196c8ef058239aaa0724b4aadb0107940b",
"reference": "e6c434196c8ef058239aaa0724b4aadb0107940b",
"shasum": ""
},
@@ -2304,12 +2304,12 @@
"version": "v2.2.1",
"source": {
"type": "git",
"url": "https://github.com/google/google-api-php-client.git",
"url": "https://github.com/googleapis/google-api-php-client.git",
"reference": "b69b8ac4bf6501793c389d4e013a79d09c85c5f2"
},
"dist": {
"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",
"shasum": ""
},
@@ -2363,12 +2363,12 @@
"version": "v0.36",
"source": {
"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"
},
"dist": {
"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",
"shasum": ""
},
@@ -2400,12 +2400,12 @@
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/google/google-auth-library-php.git",
"url": "https://github.com/googleapis/google-auth-library-php.git",
"reference": "548d27d670f0236dc5258fa4cdde6e7b63464cfd"
},
"dist": {
"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",
"shasum": ""
},
@@ -4334,16 +4334,16 @@
},
{
"name": "media-alchemyst/media-alchemyst",
"version": "0.5.1",
"version": "0.5.2",
"source": {
"type": "git",
"url": "https://github.com/alchemy-fr/Media-Alchemyst.git",
"reference": "b82bb891640cb1ce5d5523235047c34c64194514"
"reference": "5d2fe6dd95215804202ecf0466fd9cfaeedd0140"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/Media-Alchemyst/zipball/b82bb891640cb1ce5d5523235047c34c64194514",
"reference": "b82bb891640cb1ce5d5523235047c34c64194514",
"url": "https://api.github.com/repos/alchemy-fr/Media-Alchemyst/zipball/5d2fe6dd95215804202ecf0466fd9cfaeedd0140",
"reference": "5d2fe6dd95215804202ecf0466fd9cfaeedd0140",
"shasum": ""
},
"require": {
@@ -4404,7 +4404,7 @@
"video",
"video processing"
],
"time": "2016-03-16T13:11:52+00:00"
"time": "2019-01-25T12:09:11+00:00"
},
{
"name": "monolog/monolog",
@@ -5766,17 +5766,6 @@
{
"name": "roave/security-advisories",
"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": {
"adodb/adodb-php": "<5.20.6",
"amphp/artax": ">=2,<2.0.4|>0.7.1,<1.0.4",
@@ -6015,6 +6004,7 @@
"keywords": [
"microframework"
],
"abandoned": "symfony/flex",
"time": "2016-01-06T14:59:35+00:00"
},
{
@@ -6060,6 +6050,7 @@
],
"description": "A WebProfiler for Silex",
"homepage": "http://silex.sensiolabs.org/",
"abandoned": true,
"time": "2016-01-10T11:39:13+00:00"
},
{

View File

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

View File

@@ -65,8 +65,6 @@ class RouteLoader
'/prod/upload/' => Providers\Prod\Upload::class,
'/prod/WorkZone' => Providers\Prod\WorkZone::class,
'/prod/' => Providers\Prod\Root::class,
'/report/activity' => Providers\Report\Activity::class,
'/report/informations' => Providers\Report\Information::class,
'/report/' => Providers\Report\Root::class,
'/session/' => Providers\Root\Session::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_AUDIOSAMPLERATE] = $config["audio"]["definitions"][$preset][Audio::OPTION_AUDIOSAMPLERATE];
$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) {
$options[Subdef::OPTION_DEVICE][] = $devices;
}
@@ -211,7 +212,7 @@ class SubdefsController extends Controller
{
$mapping = [
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_DOCUMENT => [Subdef::TYPE_IMAGE, Subdef::TYPE_FLEXPAPER, Subdef::TYPE_PDF],
Type::TYPE_FLASH => [Subdef::TYPE_IMAGE]
@@ -525,29 +526,44 @@ class SubdefsController extends Controller
],
Subdef::TYPE_AUDIO => [
"definitions" => [
"Low AAC 96 kbit/s" => [
"Low MP3 96 kbit/s" => [
Audio::OPTION_AUDIOBITRATE => "100",
Audio::OPTION_AUDIOSAMPLERATE => "8000",
Audio::OPTION_ACODEC => "libmp3lame",
Subdef::OPTION_DEVICE => ["all"]
],
"Normal AAC 128 kbit/s" => [
"Normal MP3 128 kbit/s" => [
Audio::OPTION_AUDIOBITRATE => "180",
Audio::OPTION_AUDIOSAMPLERATE => "44100",
Audio::OPTION_ACODEC => "libmp3lame",
Subdef::OPTION_DEVICE => ["all"]
],
"High AAC 320 kbit/s" => [
"High MP3 320 kbit/s" => [
Audio::OPTION_AUDIOBITRATE => "230",
Audio::OPTION_AUDIOSAMPLERATE => "50000",
Audio::OPTION_ACODEC => "libmp3lame",
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" => [
Audio::OPTION_AUDIOBITRATE => "slide",
Audio::OPTION_AUDIOSAMPLERATE => "select",
Audio::OPTION_ACODEC => "select",
Audio::OPTION_AUDIOCHANNEL => "select",
Subdef::OPTION_DEVICE => "checkbox",
],
],

View File

@@ -323,9 +323,14 @@ class QueryController extends Controller
// add technical fields
$fieldLabels = [];
$fieldsInfosByName = [];
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
@@ -337,13 +342,25 @@ class QueryController extends Controller
foreach ($databox->get_meta_structure() as $field) {
$name = $field->get_name();
$fieldsInfos[$sbasId][$name] = [
'label' => $field->get_label($this->app['locale']),
'type' => $field->get_type(),
'label' => $field->get_label($this->app['locale']),
'labels' => $field->get_labels(),
'type' => $field->get_type(),
'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)
$facets = [];
// $facetClauses = [];
foreach ($result->getFacets() as $facet) {
$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['phrasea_props'] = $proposals;
$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;
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 RootController extends Controller
{
@@ -53,22 +49,34 @@ class RootController extends Controller
$granted = [];
foreach ($this->getAclForUser()->get_granted_base([\ACL::CANREPORT]) as $collection) {
if (!isset($granted[$collection->get_sbas_id()])) {
$granted[$collection->get_sbas_id()] = [
'id' => $collection->get_sbas_id(),
'name' => $collection->get_databox()->get_viewname(),
'collections' => []
$acl = $this->getAclForUser();
foreach ($acl->get_granted_base([\ACL::CANREPORT]) as $collection) {
$sbas_id = $collection->get_sbas_id();
if (!isset($granted[$sbas_id])) {
$granted[$sbas_id] = [
'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'][] = [
'id' => $collection->get_coll_id(),
$granted[$sbas_id]['collections'][] = [
'id' => $collection->get_coll_id(),
'base_id' => $collection->get_base_id(),
'name' => $collection->get_name()
'name' => $collection->get_name(),
];
}
$conf = $this->getConf();
return $this->render('report/report_layout_child.html.twig', [
'ajax_dash' => true,
'dashboard' => null,
@@ -82,594 +90,4 @@ class RootController extends Controller
'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)
{
if (null === $lng = $request->get('lng')) {
$data = explode('_', $this->app['locale']);
if (count($data) > 0) {
$lng = $data[0];
}
}
$lng = $request->get('lng');
$html = '';
$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 @lng=\'' . \thesaurus::xquery_escape($lng) . '\'';
if($lng != null){
$q2 .= ' and @lng=\'' . \thesaurus::xquery_escape($lng) . '\'';
}
$q .= ('//sy[' . $q2 . ']');
$nodes = $xpath->query($q);

View File

@@ -88,8 +88,6 @@ class ControllerProviderServiceProvider implements ServiceProviderInterface
Prod\Upload::class => [],
Prod\UsrLists::class => [],
Prod\WorkZone::class => [],
Report\Activity::class => [],
Report\Information::class => [],
Report\Root::class => [],
Root\Account::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
*/
private $number = '4.1.0-alpha.13';
private $number = '4.1.0-alpha.14a';
/**
* @var string

View File

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

View File

@@ -19,6 +19,7 @@ class Audio extends Provider
const OPTION_THREADS = 'threads';
const OPTION_ACODEC = 'acodec';
const OPTION_AUDIOSAMPLERATE = 'audiosamplerate';
const OPTION_AUDIOCHANNEL = 'audiochannel';
public function __construct(TranslatorInterface $translator)
{
@@ -29,9 +30,12 @@ class Audio extends Provider
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\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()
@@ -53,7 +57,21 @@ class Audio extends Provider
$this->spec->setAudioCodec($this->getOption(self::OPTION_ACODEC)->getValue());
$this->spec->setAudioSampleRate($this->getOption(self::OPTION_AUDIOSAMPLERATE)->getValue());
$this->spec->setAudioKiloBitrate($this->getOption(self::OPTION_AUDIOBITRATE)->getValue());
$this->spec->setAudioChannels($this->getChannelNumber($this->getOption(self::OPTION_AUDIOCHANNEL)->getValue()));
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;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Report\Report;
use Alchemy\Phrasea\Report\ReportConnections;
use Alchemy\Phrasea\Report\ReportDownloads;
@@ -16,10 +17,11 @@ use Alchemy\Phrasea\Report\ReportFactory;
use Alchemy\Phrasea\Report\ReportRecords;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
class ProdReportController
class ProdReportController extends Controller
{
private static $mapFromExtension = [
'csv' => [
@@ -55,6 +57,19 @@ class ProdReportController
$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
*

View File

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

View File

@@ -60,18 +60,24 @@ class ProdReportControllerProvider implements ControllerProviderInterface, Servi
$controllers = $this->createAuthenticatedCollection($app);
$controllers
->get('/connections/{sbasId}/', 'controller.prod.report:connectionsAction')
->match('/connections/{sbasId}/', 'controller.prod.report:connectionsAction')
->assert('sbasId', '\d+')
->bind('report2_connections')
->method('GET|POST')
;
$controllers
->get('/downloads/{sbasId}/', 'controller.prod.report:downloadsAction')
->match('/downloads/{sbasId}/', 'controller.prod.report:downloadsAction')
->assert('sbasId', '\d+')
->bind('report2_downloads')
->method('GET|POST')
;
$controllers
->get('/records/{sbasId}/', 'controller.prod.report:recordsAction')
->match('/records/{sbasId}/', 'controller.prod.report:recordsAction')
->assert('sbasId', '\d+')
->bind('report2_records')
->method('GET|POST')
;
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"
. "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, []);
$rows = $stmt->fetchAll();
$stmt->closeCursor();

View File

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

View File

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

View File

@@ -127,20 +127,21 @@ class Fetcher
private function getExecutedStatement()
{
if (!$this->statement) {
$sql = "SELECT r.record_id"
. ", r.coll_id AS collection_id"
. ", c.asciiname AS collection_name"
. ", r.uuid"
. ", r.status AS flags_bitfield"
. ", r.sha256" // -- TODO rename in "hash"
. ", r.originalname AS original_name"
. ", r.mime, r.type, r.parent_record_id, r.credate AS created_on, r.moddate AS updated_on"
. ", subdef.width, subdef.height, subdef.size"
. " FROM (record r INNER JOIN coll c ON (c.coll_id = r.coll_id))"
. " LEFT JOIN subdef ON subdef.record_id=r.record_id AND subdef.name='document'"
. " -- WHERE"
. " ORDER BY " . $this->options->getPopulateOrderAsSQL() . " " . $this->options->getPopulateDirectionAsSQL()
. " LIMIT :offset, :limit";
$sql = "SELECT r.*, c.asciiname AS collection_name, subdef.width, subdef.height, subdef.size\n"
. " FROM ((\n"
. " SELECT r.record_id, r.coll_id AS collection_id, r.uuid, r.status AS flags_bitfield, r.sha256,\n"
. " r.originalname AS original_name, r.mime, r.type, r.parent_record_id,\n"
. " r.credate AS created_on, r.moddate AS updated_on, r.coll_id\n"
. " FROM record r\n"
. " -- WHERE\n"
. " ORDER BY " . $this->options->getPopulateOrderAsSQL() . " " . $this->options->getPopulateDirectionAsSQL() . "\n"
. " LIMIT :offset, :limit\n"
. " ) AS r\n"
. " INNER JOIN coll c ON (c.coll_id = r.coll_id)\n"
. " )\n"
. " LEFT JOIN\n"
. " 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();
$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)
{
if ($field->getType() === FieldMapping::TYPE_DATE) {
return new DateFieldMapping($field->getName(), FieldMapping::DATE_FORMAT_CAPTION);
$ret = null;
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) {
$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());
return $ret;
}
}

View File

@@ -4,6 +4,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\Exception\RuntimeException;
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\GlobalStructure;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion;
use Doctrine\Common\Collections\ArrayCollection;
@@ -14,28 +15,72 @@ class FacetsResponse
private $escaper;
private $facets = array();
public function __construct(Escaper $escaper, array $response)
public function __construct(Escaper $escaper, array $response, GlobalStructure $structure)
{
$this->escaper = $escaper;
if (!isset($response['aggregations'])) {
return;
}
$atf = ElasticsearchOptions::getAggregableTechnicalFields();
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);
if (!isset($aggregation['buckets'])) {
$this->throwAggregationResponseError();
}
$values = $this->buildBucketsValues($name, $aggregation['buckets']);
if ($values) {
$this->facets[] = array(
$values = [];
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,
'field' => $tf ? $tf['field'] : sprintf('field.%s', $name),
'values' => $values,
);
];
}
}
}
/**
* @return ArrayCollection
*/
@@ -53,44 +98,6 @@ class FacetsResponse
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()
{
throw new RuntimeException('Invalid aggregation response');

View File

@@ -107,13 +107,28 @@ class QueryContext
*/
public function localizeField(Field $field)
{
$ret = null;
$index_field = $field->getIndexField();
if ($field->getType() === FieldMapping::TYPE_STRING) {
return $this->localizeFieldName($index_field);
} else {
return [$index_field];
switch($field->getType()) {
case FieldMapping::TYPE_STRING:
$ret = $this->localizeFieldName($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)

View File

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

View File

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

View File

@@ -60,7 +60,7 @@ class Thesaurus
// TODO Use bulk queries for performance
$concepts = array();
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);
}

View File

@@ -88,7 +88,7 @@ class PhraseanetExtension extends \Twig_Extension
$highlightValue = $highlights[$field];
// 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) {
return str_replace(array('[[em]]', '[[/em]]'), array('', ''), $value);
}, $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)
{
$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
if ($token_param === false) {
@@ -808,4 +812,21 @@ class API_OAuth2_Adapter extends OAuth2
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_NUMBER
, databox_field::TYPE_STRING
, databox_field::TYPE_TEXT
]
) ? $type : databox_field::TYPE_STRING;

View File

@@ -100,7 +100,6 @@ class databox_field implements cache_cacheableInterface
protected $original_dces;
protected $aggregable;
const TYPE_TEXT = "text";
const TYPE_DATE = "date";
const TYPE_STRING = "string";
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;
}
/**
* get all localized labels
*
* @return string[]
*/
public function get_labels()
{
return $this->labels;
}
/**
* @param string $name
* @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_FLASH => [SubdefSpecs::TYPE_IMAGE],
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],
];
const CLASS_THUMBNAIL = 'thumbnail';
@@ -156,6 +156,10 @@ class databox_subdef
if ($sd->audiosamplerate) {
$audio->setOptionValue(Audio::OPTION_AUDIOSAMPLERATE, (int) $sd->audiosamplerate);
}
if ($sd->audiochannel) {
$audio->setOptionValue(Audio::OPTION_AUDIOCHANNEL, (string) $sd->audiochannel);
}
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_IMAGE = 'IMAGE';
const TYPE_NO_PLAYER = 'UNKNOWN';
const TYPE_PDF = 'PDF';
/*
* Technical datas types constants
@@ -407,6 +408,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
{
static $types = [
'application/x-shockwave-flash' => self::TYPE_FLEXPAPER,
'application/pdf' => self::TYPE_PDF,
'audio/mp3' => self::TYPE_AUDIO_MP3,
'audio/mpeg' => self::TYPE_AUDIO_MP3,
'image/gif' => self::TYPE_IMAGE,

View File

@@ -50,6 +50,21 @@ class patch_380alpha3a extends patchAbstract
{
$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";
$stmt = $conn->prepare($removeProc);

View File

@@ -60,8 +60,14 @@ class patch_410alpha13a implements patchInterface
*/
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`";
$databox->get_connection()->prepare($sql)->execute();
*/
/*
* 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_to = $collection->get_coll_id();
$sql = "UPDATE record SET moddate = NOW(), coll_id = :coll_id WHERE record_id =:record_id";
$params = [
':coll_id' => $collection->get_coll_id(),
':coll_id' => $coll_id_to,
':record_id' => $this->getRecordId(),
];
@@ -543,12 +544,13 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
$stmt->closeCursor();
$this->base_id = $collection->get_base_id();
$this->collection_id = $coll_id_to;
$this->delete_data_from_cache();
$this->app['phraseanet.logger']($this->getDatabox())
->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));
return $this;

View File

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

View File

@@ -148,7 +148,7 @@
</subdef>
<subdef class="preview" name="preview" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>flexpaper</mediatype>
<mediatype>pdf</mediatype>
<writeDatas>no</writeDatas>
<devices>screen</devices>
<label lang="fr">Prévisualisation</label>
@@ -198,7 +198,7 @@
<Coverage src="XMP-dc:Coverage" report="1" />
<Rights src="XMP-dc:Rights" 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" />
<Latitude src="GPS:GPSLatitude" readonly="1" report="0" />
<Longitude src="GPS:GPSLongitude" readonly="1" report="0"/>

View File

@@ -148,7 +148,7 @@
</subdef>
<subdef class="preview" name="preview" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>flexpaper</mediatype>
<mediatype>pdf</mediatype>
<writeDatas>no</writeDatas>
<devices>screen</devices>
<label lang="fr">Prévisualisation</label>
@@ -202,7 +202,7 @@
<Longitude src="GPS:GPSLongitude" readonly="1"/>
<Latitude src="GPS:GPSLatitude" 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>
<statbits>

View File

@@ -148,7 +148,7 @@
</subdef>
<subdef class="preview" name="preview" downloadable="false">
<path>{{datapathnoweb}}{{basename}}/subdefs</path>
<mediatype>flexpaper</mediatype>
<mediatype>pdf</mediatype>
<writeDatas>no</writeDatas>
<devices>screen</devices>
<label lang="fr">Prévisualisation</label>
@@ -202,7 +202,7 @@
<Longitude src="GPS:GPSLongitude" readonly="1"/>
<Latitude src="GPS:GPSLatitude" 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>
<statbits>

View File

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

View File

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

View File

@@ -28,3 +28,13 @@
lineinfile: dest=/etc/php/{{ phpversion }}/apache2/php.ini
regexp=';?max_input_vars\s*=\s*'
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
regexp=';?max_input_vars\s*=\s*'
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*'
line='max_input_vars = 12000'
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 }}'
when: server.packages is defined
- name: Pip install ndg-httpsclient
shell: pip install ndg-httpsclient
sudo: yes
- name: Configure the timezone
sudo: yes
template: src=timezone.j2 dest=/etc/timezone

View File

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

View File

@@ -8,13 +8,7 @@ gulp.task('copy-report-images', function(){
.pipe(gulp.dest( config.paths.build + 'report/images'));
});
gulp.task('build-report-print-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(){
gulp.task('build-report-css', function(){
return utils.buildCssGroup([
config.paths.src + 'report/styles/main.scss'
], 'report', 'report/css/', debugMode);
@@ -22,10 +16,6 @@ gulp.task('build-report-css', ['build-report-print-css'], function(){
gulp.task('build-report-js', function(){
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'
];
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"?>
<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>
<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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2018-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>
<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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2018-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>
<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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
<file date="2018-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>
<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>

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