diff --git a/.travis.yml b/.travis.yml index 39136bd693..895299b9fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,11 +21,14 @@ before_script: - git clone git://github.com/alchemy-fr/Phraseanet-Extension.git - sh -c "cd Phraseanet-Extension && phpize && ./configure && make && sudo make install" - echo "extension=phrasea2.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` - - wget http://pecl.php.net/get/gmagick-1.1.0RC2.tgz - - tar -xzf gmagick-1.1.0RC2.tgz - - sh -c "cd gmagick-1.1.0RC2 && phpize && ./configure --with-gmagick=/usr/local && make && sudo make install" - - echo "extension=gmagick.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` - - bin/setup system:upgrade -y + - wget http://pecl.php.net/get/imagick-3.1.0RC2.tgz + - tar -xzf imagick-3.1.0RC2.tgz + - sh -c "cd imagick-3.1.0RC2 && phpize && ./configure --with-imagick=/usr/local && make && sudo make install" + - echo "extension=imagick.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` +# - wget http://pecl.php.net/get/gmagick-1.1.0RC2.tgz +# - tar -xzf gmagick-1.1.0RC2.tgz +# - sh -c "cd gmagick-1.1.0RC2 && phpize && ./configure --with-gmagick=/usr/local && make && sudo make install" +# - echo "extension=gmagick.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` notifications: irc: @@ -39,4 +42,4 @@ notifications: php: - 5.3 - 5.4 - + - 5.5 diff --git a/README.md b/README.md index c72bd39814..cf9fb80be8 100644 --- a/README.md +++ b/README.md @@ -5,47 +5,23 @@ Phraseanet 3.8 - Digital Asset Management application #Features : -Metadatas Management (include Thesaurus and DublinCore Mapping) -Search Engine (Sphinx Search Integration) -RestFull APIS (See Developer Documentation https://docs.phraseanet.com/Devel) -Bridge to Youtube/Dailymotion/Flickr + - Metadatas Management (include Thesaurus and DublinCore Mapping) + - Search Engine (Sphinx Search Integration) + - RestFull APIS (See Developer Documentation https://docs.phraseanet.com/Devel) + - Bridge to Youtube/Dailymotion/Flickr #Documentation : https://docs.phraseanet.com/ -#Easy Installation +#Installation -Get the latest sources here https://github.com/alchemy-fr/Phraseanet/downloads +You **must** not download the source from GitHub, but download a packaged version here : -**Setup your webserver** +https://sourceforge.net/projects/phraseanet/files/ -***Nginx*** -
-server {
-    listen        80;
-    server_name   subdomain.domain.tld;
-    root          /path/to/Phraseanet/www;
-
-    index         index.php;
-
-    location /download {
-        internal;
-        alias /path/to/Phraseanet/tmp/download;
-    }
-    location /lazaret {
-        internal;
-        alias /path/to/Phraseanet/tmp/lazaret;
-    }
-}
-
- - -Let's go ! +And follow the install steps described at https://docs.phraseanet.com/Admin/ #License Phraseanet is licensed under GPL-v3 license. - -[1]: http://developer.phraseanet.com/ - diff --git a/builder.php b/builder.php index 3937b096b1..7c501862d2 100755 --- a/builder.php +++ b/builder.php @@ -61,6 +61,7 @@ $finder ->directories() ->name('test') ->name('tests') + ->name('functionnal-tests') ->name('Tests') ->name('test-suite') ->name('test_script') diff --git a/functionnal-tests/api/config/keys.conf.sample.yml b/functionnal-tests/api/config/keys.conf.sample.yml new file mode 100644 index 0000000000..01869b5035 --- /dev/null +++ b/functionnal-tests/api/config/keys.conf.sample.yml @@ -0,0 +1,4 @@ +dailymotion: + public_key: + secret_key: + dev_token: diff --git a/functionnal-tests/api/dailymotion.php b/functionnal-tests/api/dailymotion.php new file mode 100644 index 0000000000..4a7339a745 --- /dev/null +++ b/functionnal-tests/api/dailymotion.php @@ -0,0 +1,79 @@ +register('upload:dailymotion') + ->setDescription('Test upload on dailymotion API') + ->setCode(function (InputInterface $input, OutputInterface $output) use ($core) { + try { + $configuration = Yaml::parse(__DIR__. '/config/keys.conf.yml'); + } catch(\Exception $e) { + $output->writeln('could not parse configuration file'); + return; + } + + + $appbox = \appbox::get_instance($core); + + $found = false; + foreach ($appbox->get_databoxes() as $databox) { + /* @var $databox \databox */ + $sql = 'SELECT record_id FROM record WHERE type="video" AND ( + mime="video/mp4" OR mime="video/quicktime" OR mime="video/x-msvideo" OR mime="video/x-msvideo" + ) LIMIT 1'; + $stmt = $databox->get_connection()->prepare($sql); + $stmt->execute(); + $rows = $stmt->fetch(\PDO::FETCH_ASSOC); + if(1 === count($rows)) { + $found = true; + $record = $databox->get_record($rows['record_id']); + break; + } + unset($stmt); + } + + if (!$found) { + $output->writeln('No video found, '); + return; + } + + $bridge = new \Bridge_Api_Dailymotion($core['Registry'], new \Bridge_Api_Auth_OAuth2()); + + $bridge->set_oauth_token($configuration['dailymotion']['dev_token']); + + $options = array(); + $samples = array( + 'title' => $record->get_title(), + 'description' => 'Upload functionnal test', + 'tags' => 'phraseanet upload test dm api', + 'private' => true, + ); + + foreach($bridge->get_fields() as $field) { + $options[$field['name']] = isset($samples[$field['name']]) ? $samples[$field['name']] : uniqid('test_upload'); + } + + try { + $idVideo = $bridge->upload($record, $options); + $output->writeln(sprintf('video id is %s', $idVideo)); + } catch(\Bridge_Exception_ActionAuthNeedReconnect $e) { + $output->writeln(sprintf('Invalid token %s', $configuration['dailymotion']['dev_token'])); + } catch(\Exception $e) { + $output->writeln(sprintf('%s : %s -> %s',get_class($e), $e->getMessage(), $e->getTraceAsString())); + } + }); + +$console->run(); diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index bc21a305ad..aaa982a285 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -361,6 +361,26 @@ return call_user_func(function($environment = 'prod') { return $app['api']->add_record($app, $request)->get_response(); }); + /** + * Route : /search/ + * + * Method : GET or POST + * + * Parameters : + * bases[] : array + * status[] : array + * fields[] : array + * record_type : boolean + * media_type : string + * + * Response : + * Array containing an array of records and stories collection + * + */ + $app->match('/search/', function() use ($app) { + return $app['api']->search($app['request'])->get_response(); + }); + /** * Route : /records/search/ * @@ -656,6 +676,41 @@ return call_user_func(function($environment = 'prod') { $app->get('/feeds/{wrong_feed_id}/content/', $bad_request_exception); + /** + * Route : /stories/DATABOX_ID/RECORD_ID/embed/ + * + * Method : GET + * + * Parameters : + * DATABOX_ID : required INT + * RECORD_ID : required INT + * + */ + $app->get('/stories/{databox_id}/{story_id}/embed/', function($databox_id, $story_id) use ($app) { + $result = $app['api']->get_story_embed($app['request'], $databox_id, $story_id); + + return $result->get_response(); + } + )->assert('databox_id', '\d+')->assert('story_id', '\d+'); + + $app->get('/stories/{any_id}/{anyother_id}/embed/', $bad_request_exception); + + $app->get('/stories/{databox_id}/{story_id}/', function($databox_id, $story_id) use ($app) { + $result = $app['api']->get_story($app['request'], $databox_id, $story_id); + + return $result->get_response(); + })->assert('databox_id', '\d+')->assert('story_id', '\d+'); + + $app->get('/stories/{any_id}/{anyother_id}/', $bad_request_exception); + + $app->get('/stories/{databox_id}/{story_id}/', function($databox_id, $story_id) use ($app) { + $result = $app['api']->get_story($app['request'], $databox_id, $story_id); + + return $result->get_response(); + })->assert('databox_id', '\d+')->assert('story_id', '\d+'); + $app->get('/stories/{any_id}/{anyother_id}/', $bad_request_exception); + + /** * Route Errors */ diff --git a/lib/Alchemy/Phrasea/Application/OAuth2.php b/lib/Alchemy/Phrasea/Application/OAuth2.php index 010442fa83..ec25b4ce9b 100644 --- a/lib/Alchemy/Phrasea/Application/OAuth2.php +++ b/lib/Alchemy/Phrasea/Application/OAuth2.php @@ -14,6 +14,7 @@ namespace Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application as PhraseaApplication; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; +use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpFoundation\Request; @@ -135,13 +136,16 @@ return call_user_func(function($environment = 'prod') { * Token endpoint - used to exchange an authorization grant for an access token. */ $app->post('/token', function(\Silex\Application $app, Request $request) { + if ( ! $request->isSecure()) { + throw new HttpException(400, 'This route requires the use of the https scheme', null, array('content-type' => 'application/json')); + } $app['oauth']->grantAccessToken(); ob_flush(); flush(); return; - })->requireHttps(); + }); /** * Error Handler diff --git a/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php b/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php index 7056fcae41..99a7bcf642 100644 --- a/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php +++ b/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php @@ -29,7 +29,7 @@ class MetaField implements AttributeInterface /** * - * @var mixed + * @var array */ protected $value; @@ -37,15 +37,10 @@ class MetaField implements AttributeInterface * Constructor * * @param \databox_field $databox_field The databox field - * @param string $value A scalar value - * - * @throws \InvalidArgumentException When value is not scalar + * @param array $value An array of scalar values */ - public function __construct(\databox_field $databox_field, $value) + public function __construct(\databox_field $databox_field, array $value) { - if (!is_scalar($value)) { - throw new \InvalidArgumentException('Databox field only accept scalar values'); - } $this->databox_field = $databox_field; $this->value = $value; } @@ -79,7 +74,7 @@ class MetaField implements AttributeInterface /** * {@inheritdoc} * - * @return mixed A scalar value + * @return array An array of scalar values */ public function getValue() { @@ -92,10 +87,10 @@ class MetaField implements AttributeInterface public function asString() { return serialize(array( - 'id' => $this->databox_field->get_id(), - 'sbas_id' => $this->databox_field->get_databox()->get_sbas_id(), - 'value' => $this->value - )); + 'id' => $this->databox_field->get_id(), + 'sbas_id' => $this->databox_field->get_databox()->get_sbas_id(), + 'value' => $this->value + )); } /** diff --git a/lib/Alchemy/Phrasea/Border/File.php b/lib/Alchemy/Phrasea/Border/File.php index 3da3fc5a69..4f1f76e72a 100644 --- a/lib/Alchemy/Phrasea/Border/File.php +++ b/lib/Alchemy/Phrasea/Border/File.php @@ -24,7 +24,7 @@ use MediaVorus\Exception\FileNotFoundException; use PHPExiftool\Writer; use PHPExiftool\Driver\TagFactory; use PHPExiftool\Driver\Metadata\Metadata; -use PHPExiftool\Driver\Metadata\MetadataBag; +use PHPExiftool\Driver\Metadata\MetadataBag as ExiftoolMetadataBag; use PHPExiftool\Driver\Value\Mono as MonoValue; use PHPExiftool\Exiftool; use PHPExiftool\Exception\ExceptionInterface as PHPExiftoolException; @@ -133,7 +133,7 @@ class File if ($write) { $value = new MonoValue($this->uuid); - $metadatas = new MetadataBag(); + $metadatas = new ExiftoolMetadataBag(); foreach ($availableUUIDs as $tagname) { $metadatas->add(new Metadata(TagFactory::getFromRDFTagname($tagname), $value)); diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php index 37825fa041..1fff81cfec 100644 --- a/lib/Alchemy/Phrasea/Border/Manager.php +++ b/lib/Alchemy/Phrasea/Border/Manager.php @@ -320,7 +320,7 @@ class Manager $metadatas[$key] = array(); } - $metadatas[$key] = array_merge($metadatas[$key], array($attribute->getValue())); + $metadatas[$key] = array_merge($metadatas[$key], $attribute->getValue()); break; case AttributeInterface::NAME_METADATA: diff --git a/lib/Alchemy/Phrasea/Border/MetaBagInterface.php b/lib/Alchemy/Phrasea/Border/MetaBagInterface.php new file mode 100644 index 0000000000..8affd5e562 --- /dev/null +++ b/lib/Alchemy/Phrasea/Border/MetaBagInterface.php @@ -0,0 +1,27 @@ +containsKey($databox_field->get_name())) { + if ($databox_field->is_multi()) { + + $values = $this->get($databox_field->get_name())->getValue(); + + $tmp = array(); + + foreach ($values as $value) { + foreach (\caption_field::get_multi_values($value, $databox_field->get_separator()) as $v) { + $tmp[] = $v; + } + } + + $values = array_unique($tmp); + + foreach ($values as $value) { + + $value = $unicode->substituteCtrlCharacters($value, ' '); + $value = $unicode->toUTF8($value); + if ($databox_field->get_type() == 'date') { + $value = $unicode->parseDate($value); + } + + $metas[] = array( + 'meta_struct_id' => $databox_field->get_id(), + 'value' => $value, + 'meta_id' => null + ); + } + } else { + + $values = $this->get($databox_field->get_name())->getValue(); + $value = array_shift($values); + + $value = $unicode->substituteCtrlCharacters($value, ' '); + $value = $unicode->toUTF8($value); + if ($databox_field->get_type() == 'date') { + $value = $unicode->parseDate($value); + } + + $metas[] = array( + 'meta_struct_id' => $databox_field->get_id(), + 'value' => $value, + 'meta_id' => null + ); + } + } + } + + return $metas; + } +} diff --git a/lib/Alchemy/Phrasea/Border/MetadataBag.php b/lib/Alchemy/Phrasea/Border/MetadataBag.php new file mode 100644 index 0000000000..6b99a25d53 --- /dev/null +++ b/lib/Alchemy/Phrasea/Border/MetadataBag.php @@ -0,0 +1,91 @@ +get_tag()->getTagname()) { + // skipping fields without sources + continue; + } + + if ($this->containsKey($databox_field->get_tag()->getTagname())) { + + if ($databox_field->is_multi()) { + + $values = $this->get($databox_field->get_tag()->getTagname())->getValue()->asArray(); + + $tmp = array(); + + foreach ($values as $value) { + foreach (\caption_field::get_multi_values($value, $databox_field->get_separator()) as $v) { + $tmp[] = $v; + } + } + + $values = array_unique($tmp); + + foreach ($values as $value) { + + $value = $unicode->substituteCtrlCharacters($value, ' '); + $value = $unicode->toUTF8($value); + if ($databox_field->get_type() == 'date') { + $value = $unicode->parseDate($value); + } + + $metas[] = array( + 'meta_struct_id' => $databox_field->get_id(), + 'value' => $value, + 'meta_id' => null + ); + } + } else { + $value = $this->get($databox_field->get_tag()->getTagname())->getValue()->asString(); + + $value = $unicode->substituteCtrlCharacters($value, ' '); + $value = $unicode->toUTF8($value); + if ($databox_field->get_type() == 'date') { + $value = $unicode->parseDate($value); + } + + $metas[] = array( + 'meta_struct_id' => $databox_field->get_id(), + 'value' => $value, + 'meta_id' => null + ); + } + } + } + + unset($unicode); + + return $metas; + } +} diff --git a/lib/Alchemy/Phrasea/Command/CreateCollection.php b/lib/Alchemy/Phrasea/Command/CreateCollection.php index 4992e0f284..cdd5e93e02 100644 --- a/lib/Alchemy/Phrasea/Command/CreateCollection.php +++ b/lib/Alchemy/Phrasea/Command/CreateCollection.php @@ -49,16 +49,16 @@ class CreateCollection extends Command $new_collection = \collection::create($app, $databox, $this->container['phraseanet.appbox'], $input->getArgument('collname')); - if ($new_collection && $input->getOption('duplicate_rights_from_base_id')) { + if ($new_collection && $input->getOption('base_id_rights')) { $query = new \User_Query($this->container); - $total = $query->on_base_ids(array($input->getOption('duplicate_rights_from_base_id')))->get_total(); + $total = $query->on_base_ids(array($input->getOption('base_id_rights')))->get_total(); $n = 0; while ($n < $total) { $results = $query->limit($n, 40)->execute()->get_results(); foreach ($results as $user) { - $user->ACL()->duplicate_right_from_bas($input->getOption('duplicate_rights_from_base_id'), $new_collection->get_base_id()); + $user->ACL()->duplicate_right_from_bas($input->getOption('base_id_rights'), $new_collection->get_base_id()); } $n+=40; } diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Databox.php b/lib/Alchemy/Phrasea/Controller/Admin/Databox.php index 82f604a546..ce931c9fbc 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/Databox.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/Databox.php @@ -461,7 +461,7 @@ class Databox implements ControllerProviderInterface if ($databox->get_record_amount() > 0) { $msg = _('admin::base: vider la base avant de la supprimer'); } else { - $databox->unmount_databox($app['phraseanet.appbox']); + $databox->unmount_databox(); $app['phraseanet.appbox']->write_databox_pic($app['media-alchemyst'], $app['filesystem'], $databox, null, \databox::PIC_PDF); $databox->delete(); $success = true; @@ -744,7 +744,7 @@ class Databox implements ControllerProviderInterface try { $databox = $app['phraseanet.appbox']->get_databox($databox_id); - $databox->unmount_databox($app['phraseanet.appbox']); + $databox->unmount_databox(); $success = true; } catch (\Exception $e) { diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Description.php b/lib/Alchemy/Phrasea/Controller/Admin/Description.php index adb890a764..100842cf61 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/Description.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/Description.php @@ -70,15 +70,16 @@ class Description implements ControllerProviderInterface 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfAtime', 'namespace' => 'Phraseanet' ), + 'tfbasename' => array( + 'tagname' => 'TfBasename', + 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfBasename', + 'namespace' => 'Phraseanet' + ), 'tfbits' => array( 'tagname' => 'TfBits', 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfBits', 'namespace' => 'Phraseanet' ), - 'tfbasename' => array( - 'tagname' => 'TfBasename', - 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfBasename', - 'namespace' => 'Phraseanet'), 'tfchannels' => array( 'tagname' => 'TfChannels', 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfChannels', @@ -89,6 +90,11 @@ class Description implements ControllerProviderInterface 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfCtime', 'namespace' => 'Phraseanet' ), + 'tfdirname' => array( + 'tagname' => 'TfDirname', + 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfDirname', + 'namespace' => 'Phraseanet' + ), 'tfduration' => array( 'tagname' => 'TfDuration', 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfDuration', @@ -129,10 +135,10 @@ class Description implements ControllerProviderInterface 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfMtime', 'namespace' => 'Phraseanet' ), - 'tfdirname' => array( - 'tagname' => 'TfDirname', - 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfDirname', - 'namespace' => 'Phraseanet' + 'tfquarantine' => array( + 'tagname' => 'TfQuarantine', + 'classname' => '\\Alchemy\\Phrasea\\Metadata\\Tag\\TfQuarantine', + 'namespace' => 'Phraseanet' ), 'tfrecordid' => array( 'tagname' => 'TfRecordid', diff --git a/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php b/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php index 9e325e1823..782d41529b 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php @@ -123,7 +123,7 @@ class TaskManager implements ControllerProviderInterface ob_flush(); flush(); } - }); + }, 200, array('Content-Type' => 'text/html')); }); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Lazaret.php b/lib/Alchemy/Phrasea/Controller/Prod/Lazaret.php index 935aebee98..8dd46b78db 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Lazaret.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Lazaret.php @@ -253,7 +253,6 @@ class Lazaret implements ControllerProviderInterface return $app->json($ret); } - $lazaretFile = $app['EM']->find('Entities\LazaretFile', $file_id); /* @var $lazaretFile \Entities\LazaretFile */ @@ -286,8 +285,11 @@ class Lazaret implements ControllerProviderInterface if ($keepAttributes) { //add attribute - foreach ($lazaretFile->getAttributes() as $attr) { + $metaFields = new Border\MetaFieldsBag(); + $metadataBag = new Border\MetadataBag(); + + foreach ($lazaretFile->getAttributes() as $attr) { //Check which ones to keep if (!!count($attributesToKeep)) { if (!in_array($attr->getId(), $attributesToKeep)) { @@ -305,9 +307,8 @@ class Lazaret implements ControllerProviderInterface switch ($attribute->getName()) { case AttributeInterface::NAME_METADATA: - /** - * @todo romain neutron - */ + $value = $attribute->getValue(); + $metadataBag->set($value->getTag()->getTagname(), new \PHPExiftool\Driver\Metadata\Metadata($value->getTag(), $value->getValue())); break; case AttributeInterface::NAME_STORY: $attribute->getValue()->appendChild($record); @@ -316,12 +317,16 @@ class Lazaret implements ControllerProviderInterface $record->set_binary_status($attribute->getValue()); break; case AttributeInterface::NAME_METAFIELD: - /** - * @todo romain neutron - */ + $metaFields->set($attribute->getField()->get_name(), $attribute->getValue()); break; } } + + $datas = $metadataBag->toMetadataArray($record->get_databox()->get_meta_structure()); + $record->set_metadatas($datas); + + $fields = $metaFields->toMetadataArray($record->get_databox()->get_meta_structure()); + $record->set_metadatas($fields); } //Delete lazaret file diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php b/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php index e20300981d..526270be64 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php @@ -131,9 +131,15 @@ class Tooltip implements ControllerProviderInterface { $record = new \record_adapter($app, $sbas_id, $record_id); + try { + $document = $record->get_subdef('document'); + } catch(\Exception $e) { + $document = null; + } + return $app['twig']->render( 'prod/Tooltip/TechnicalDatas.html.twig' - , array('record' => $record, 'document' => $record->get_subdef('document')) + , array('record' => $record, 'document' => $document) ); } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Upload.php b/lib/Alchemy/Phrasea/Controller/Prod/Upload.php index 563c4e9ffd..f6eef27ae5 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Upload.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Upload.php @@ -302,7 +302,8 @@ class Upload implements ControllerProviderInterface foreach ($user->ACL()->get_granted_base(array('canaddrecord')) as $collection) { $databox = $collection->get_databox(); - if (!isset($collections[$databox->get_sbas_id()])) { + + if ( ! isset($collections[$databox->get_sbas_id()])) { $collections[$databox->get_sbas_id()] = array( 'databox' => $databox, 'databox_collections' => array() diff --git a/lib/Doctrine/Repositories/BasketElementRepository.php b/lib/Doctrine/Repositories/BasketElementRepository.php index 6c1aaee9f4..11d47cfac9 100644 --- a/lib/Doctrine/Repositories/BasketElementRepository.php +++ b/lib/Doctrine/Repositories/BasketElementRepository.php @@ -65,6 +65,25 @@ class BasketElementRepository extends EntityRepository return $query->getResult(); } + public function findElementsByDatabox(\databox $databox) + { + $dql = 'SELECT e + FROM Entities\BasketElement e + JOIN e.basket b + LEFT JOIN b.validation s + LEFT JOIN s.participants p + WHERE e.sbas_id = :sbas_id'; + + $params = array( + 'sbas_id' => $databox->get_sbas_id(), + ); + + $query = $this->_em->createQuery($dql); + $query->setParameters($params); + + return $query->getResult(); + } + /** * * @param \record_adapter $record diff --git a/lib/Doctrine/Repositories/StoryWZRepository.php b/lib/Doctrine/Repositories/StoryWZRepository.php index 77c3f809bf..57462061f9 100644 --- a/lib/Doctrine/Repositories/StoryWZRepository.php +++ b/lib/Doctrine/Repositories/StoryWZRepository.php @@ -30,7 +30,7 @@ class StoryWZRepository extends EntityRepository foreach ($stories as $key => $story) { try { $story->getRecord($app)->get_title(); - } catch (\Exception_Record_AdapterNotFound $e) { + } catch (\Exception_NotFound $e) { $this->getEntityManager()->remove($story); unset($stories[$key]); } @@ -67,7 +67,7 @@ class StoryWZRepository extends EntityRepository if ($story) { try { $story->getRecord($app)->get_title(); - } catch (\Exception_Record_AdapterNotFound $e) { + } catch (\Exception_NotFound $e) { $this->getEntityManager()->remove($story); throw new \Exception_NotFound('Story not found'); } @@ -95,7 +95,7 @@ class StoryWZRepository extends EntityRepository if ($story) { try { $record = $story->getRecord($app); - } catch (\Exception_Record_AdapterNotFound $e) { + } catch (\Exception_NotFound $e) { $this->getEntityManager()->remove($story); $this->getEntityManager()->flush(); $story = null; @@ -121,7 +121,31 @@ class StoryWZRepository extends EntityRepository foreach ($stories as $key => $story) { try { $record = $story->getRecord(); - } catch (\Exception_Record_AdapterNotFound $e) { + } catch (\Exception_NotFound $e) { + $this->getEntityManager()->remove($story); + $this->getEntityManager()->flush(); + unset($stories[$key]); + } + } + + return $stories; + } + + public function findByDatabox(\databox $databox) + { + $dql = 'SELECT s FROM Entities\StoryWZ s WHERE s.sbas_id = :sbas_id'; + + $query = $this->_em->createQuery($dql); + $query->setParameters(array( + 'sbas_id' => $databox->get_sbas_id(), + )); + + $stories = $query->getResult(); + + foreach ($stories as $key => $story) { + try { + $record = $story->getRecord(); + } catch (\Exception_NotFound $e) { $this->getEntityManager()->remove($story); $this->getEntityManager()->flush(); unset($stories[$key]); diff --git a/lib/classes/API/V1/adapter.class.php b/lib/classes/API/V1/adapter.class.php index 363b0e8f00..2a44089972 100644 --- a/lib/classes/API/V1/adapter.class.php +++ b/lib/classes/API/V1/adapter.class.php @@ -26,7 +26,7 @@ class API_V1_adapter extends API_V1_Abstract * * @var string */ - protected $version = '1.2'; + protected $version = '1.3'; /** * Application context @@ -35,6 +35,9 @@ class API_V1_adapter extends API_V1_Abstract */ protected $app; + const OBJECT_TYPE_STORY = 'http://api.phraseanet.com/api/objects/story'; + const OBJECT_TYPE_STORY_METADATA_BAG = 'http://api.phraseanet.com/api/objects/story-metadata-bag'; + /** * API constructor * @@ -814,9 +817,41 @@ class API_V1_adapter extends API_V1_Abstract ); } + /** + * Search for results + * + * @param Request $request + * @return \API_V1_result + */ + public function search(Request $request) + { + $result = new API_V1_result($request, $this); + + list($ret, $search_result) = $this->prepare_search_request($request); + + $ret['results'] = array('records' => array(), 'stories' => array()); + + foreach ($search_result->get_datas()->get_elements() as $record) { + if ($record->is_grouping()) { + $ret['results']['stories'][] = $this->list_story($record); + } else { + $ret['results']['records'][] = $this->list_record($record); + } + } + + /** + * @todo donner des highlights + */ + $result->set_datas($ret); + + return $result; + } + /** * Get an API_V1_result containing the results of a records search * + * Deprecated in favor of search + * * @param Request $request * @param int $databox_id * @param string $response_type @@ -826,6 +861,22 @@ class API_V1_adapter extends API_V1_Abstract { $result = new API_V1_result($request, $this); + list($ret, $search_result) = $this->prepare_search_request($request); + + foreach ($search_result->get_datas()->get_elements() as $record) { + $ret['results'][] = $this->list_record($record); + } + + /** + * @todo donner des highlights + */ + $result->set_datas($ret); + + return $result; + } + + private function prepare_search_request(Request $request) + { $search_type = ($request->get('search_type') && in_array($request->get('search_type'), array(0, 1))) ? $request->get('search_type') : 0; @@ -918,19 +969,10 @@ class API_V1_adapter extends API_V1_Abstract 'search_indexes' => $search_result->get_search_indexes(), 'suggestions' => $search_result->get_suggestions($this->app['locale.I18n']), 'results' => array(), - 'query' => $search_engine->get_query(), + 'query' => $search_engine->get_query(), ); - foreach ($search_result->get_datas()->get_elements() as $record) { - $ret['results'][] = $this->list_record($record); - } - - /** - * @todo donner des highlights - */ - $result->set_datas($ret); - - return $result; + return array($ret, $search_result); } /** @@ -946,17 +988,25 @@ class API_V1_adapter extends API_V1_Abstract { $result = new API_V1_result($request, $this); - $containers = $this->app['phraseanet.appbox'] - ->get_databox($databox_id) - ->get_record($record_id) - ->get_container_baskets($this->app['EM'], $this->app['phraseanet.user']); + $that = $this; + $baskets = array_map(function ($basket) use ($that) { + return $that->list_basket($basket); + }, (array) $this->app['phraseanet.appbox'] + ->get_databox($databox_id) + ->get_record($record_id) + ->get_container_baskets($this->app['EM'], $this->app['phraseanet.user']) + ); - $ret = array(); - foreach ($containers as $basket) { - $ret[] = $this->list_basket($basket); - } + $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - $result->set_datas(array("baskets" => $ret)); + $stories = array_map(function ($story) use ($that) { + return $that->list_story($story); + }, array_values($record->get_grouping_parents()->get_elements())); + + $result->set_datas(array( + "baskets" => $baskets, + "stories" => $stories, + )); return $result; } @@ -1045,6 +1095,38 @@ class API_V1_adapter extends API_V1_Abstract return $result; } + /** + * Get an API_V1_result containing the story embed files + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * @param string $response_type + * @return API_V1_result + */ + public function get_story_embed(Request $request, $databox_id, $record_id) + { + + $result = new API_V1_result($request, $this); + + $record = $this->app['phraseanet.appbox'] + ->get_databox($databox_id) + ->get_record($record_id); + + $ret = array(); + + $devices = $request->get('devices', array()); + $mimes = $request->get('mimes', array()); + + foreach ($record->get_embedable_medias($devices, $mimes) as $name => $media) { + $ret[] = $this->list_embedable_media($media, $this->app['phraseanet.registry']); + } + + $result->set_datas(array("embed" => $ret)); + + return $result; + } + public function set_record_metadatas(Request $request, $databox_id, $record_id) { $result = new API_V1_result($request, $this); @@ -1165,6 +1247,30 @@ class API_V1_adapter extends API_V1_Abstract return $result; } + /** + * Return detailed informations about one story + * + * @param Request $request + * @param int $databox_id + * @param int $story_id + * @return API_V1_result + */ + public function get_story(Request $request, $databox_id, $story_id) + { + $result = new API_V1_result($request, $this); + $databox = $this->app['phraseanet.appbox']->get_databox($databox_id); + try { + $story = $databox->get_record($story_id); + $result->set_datas(array('story' => $this->list_story($story))); + } catch (Exception_NotFound $e) { + $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Story Not Found')); + } catch (Exception $e) { + $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('An error occured')); + } + + return $result; + } + /** * Return the baskets list of the authenticated user * @@ -1737,7 +1843,7 @@ class API_V1_adapter extends API_V1_Abstract * @param \Entities\Basket $basket * @return array */ - protected function list_basket(\Entities\Basket $basket) + public function list_basket(\Entities\Basket $basket) { $ret = array( 'basket_id' => $basket->getId(), @@ -1793,7 +1899,7 @@ class API_V1_adapter extends API_V1_Abstract * @param record_adapter $record * @return array */ - protected function list_record(record_adapter $record) + public function list_record(record_adapter $record) { $technicalInformation = array(); foreach ($record->get_technical_infos() as $name => $value) { @@ -1820,6 +1926,67 @@ class API_V1_adapter extends API_V1_Abstract ); } + /** + * Retrieve detailled informations about one story + * + * @param record_adapter $story + * @return array + */ + public function list_story(record_adapter $story, $includeChildren = true) + { + if (!$story->is_grouping()) { + throw new \API_V1_exception_notfound('Story not found'); + } + + $that = $this; + $records = array_map(function (\record_adapter $record) use ($that) { + return $that->list_record($record); + }, array_values($story->get_children()->get_elements())); + + $caption = $story->get_caption(); + + $format = function(caption_record $caption, $dcField) { + + $field = $caption->get_dc_field($dcField); + + if (!$field) { + return null; + } + + return $field->get_serialized_values(); + }; + + return array( + '@entity@' => self::OBJECT_TYPE_STORY, + 'databox_id' => $story->get_sbas_id(), + 'story_id' => $story->get_record_id(), + 'updated_on' => $story->get_modification_date()->format(DATE_ATOM), + 'created_on' => $story->get_creation_date()->format(DATE_ATOM), + 'collection_id' => phrasea::collFromBas($this->app, $story->get_base_id()), + 'thumbnail' => $this->list_embedable_media($story->get_thumbnail(), $this->app['phraseanet.registry']), + 'uuid' => $story->get_uuid(), + 'metadatas' => array( + '@entity@' => self::OBJECT_TYPE_STORY_METADATA_BAG, + 'dc:contributor' => $format($caption, databox_Field_DCESAbstract::Contributor), + 'dc:coverage' => $format($caption, databox_Field_DCESAbstract::Coverage), + 'dc:creator' => $format($caption, databox_Field_DCESAbstract::Creator), + 'dc:date' => $format($caption, databox_Field_DCESAbstract::Date), + 'dc:description' => $format($caption, databox_Field_DCESAbstract::Description), + 'dc:format' => $format($caption, databox_Field_DCESAbstract::Format), + 'dc:identifier' => $format($caption, databox_Field_DCESAbstract::Identifier), + 'dc:language' => $format($caption, databox_Field_DCESAbstract::Language), + 'dc:publisher' => $format($caption, databox_Field_DCESAbstract::Publisher), + 'dc:relation' => $format($caption, databox_Field_DCESAbstract::Relation), + 'dc:rights' => $format($caption, databox_Field_DCESAbstract::Rights), + 'dc:source' => $format($caption, databox_Field_DCESAbstract::Source), + 'dc:subject' => $format($caption, databox_Field_DCESAbstract::Subject), + 'dc:title' => $format($caption, databox_Field_DCESAbstract::Title), + 'dc:type' => $format($caption, databox_Field_DCESAbstract::Type), + ), + 'records' => $records, + ); + } + /** * List all databoxes of the current appbox * diff --git a/lib/classes/API/V1/result.class.php b/lib/classes/API/V1/result.class.php index 6bc5d63033..e526e25b5b 100644 --- a/lib/classes/API/V1/result.class.php +++ b/lib/classes/API/V1/result.class.php @@ -161,6 +161,16 @@ class API_V1_result return $this; } + /** + * Return response data + * + * @return array + */ + public function get_datas() + { + return (array) $this->response; + } + /** * Format the data and return serialized string * diff --git a/lib/classes/Bridge/Api/Dailymotion.class.php b/lib/classes/Bridge/Api/Dailymotion.class.php index 3b0796b071..3b39934b07 100644 --- a/lib/classes/Bridge/Api/Dailymotion.class.php +++ b/lib/classes/Bridge/Api/Dailymotion.class.php @@ -194,7 +194,19 @@ class Bridge_Api_Dailymotion extends Bridge_Api_Abstract implements Bridge_Api_I { return array(self::CONTAINER_TYPE_PLAYLIST => _('Playlists')); } + + public function get_oauth_token() + { + return $this->oauth_token; + } + public function set_oauth_token($oauth_token) + { + $this->oauth_token = $oauth_token; + + return $this; + } + /** * * @param string $type @@ -847,9 +859,8 @@ class Bridge_Api_Dailymotion extends Bridge_Api_Abstract implements Bridge_Api_I $datas = array( 'title' => $request->get('title_' . $key), 'description' => $request->get('description_' . $key), - 'category' => $request->get('category_' . $key), 'tag' => $request->get('tags_' . $key), - 'privacy' => $request->get('privacy_' . $key), + 'private' => $request->get('privacy_' . $key) === 'private' ? true : false, ); return $datas; @@ -865,9 +876,8 @@ class Bridge_Api_Dailymotion extends Bridge_Api_Abstract implements Bridge_Api_I $datas = array( 'title' => $request->get('modif_title'), 'description' => $request->get('modif_description'), - 'category' => $request->get('modif_category'), 'tags' => $request->get('modif_tags'), - 'privacy' => $request->get('modif_privacy'), + 'private' => $request->get('modif_privacy') === 'private' ? true : false, ); return $datas; @@ -908,7 +918,7 @@ class Bridge_Api_Dailymotion extends Bridge_Api_Abstract implements Bridge_Api_I * * @return array */ - private function get_fields() + public function get_fields() { return array( array( @@ -930,7 +940,7 @@ class Bridge_Api_Dailymotion extends Bridge_Api_Abstract implements Bridge_Api_I 'required' => false ) , array( - 'name' => 'privacy', + 'name' => 'private', 'length' => '0', 'length_min' => '0', 'required' => true diff --git a/lib/classes/appbox.class.php b/lib/classes/appbox.class.php index a351a8e777..a04d77ef3d 100644 --- a/lib/classes/appbox.class.php +++ b/lib/classes/appbox.class.php @@ -91,8 +91,13 @@ class appbox extends base if ($pic_type === collection::PIC_LOGO) { //resize collection logo $imageSpec = new ImageSpecification(); - $imageSpec->setResizeMode(ImageSpecification::RESIZE_MODE_INBOUND_FIXEDRATIO); - $imageSpec->setDimensions(120, 24); + + $media = $this->app['mediavorus']->guess($filename); + + if($media->getWidth() > 120 || $media->getHeight() > 24) { + $imageSpec->setResizeMode(ImageSpecification::RESIZE_MODE_INBOUND_FIXEDRATIO); + $imageSpec->setDimensions(120, 24); + } $tmp = tempnam(sys_get_temp_dir(), 'tmpdatabox') . '.jpg'; diff --git a/lib/classes/caption/record.class.php b/lib/classes/caption/record.class.php index 1fb2c41de8..bd4f956549 100644 --- a/lib/classes/caption/record.class.php +++ b/lib/classes/caption/record.class.php @@ -222,7 +222,7 @@ class caption_record implements caption_interface, cache_cacheableInterface */ public function get_dc_field($label) { - $fields = $this->get_fields(); + $fields = $this->retrieve_fields(); if (isset($this->dces_elements[$label])) { return $fields[$this->dces_elements[$label]]; } @@ -275,7 +275,7 @@ class caption_record implements caption_interface, cache_cacheableInterface foreach ($fields as $key => $value) { $n++; - + if (!isset($fields[$key])) { continue; } diff --git a/lib/classes/databox.class.php b/lib/classes/databox.class.php index bb90fc248e..0b5beffafa 100644 --- a/lib/classes/databox.class.php +++ b/lib/classes/databox.class.php @@ -322,7 +322,7 @@ class databox extends base return $ret; } - public function unmount_databox(appbox $appbox) + public function unmount_databox() { foreach ($this->get_collections() as $collection) { $collection->unmount_collection($this->app); @@ -346,6 +346,16 @@ class databox extends base $n+=50; } + foreach ($this->app['EM']->getRepository('\Entities\StoryWZ')->findByDatabox($this) as $story) { + $this->app['EM']->remove($story); + } + + foreach ($this->app['EM']->getRepository('\Entities\BasketElement')->findElementsByDatabox($this) as $element) { + $this->app['EM']->remove($element); + } + + $this->app['EM']->flush(); + $params = array(':site_id' => $this->app['phraseanet.registry']->get('GV_sit')); $sql = 'DELETE FROM clients WHERE site_id = :site_id'; @@ -359,16 +369,16 @@ class databox extends base $stmt->closeCursor(); $sql = "DELETE FROM sbas WHERE sbas_id = :sbas_id"; - $stmt = $appbox->get_connection()->prepare($sql); + $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql); $stmt->execute(array(':sbas_id' => $this->get_sbas_id())); $stmt->closeCursor(); $sql = "DELETE FROM sbasusr WHERE sbas_id = :sbas_id"; - $stmt = $appbox->get_connection()->prepare($sql); + $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql); $stmt->execute(array(':sbas_id' => $this->get_sbas_id())); $stmt->closeCursor(); - $appbox->delete_data_from_cache(appbox::CACHE_LIST_BASES); + $this->app['phraseanet.appbox']->delete_data_from_cache(appbox::CACHE_LIST_BASES); return; } diff --git a/lib/classes/module/report/activity.class.php b/lib/classes/module/report/activity.class.php index 00a2d6148f..75044ed4db 100644 --- a/lib/classes/module/report/activity.class.php +++ b/lib/classes/module/report/activity.class.php @@ -1094,7 +1094,7 @@ class module_report_activity extends module_report $stmt->closeCursor(); foreach ($rs as $row) { - $date = $this->app['date-formatter']->getPrettyString(new DateTime($row['ddate'])); + $date = $app['date-formatter']->getPrettyString(new DateTime($row['ddate'])); $result[$date] = $row['activity']; } diff --git a/lib/classes/record/adapter.class.php b/lib/classes/record/adapter.class.php index 29102ba78d..835321a409 100644 --- a/lib/classes/record/adapter.class.php +++ b/lib/classes/record/adapter.class.php @@ -382,7 +382,6 @@ class record_adapter implements record_Interface, cache_cacheableInterface */ public function get_embedable_medias($devices = null, $mimes = null) { - return $this->getSubdfefByDeviceAndMime($devices, $mimes); } @@ -715,9 +714,11 @@ class record_adapter implements record_Interface, cache_cacheableInterface $searchDevices = array_merge((array) $devices, (array) databox_subdef::DEVICE_ALL); + $type = $this->is_grouping() ? 'image' : $this->get_type(); + foreach ($this->databox->get_subdef_structure() as $group => $databoxSubdefs) { - if ($this->get_type() != $group) { + if ($type != $group) { continue; } diff --git a/lib/classes/recordutils/image.class.php b/lib/classes/recordutils/image.class.php index a8ff72641c..94f520fdee 100644 --- a/lib/classes/recordutils/image.class.php +++ b/lib/classes/recordutils/image.class.php @@ -339,7 +339,7 @@ class recordutils_image extends recordutils return $pathOut; } - if ($app['phraseanet.registry']->get('GV_pathcomposite') && + if ($app['phraseanet.registry']->get('composite_binary') && file_exists($app['phraseanet.registry']->get('GV_RootPath') . 'config/wm/' . $base_id)) { $builder = ProcessBuilder::create(array( diff --git a/lib/classes/set/export.class.php b/lib/classes/set/export.class.php index ef3cc483fa..b274840087 100644 --- a/lib/classes/set/export.class.php +++ b/lib/classes/set/export.class.php @@ -453,7 +453,7 @@ class set_export extends set_abstract if ($rename_title) { $title = strip_tags($download_element->get_title(null, null, true)); - $files[$id]['export_name'] = $unicode->remove_nonazAZ09($title, true); + $files[$id]['export_name'] = $unicode->remove_nonazAZ09($title, true, true, true); $rename_done = true; } else { $files[$id]["export_name"] = $infos['filename']; @@ -611,8 +611,8 @@ class set_export extends set_abstract $file_names[] = mb_strtolower($name); $files[$id]["export_name"] = $name; - $files[$id]["export_name"] = $unicode->remove_nonazAZ09($files[$id]["export_name"]); - $files[$id]["original_name"] = $unicode->remove_nonazAZ09($files[$id]["original_name"]); + $files[$id]["export_name"] = $unicode->remove_nonazAZ09($files[$id]["export_name"], true, true, true); + $files[$id]["original_name"] = $unicode->remove_nonazAZ09($files[$id]["original_name"], true, true, true); $i = 0; $name = utf8_decode($files[$id]["export_name"]); @@ -769,7 +769,11 @@ class set_export extends set_abstract $unicode = new \unicode(); $disposition = $disposition === 'attachment' ? ResponseHeaderBag::DISPOSITION_ATTACHMENT : ResponseHeaderBag::DISPOSITION_INLINE; - $headerDisposition = $response->headers->makeDisposition($disposition, $exportname, $unicode->remove_nonazAZ09($exportname)); + $headerDisposition = $response->headers->makeDisposition( + $disposition, + str_replace(array('/', '\\'), '', $exportname), + $unicode->remove_nonazAZ09($exportname, true, true, true) + ); if (is_file($file)) { if ($app['phraseanet.registry']->get('GV_modxsendfile')) { @@ -825,7 +829,8 @@ class set_export extends set_abstract */ public static function stream_data($data, $exportname, $mime, $disposition = 'attachment') { - + $unicode = new \unicode(); + header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); header("Cache-Control: no-store, no-cache, must-revalidate"); @@ -835,7 +840,7 @@ class set_export extends set_abstract header("Content-Length: " . strlen($data)); header("Cache-Control: max-age=3600, must-revalidate "); header("Content-Disposition: " . $disposition - . "; filename=" . $exportname . ";"); + . "; filename=" . str_replace(array('/', '\\'), '', $exportname) . ";"); echo $data; diff --git a/lib/classes/task/period/archive.class.php b/lib/classes/task/period/archive.class.php index 2f2af74363..d481d3dcb3 100755 --- a/lib/classes/task/period/archive.class.php +++ b/lib/classes/task/period/archive.class.php @@ -10,8 +10,10 @@ use Alchemy\Phrasea\Metadata\Tag as PhraseaTag; use Alchemy\Phrasea\Border\Attribute as BorderAttribute; +use Alchemy\Phrasea\Border\MetadataBag; +use Alchemy\Phrasea\Border\MetaFieldsBag; +use PHPExiftool\Driver\Metadata\MetadataBag as ExiftoolMetadataBag; use PHPExiftool\Driver\Metadata\Metadata; -use PHPExiftool\Driver\Metadata\MetadataBag; use Symfony\Component\Filesystem\Exception\IOException; /** @@ -1614,22 +1616,20 @@ class task_period_archive extends task_abstract $metadatas = $this->getIndexByFieldName($metadatasStructure, $media->getMetadatas()); if ($captionFile !== null && true === $this->dependencyContainer['filesystem']->exists($captionFile)) { - $caption = $this->readXMLForDatabox($metadatasStructure, $captionFile); + $metaFields = $this->readXMLForDatabox($metadatasStructure, $captionFile); $captionStatus = $this->parseStatusBit(@simplexml_load_file($captionFile)); if ($captionStatus) { $status = databox_status::operation_or($this->dependencyContainer, $status, $captionStatus); } - - $metadatas = $this->mergeForDatabox($metadatasStructure, $metadatas, $caption); } - $metas = $this->bagToArray($metadatasStructure, $metadatas); - $story = record_adapter::createStory($this->dependencyContainer, $collection); $story->substitute_subdef('document', $media, $this->dependencyContainer); - $story->set_metadatas($metas, true); + $story->set_metadatas($metadatas->toMetadataArray($metadatasStructure), true); + $story->set_metadatas($metaFields->toMetadataArray($metadatasStructure), true); + $story->set_binary_status(databox_status::operation_or($this->dependencyContainer, $stat0, $stat1)); $story->rebuild_subdefs(); $story->reindex(); @@ -1679,14 +1679,12 @@ class task_period_archive extends task_abstract $metadatas = $this->getIndexByFieldName($metadatasStructure, $media->getMetadatas()); if ($captionFile !== null && true === $this->dependencyContainer['filesystem']->exists($captionFile)) { - $caption = $this->readXMLForDatabox($metadatasStructure, $captionFile); + $metaFields = $this->readXMLForDatabox($metadatasStructure, $captionFile); $captionStatus = $this->parseStatusBit(@simplexml_load_file($captionFile)); if ($captionStatus) { $status = databox_status::operation_or($this->dependencyContainer, $status, $captionStatus); } - - $metadatas = $this->mergeForDatabox($metadatasStructure, $metadatas, $caption); } $file = new \Alchemy\Phrasea\Border\File($this->dependencyContainer, $media, $collection); @@ -1703,6 +1701,10 @@ class task_period_archive extends task_abstract $file->addAttribute(new BorderAttribute\Metadata($meta)); } + foreach ($metaFields as $metaField) { + $file->addAttribute($metaField); + } + if ($grp_rid) { $file->addAttribute(new BorderAttribute\Story(new record_adapter($this->dependencyContainer, $databox->get_sbas_id(), $grp_rid))); } @@ -2047,10 +2049,10 @@ class task_period_archive extends task_abstract * indexed by **FieldNames** * * @param \databox_descriptionStructure $metadatasStructure The databox structure related - * @param MetadataBag $bag The metadata bag + * @param ExiftoolMetadataBag $bag The metadata bag * @return MetadataBag */ - protected function getIndexByFieldName(\databox_descriptionStructure $metadatasStructure, MetadataBag $bag) + protected function getIndexByFieldName(\databox_descriptionStructure $metadatasStructure, ExiftoolMetadataBag $bag) { $ret = new MetadataBag(); @@ -2063,121 +2065,6 @@ class task_period_archive extends task_abstract return $ret; } - /** - * Map a bag of metadatas indexed by **FieldNames** to an array ready for - * \record_adapter metadatas submission - * - * @param \databox_descriptionStructure $metadatasStructure The databox structure related - * @param MetadataBag $metadatas The metadata bag - * @return array - */ - protected function bagToArray(\databox_descriptionStructure $metadatasStructure, MetadataBag $metadatas) - { - $metas = array(); - $unicode = new \unicode(); - - foreach ($metadatasStructure as $databox_field) { - if ($metadatas->containsKey($databox_field->get_tag()->getTagname())) { - - if ($databox_field->is_multi()) { - - $values = $metadatas->get($databox_field->get_tag()->getTagname())->getValue()->asArray(); - - $tmp = array(); - - foreach ($values as $value) { - foreach (\caption_field::get_multi_values($value, $databox_field->get_separator()) as $v) { - $tmp[] = $v; - } - } - - $values = array_unique($tmp); - - foreach ($values as $value) { - - $value = $unicode->substituteCtrlCharacters($value, ' '); - $value = $unicode->toUTF8($value); - if ($databox_field->get_type() == 'date') { - $value = $unicode->parseDate($value); - } - - $metas[] = array( - 'meta_struct_id' => $databox_field->get_id(), - 'value' => $value, - 'meta_id' => null - ); - } - } else { - $value = $metadatas->get($databox_field->get_tag()->getTagname())->getValue()->asString(); - - $value = $unicode->substituteCtrlCharacters($value, ' '); - $value = $unicode->toUTF8($value); - if ($databox_field->get_type() == 'date') { - $value = $unicode->parseDate($value); - } - - $metas[] = array( - 'meta_struct_id' => $databox_field->get_id(), - 'value' => $metadatas->get($databox_field->get_tag()->getTagname())->getValue()->asString(), - 'meta_id' => null - ); - } - } - } - - unset($unicode); - - return $metas; - } - - /** - * Merge two bags of metadatas indexed by **FieldNames** - * Return a bag indexed by **FieldNames** - * - * @param \databox_descriptionStructure $metadatasStructure The databox structure related - * @param MetadataBag $bag1 The first metadata bag - * @param MetadataBag $bag2 The second metadata bag - * @return \PHPExiftool\Driver\Metadata\MetadataBag - */ - protected function mergeForDatabox(\databox_descriptionStructure $metadatasStructure, MetadataBag $bag1, MetadataBag $bag2) - { - $metadatasBag = new MetadataBag(); - - foreach ($metadatasStructure as $databox_field) { - - $value = array(); - - $tag = $databox_field->get_tag(); - - foreach (array($bag1, $bag2) as $bag) { - - if ( ! $bag->containsKey($databox_field->get_name())) { - continue; - } - - if ($databox_field->is_multi()) { - $value = array_unique(array_merge($value, $bag->get($databox_field->get_name())->getValue()->asArray())); - } else { - $value = $bag->get($databox_field->get_name())->getValue()->asString(); - } - } - - if ( ! $value) { - continue; - } - - if ($databox_field->is_multi()) { - $value = new \PHPExiftool\Driver\Value\Multi($value); - } else { - $value = new \PHPExiftool\Driver\Value\Mono($value); - } - - $metadatasBag->set($databox_field->get_name(), new PHPExiftool\Driver\Metadata\Metadata($tag, $value)); - } - - return $metadatasBag; - } - protected function readXMLForDatabox(\databox_descriptionStructure $metadatasStructure, $pathfile) { if (false === $this->dependencyContainer['filesystem']->exists($pathfile)) { @@ -2188,10 +2075,7 @@ class task_period_archive extends task_abstract throw new \InvalidArgumentException(sprintf('Invalid XML file %s', $pathfile)); } - /** - * @todo update with metafield, ensure that metafield primes on metadata - */ - $metadataBag = new MetadataBag(); + $metadataBag = new MetaFieldsBag(); foreach ($sxcaption->description->children() as $tagname => $field) { $field = trim($field); @@ -2201,27 +2085,18 @@ class task_period_archive extends task_abstract continue; } - $tag = $meta->get_tag(); - if ($meta->is_multi()) { $fields = caption_field::get_multi_values($field, $meta->get_separator()); if ( ! $metadataBag->containsKey($meta->get_name())) { - $values = new \PHPExiftool\Driver\Value\Multi($fields); + $values = $fields; } else { - $values = $metadataBag->get($meta->get_name())->getValue(); - - foreach ($fields as $f) { - $values->addValue($f); - } + $values = array_merge($metadataBag->get($meta->get_name())->getValue(), $fields); } - /** - * fail if not tagname defined - */ - $metadataBag->set($meta->get_name(), new \PHPExiftool\Driver\Metadata\Metadata($tag, $values)); + $metadataBag->set($meta->get_name(), new BorderAttribute\MetaField($meta, $values)); } else { - $metadataBag->set($meta->get_name(), new \PHPExiftool\Driver\Metadata\Metadata($tag, new \PHPExiftool\Driver\Value\Mono($field))); + $metadataBag->set($meta->get_name(), new BorderAttribute\MetaField($meta, array($field))); } } diff --git a/templates/web/common/dialog_export.html.twig b/templates/web/common/dialog_export.html.twig index 21d4e762bc..049b3aa8a3 100644 --- a/templates/web/common/dialog_export.html.twig +++ b/templates/web/common/dialog_export.html.twig @@ -189,7 +189,7 @@

{% trans 'export::mail: contenu du mail' %}

- +

{% trans 'export::mail: fichiers joint' %}

@@ -679,10 +679,16 @@ $('#order .order_button_loader').css('visibility','hidden'); + if(!data.error) { + var title = '{% trans "Success" %}'; + } else { + var title = '{% trans "Warning !" %}'; + } + var options = { size : 'Alert', closeButton: true, - title : '{% trans "Warning !" %}' + title : title }; p4.Dialog.Create(options, 2).setContent(data.message); diff --git a/templates/web/common/technical_datas.html.twig b/templates/web/common/technical_datas.html.twig index a321d9d686..f5b2bb895f 100644 --- a/templates/web/common/technical_datas.html.twig +++ b/templates/web/common/technical_datas.html.twig @@ -1,4 +1,8 @@ -{% trans 'Record_id' %} : {{ record.get_record_id() }}
+{% if record.is_grouping() %} + {% trans 'Story_id' %} : {{ record.get_record_id() }}
+{% else %} + {% trans 'Record_id' %} : {{ record.get_record_id() }}
+{% endif %} {% if record.is_grouping() == false %} diff --git a/templates/web/lightbox/IE6/feed.html.twig b/templates/web/lightbox/IE6/feed.html.twig index 429e18b939..90f806757e 100644 --- a/templates/web/lightbox/IE6/feed.html.twig +++ b/templates/web/lightbox/IE6/feed.html.twig @@ -7,7 +7,6 @@ - {% endblock %} {% block stylesheet %} diff --git a/templates/web/lightbox/IE6/validate.html.twig b/templates/web/lightbox/IE6/validate.html.twig index 7bc36d668b..bca089d54d 100644 --- a/templates/web/lightbox/IE6/validate.html.twig +++ b/templates/web/lightbox/IE6/validate.html.twig @@ -7,7 +7,6 @@ - {% endblock %} {% block stylesheet %} diff --git a/templates/web/lightbox/feed.html.twig b/templates/web/lightbox/feed.html.twig index 7237e3697b..dffc3eab45 100644 --- a/templates/web/lightbox/feed.html.twig +++ b/templates/web/lightbox/feed.html.twig @@ -7,7 +7,6 @@ - {% endblock %} {% block stylesheet %} diff --git a/templates/web/lightbox/sc_note.html.twig b/templates/web/lightbox/sc_note.html.twig index 4a83cdb201..149b406696 100644 --- a/templates/web/lightbox/sc_note.html.twig +++ b/templates/web/lightbox/sc_note.html.twig @@ -1,33 +1,32 @@ {% if basket_element and basket_element.getBasket().getValidation() %} -
-
-
-
-
-

{% trans 'validation:: votre note' %}

-
-
- {% for validationDatas in basket_element.getValidationDatas() %} - {% if validationDatas.getNote() != '' %} -
- - {{validationDatas.getParticipant().getUser(app).get_display_name()}} - : {{ validationDatas.getNote()|nl2br }} -
- {% endif %} - {% endfor %} +
+
+
+
+

{% trans 'validation:: votre note' %}

+
+
+ {% for validationDatas in basket_element.getValidationDatas() %} + {% if validationDatas.getNote() != '' %} +
+ + {{validationDatas.getParticipant().getUser(app).get_display_name()}} + : {{ validationDatas.getNote()|nl2br }} +
+ {% endif %} + {% endfor %} -
- -
- - -
-
+
+ +
+ + +
+
-
+
{% endif %} diff --git a/templates/web/lightbox/sc_options_box.html.twig b/templates/web/lightbox/sc_options_box.html.twig index 8bbcfc94bb..07a7bc0fe5 100644 --- a/templates/web/lightbox/sc_options_box.html.twig +++ b/templates/web/lightbox/sc_options_box.html.twig @@ -1,33 +1,33 @@ {% if basket_element %} - - - - - - -
| {% if basket_element.getBasket().getValidation() %} -
-
+
{% if basket_element %} {% set bask_prev = basket_element.getRecord(app).get_preview() %} diff --git a/templates/web/prod/actions/Bridge/Dailymotion/element_informations.html.twig b/templates/web/prod/actions/Bridge/Dailymotion/element_informations.html.twig index 11e5eedaab..81032a068a 100644 --- a/templates/web/prod/actions/Bridge/Dailymotion/element_informations.html.twig +++ b/templates/web/prod/actions/Bridge/Dailymotion/element_informations.html.twig @@ -13,14 +13,16 @@ {% endtrans %} {% endif %} - {% set nb_rating = element.get_ratings|default(0) %} - {% if element.get_rating > 0 %} -
  • - {% trans %} - {{ nb_rating }} like - {% plural nb_rating %} - {{ nb_rating }} likes - {% endtrans %} -
  • - {% endif %} + {% if element.get_ratings is defined %} + {% set nb_rating = element.get_ratings|default(0) %} + {% if element.get_rating > 0 %} +
  • + {% trans %} + {{ nb_rating }} like + {% plural nb_rating %} + {{ nb_rating }} likes + {% endtrans %} +
  • + {% endif %} + {% endif %} diff --git a/templates/web/prod/actions/Bridge/index.html.twig b/templates/web/prod/actions/Bridge/index.html.twig index 134c586662..e74ab324a4 100644 --- a/templates/web/prod/actions/Bridge/index.html.twig +++ b/templates/web/prod/actions/Bridge/index.html.twig @@ -368,8 +368,8 @@ $(function() { var account_id = $('form[name="current_datas"] input[name="account_id"]').val(); $('input[name="account_id"]', $form).val(account_id); - var $panel = $('#pub_tabs .ui-tabs-panel'); - + var $panel = $('#pub_tabs .ui-tabs-panel:visible'); + $.ajax({ type : 'GET', url : '/prod/bridge/upload/', diff --git a/templates/web/prod/index.html.twig b/templates/web/prod/index.html.twig index 12e20feb31..95a05cc767 100644 --- a/templates/web/prod/index.html.twig +++ b/templates/web/prod/index.html.twig @@ -1026,7 +1026,6 @@ - - = 1073741824) { - return (bits / 1073741824).toFixed(2) + ' Gbit/s'; + // 1 byte = 8 bits + var bytes = (bits >> 3); + + if (bytes >= (1 << 30)) { + return (bytes / (1 << 30)).toFixed(2) + ' Go/s'; } - if (bits >= 1048576) { - return (bits / 1048576).toFixed(2) + ' Mbit/s'; + if (bytes >= (1 << 20)) { + return (bytes / (1 << 20)).toFixed(2) + ' Mo/s'; } - if (bits >= 1024) { - return (bits / 1024).toFixed(2) + ' Kbit/s'; + if (bytes >= (1 << 10)) { + return (bytes / (1 << 10)).toFixed(2) + ' Ko/s'; } - return bits + ' bit/s'; + return bytes + ' o/s'; }, pourcent: function(current, total){ return (current/ total * 100).toFixed(2) diff --git a/www/prod/page0.js b/www/prod/page0.js index 9a670d0de6..e16a480eb7 100644 --- a/www/prod/page0.js +++ b/www/prod/page0.js @@ -2410,20 +2410,12 @@ function downloadThis(datas) { var dialog = p4.Dialog.Create({title: language['export']}); - dialog.getDomElement().bind("dialogbeforeclose", function(event, ui) { - tinyMCE.execCommand('mceRemoveControl',true,'sendmail_message'); - tinyMCE.execCommand('mceRemoveControl',true,'order_usage'); - }); - $.post("/prod/export/multi-export/", datas, function(data) { dialog.setContent(data); $('.tabs', dialog.getDomElement()).tabs(); - tinyMCE.execCommand('mceAddControl',true,'sendmail_message'); - tinyMCE.execCommand('mceAddControl',true,'order_usage'); - $('.close_button', dialog.getDomElement()).bind('click',function(){ dialog.Close(); }); diff --git a/www/skins/lightbox/jquery.lightbox.ie6.js b/www/skins/lightbox/jquery.lightbox.ie6.js index ad9424043c..231416bb39 100644 --- a/www/skins/lightbox/jquery.lightbox.ie6.js +++ b/www/skins/lightbox/jquery.lightbox.ie6.js @@ -479,20 +479,12 @@ function download(value) { var dialog = p4.Dialog.Create({title: typeof(language) !== 'undefined' ? language['export']: ''}); - dialog.getDomElement().bind("dialogbeforeclose", function(event, ui) { - tinyMCE.execCommand('mceRemoveControl',true,'sendmail_message'); - tinyMCE.execCommand('mceRemoveControl',true,'order_usage'); - }); - $.post("/prod/export/multi-export/", "lst="+value, function(data) { dialog.setContent(data); $('.tabs', dialog.getDomElement()).tabs(); - tinyMCE.execCommand('mceAddControl',true,'sendmail_message'); - tinyMCE.execCommand('mceAddControl',true,'order_usage'); - $('.close_button', dialog.getDomElement()).bind('click',function(){ dialog.Close(); }); diff --git a/www/skins/lightbox/jquery.lightbox.js b/www/skins/lightbox/jquery.lightbox.js index 473edd978b..fe01d3cad5 100644 --- a/www/skins/lightbox/jquery.lightbox.js +++ b/www/skins/lightbox/jquery.lightbox.js @@ -414,24 +414,12 @@ function display_basket_element(compare, sselcont_id) var options_container = $('.options',container); - $('.download_button', options_container).button({ - text : false - // , - // icons : { - // primary: 'ui-icon-disk' - // } - }).bind('click',function(){ + $('.download_button', options_container).bind('click',function(){ // $(this).blur(); download($(this).next('form[name=download_form]').find('input').val()); }); - $('.comment_button', options_container).button({ - text : true - // , - // icons : { - // primary: 'ui-icon-comment' - // } - }).bind('click',function() + $('.comment_button', options_container).bind('click',function() { // $(this).blur(); if($('.container', container).hasClass('note_editing')) @@ -447,35 +435,17 @@ function display_basket_element(compare, sselcont_id) activate_notes(container); - $('.previous_button', options_container).button({ - text : false - // , - // icons : { - // primary: 'ui-icon-seek-prev' - // } - }).bind('click',function(){ + $('.previous_button', options_container).bind('click',function(){ // $(this).blur(); get_prev(); }); - $('.play_button', options_container).button({ - text : false - // , - // icons : { - // primary: 'ui-icon-play' - // } - }).bind('click',function(){ + $('.play_button', options_container).bind('click',function(){ // $(this).blur(); slideshow(true); }); - $('.pause_button', options_container).button({ - text : false - // , - // icons : { - // primary: 'ui-icon-pause' - // } - }).bind('click',function(){ + $('.pause_button', options_container).bind('click',function(){ // $(this).blur(); slideshow(false); }); @@ -489,13 +459,7 @@ function display_basket_element(compare, sselcont_id) $('.pause_button, .next_button.pause, .previous_button.pause', options_container).hide(); } - $('.next_button', options_container).button({ - text : false - // , - // icons : { - // primary: 'ui-icon-seek-next' - // } - }).bind('click',function(){ + $('.next_button', options_container).bind('click',function(){ // $(this).blur(); slideshow(false); get_next(); @@ -1078,20 +1042,12 @@ function download(value) { var dialog = p4.Dialog.Create({title: typeof(language) !== 'undefined' ? language['export']: ''}); - dialog.getDomElement().bind("dialogbeforeclose", function(event, ui) { - tinyMCE.execCommand('mceRemoveControl',true,'sendmail_message'); - tinyMCE.execCommand('mceRemoveControl',true,'order_usage'); - }); - $.post("/prod/export/multi-export/", "lst="+value, function(data) { dialog.setContent(data); $('.tabs', dialog.getDomElement()).tabs(); - tinyMCE.execCommand('mceAddControl',true,'sendmail_message'); - tinyMCE.execCommand('mceAddControl',true,'order_usage'); - $('.close_button', dialog.getDomElement()).bind('click',function(){ dialog.Close(); }); diff --git a/www/skins/lightbox/lightbox.css b/www/skins/lightbox/lightbox.css index b6b5bd479a..d7b998828c 100644 --- a/www/skins/lightbox/lightbox.css +++ b/www/skins/lightbox/lightbox.css @@ -473,6 +473,7 @@ table th i { top: -100%; height: 100%; width: 100%; + left:0px; } .record_display_box .note_wrapper { diff --git a/www/skins/lightbox/next.png b/www/skins/lightbox/next.png deleted file mode 100644 index ed9d858ab5..0000000000 Binary files a/www/skins/lightbox/next.png and /dev/null differ diff --git a/www/skins/lightbox/next_pause.png b/www/skins/lightbox/next_pause.png deleted file mode 100644 index 98a3045ed0..0000000000 Binary files a/www/skins/lightbox/next_pause.png and /dev/null differ diff --git a/www/skins/lightbox/note.png b/www/skins/lightbox/note.png deleted file mode 100644 index bb8b490016..0000000000 Binary files a/www/skins/lightbox/note.png and /dev/null differ diff --git a/www/skins/lightbox/pause.png b/www/skins/lightbox/pause.png deleted file mode 100644 index 05a3b7ce58..0000000000 Binary files a/www/skins/lightbox/pause.png and /dev/null differ diff --git a/www/skins/lightbox/play.png b/www/skins/lightbox/play.png deleted file mode 100644 index 92474796f8..0000000000 Binary files a/www/skins/lightbox/play.png and /dev/null differ diff --git a/www/skins/lightbox/prev.png b/www/skins/lightbox/prev.png deleted file mode 100644 index a5a0f6bb61..0000000000 Binary files a/www/skins/lightbox/prev.png and /dev/null differ diff --git a/www/skins/lightbox/prev_pause.png b/www/skins/lightbox/prev_pause.png deleted file mode 100644 index fe4d78d588..0000000000 Binary files a/www/skins/lightbox/prev_pause.png and /dev/null differ diff --git a/www/skins/lightbox/save.png b/www/skins/lightbox/save.png deleted file mode 100644 index fec516c0fc..0000000000 Binary files a/www/skins/lightbox/save.png and /dev/null differ