Backport of #1383.

Add logic on MediaAccessorController
This commit is contained in:
Benoît Burnichon
2015-08-12 00:20:41 +02:00
parent 657efc40e6
commit 0e8e462ca7
9 changed files with 414 additions and 45 deletions

View File

@@ -69,6 +69,7 @@ use Alchemy\Phrasea\Controller\Thesaurus\Thesaurus;
use Alchemy\Phrasea\Controller\Thesaurus\Xmlhttp as ThesaurusXMLHttp; use Alchemy\Phrasea\Controller\Thesaurus\Xmlhttp as ThesaurusXMLHttp;
use Alchemy\Phrasea\Controller\User\Notifications; use Alchemy\Phrasea\Controller\User\Notifications;
use Alchemy\Phrasea\Controller\User\Preferences; use Alchemy\Phrasea\Controller\User\Preferences;
use Alchemy\Phrasea\ControllerProvider\MediaAccessor;
use Alchemy\Phrasea\Core\PhraseaExceptionHandler; use Alchemy\Phrasea\Core\PhraseaExceptionHandler;
use Alchemy\Phrasea\Core\Provider\AccountServiceProvider; use Alchemy\Phrasea\Core\Provider\AccountServiceProvider;
use Alchemy\Phrasea\Core\Provider\AuthenticationManagerServiceProvider; use Alchemy\Phrasea\Core\Provider\AuthenticationManagerServiceProvider;
@@ -411,10 +412,12 @@ class Application extends SilexApplication
$this['log.channels'] = array('monolog', 'task-manager.logger'); $this['log.channels'] = array('monolog', 'task-manager.logger');
$this->register(new LocaleServiceProvider()); $this->register(new LocaleServiceProvider());
$this->register(new MediaAccessor());
$this->mount('/include/minify/', new Minifier()); $this->mount('/include/minify/', new Minifier());
$this->mount('/permalink/', new Permalink()); $this->mount('/permalink/', new Permalink());
$this->mount('/lightbox/', new Lightbox()); $this->mount('/lightbox/', new Lightbox());
$this->mount($this['controller.media_accessor.route_prefix'], new MediaAccessor());
$app['plugins.directory'] = $app->share(function () { $app['plugins.directory'] = $app->share(function () {
$dir = __DIR__ . '/../../../plugins'; $dir = __DIR__ . '/../../../plugins';

View File

@@ -0,0 +1,120 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Controller;
use Alchemy\Phrasea\Application;
use Firebase\JWT\JWT;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class MediaAccessorController
{
/** @var Application */
private $app;
/** @var array|\ArrayAccess */
private $keyStorage = [];
/** @var array */
private $allowedAlgorithms = [];
public function __construct(Application $app)
{
$this->app = $app;
}
/**
* @return \appbox
*/
public function getApplicationBox()
{
return $this->app['phraseanet.appbox'];
}
/**
* @param int $id
* @return \databox
*/
public function findDataboxById($id)
{
$appbox = $this->getApplicationBox();
return $appbox->get_databox($id);
}
/**
* @param array|\ArrayAccess $keyStorage
* @return $this
*/
public function setKeyStorage($keyStorage)
{
if (!is_array($keyStorage) && !$keyStorage instanceof \ArrayAccess) {
throw new \InvalidArgumentException(sprintf(
'expects $keyStorage to be an array or an instance of ArrayAccess, got %s',
is_object($keyStorage) ? get_class($keyStorage) : gettype($keyStorage)
));
}
$this->keyStorage = $keyStorage;
return $this;
}
/**
* @param array $allowedAlgorithms
* @return $this
*/
public function setAllowedAlgorithms(array $allowedAlgorithms)
{
$this->allowedAlgorithms = $allowedAlgorithms;
return $this;
}
public function showAction(Request $request, $token)
{
try {
$token = JWT::decode($token, $this->keyStorage, $this->allowedAlgorithms);
} catch (\Exception $exception) {
throw new BadRequestHttpException('invalid token', $exception);
}
if (! isset($token->sdef) || !is_array($token->sdef) || count($token->sdef) !== 3) {
throw new BadRequestHttpException('sdef should be a sub-definition identifier.');
}
list ($sbas_id, $record_id, $subdef) = $token->sdef;
try {
$databox = $this->findDataboxById($sbas_id);
$record = $databox->get_record($record_id);
$subDefinition = $record->get_subdef($subdef);
$permalink = $subDefinition->get_permalink();
} catch (\Exception $exception) {
throw new NotFoundHttpException('Media was not found', $exception);
}
$subRequest = Request::create(
(string) $permalink->get_url(),
'GET',
[],
$request->cookies->all(),
[],
$request->server->all()
);
if ($request->query->has('download')) {
$subRequest->query->set('download', $request->query->get('download'));
}
$response = $this->app->handle($subRequest, HttpKernelInterface::SUB_REQUEST, false);
// Remove Caption link header as it contains permalink token.
$response->headers->remove('link');
return $response;
}
}

View File

@@ -0,0 +1,63 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\ControllerProvider;
use Alchemy\Phrasea\Controller\MediaAccessorController;
use Alchemy\Phrasea\Model\Provider\DefaultSecretProvider;
use Doctrine\ORM\EntityManager;
use Silex\Application;
use Silex\ControllerCollection;
use Silex\ControllerProviderInterface;
use Silex\ServiceProviderInterface;
class MediaAccessor implements ServiceProviderInterface, ControllerProviderInterface
{
public function register(Application $app)
{
$app['repo.secrets'] = $app->share(function (Application $app) {
/** @var EntityManager $manager */
$manager = $app['EM'];
return $manager->getRepository('Entities\Secret');
});
$app['provider.secrets'] = $app->share(function (Application $app) {
return new DefaultSecretProvider($app['repo.secrets'], $app['random.medium']);
});
$app['controller.media_accessor'] = $app->share(function (Application $app) {
$controller = new MediaAccessorController($app);
$controller
->setAllowedAlgorithms(['HS256'])
->setKeyStorage($app['provider.secrets']);
return $controller;
});
$app['controller.media_accessor.route_prefix'] = '/medias';
}
public function boot(Application $app)
{
// Intentionally left empty
}
public function connect(Application $app)
{
/** @var ControllerCollection $controllers */
$controllers = $app['controllers_factory'];
$controllers->get('/{token}', 'controller.media_accessor:showAction')
->bind('media_accessor');
return $controllers;
}
}

View File

@@ -0,0 +1,71 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Model\Provider;
use Alchemy\Phrasea\Model\Repositories\SecretRepository;
use Entities\Secret;
use RandomLib\Generator;
/**
* This provider implements ArrayAccess to be used with php-jwt library
*/
class DefaultSecretProvider implements SecretProvider, \ArrayAccess
{
/** @var SecretRepository */
private $repository;
/** @var Generator */
private $generator;
public function __construct(SecretRepository $repository, Generator $generator)
{
$this->repository = $repository;
$this->generator = $generator;
}
public function getSecretForUser($userId)
{
$secret = $this->repository->findOneBy(['creatorId' => $userId], ['created' => 'DESC']);
if ($secret) {
return $secret;
}
$token = $this->generator->generateString(64, Generator::CHAR_ALNUM | Generator::CHAR_SYMBOLS);
$secret = new Secret($userId, $token);
$this->repository->save($secret);
return $secret;
}
public function offsetExists($offset)
{
return null !== $this->repository->find($offset);
}
public function offsetGet($offset)
{
$secret = $this->repository->find($offset);
if (!$secret instanceof Secret) {
throw new \RuntimeException('Undefined index: ' . $offset);
}
return $secret->getToken();
}
public function offsetSet($offset, $value)
{
throw new \LogicException('This ArrayAccess is non mutable.');
}
public function offsetUnset($offset)
{
throw new \LogicException('This ArrayAccess is non mutable.');
}
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Model\Provider;
use Entities\Secret;
interface SecretProvider
{
/**
* Get a secret for a user
* @param int $userId
* @return Secret
*/
public function getSecretForUser($userId);
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Model\Repositories;
use Doctrine\ORM\EntityRepository;
use Entities\Secret;
class SecretRepository extends EntityRepository
{
public function save(Secret $secret)
{
$this->_em->persist($secret);
$this->_em->flush($secret);
}
}

View File

@@ -15,12 +15,14 @@ use Alchemy\Phrasea\Account\CollectionRequestMapper;
use Alchemy\Phrasea\Account\Command\UpdateAccountCommand; use Alchemy\Phrasea\Account\Command\UpdateAccountCommand;
use Alchemy\Phrasea\Account\Command\UpdatePasswordCommand; use Alchemy\Phrasea\Account\Command\UpdatePasswordCommand;
use Alchemy\Phrasea\Form\Login\PhraseaRenewPasswordForm; use Alchemy\Phrasea\Form\Login\PhraseaRenewPasswordForm;
use Alchemy\Phrasea\Model\Provider\SecretProvider;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion; use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\File; use Alchemy\Phrasea\Border\File;
use Alchemy\Phrasea\Border\Attribute\Status; use Alchemy\Phrasea\Border\Attribute\Status;
use Alchemy\Phrasea\Border\Manager as BorderManager; use Alchemy\Phrasea\Border\Manager as BorderManager;
use Firebase\JWT\JWT;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Core\PhraseaEvents;
@@ -583,7 +585,7 @@ class API_V1_adapter extends API_V1_Abstract
$record->substitute_subdef($request->get('name'), $media, $app, $adapt); $record->substitute_subdef($request->get('name'), $media, $app, $adapt);
foreach ($record->get_embedable_medias() as $name => $media) { foreach ($record->get_embedable_medias() as $name => $media) {
if ($name == $request->get('name') && if ($name == $request->get('name') &&
null !== ($subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry']))) { null !== ($subdef = $this->listEmbeddableMedia($request, $record, $media, $this->app['phraseanet.registry']))) {
$ret[] = $subdef; $ret[] = $subdef;
} }
} }
@@ -682,9 +684,9 @@ class API_V1_adapter extends API_V1_Abstract
foreach ($search_result->getResults() as $record) { foreach ($search_result->getResults() as $record) {
if ($record->is_grouping()) { if ($record->is_grouping()) {
$ret['results']['stories'][] = $this->list_story($record, $request->get('_extended')); $ret['results']['stories'][] = $this->list_story($request, $record, $request->get('_extended'));
} else { } else {
$ret['results']['records'][] = $this->list_record($record, $request->get('_extended')); $ret['results']['records'][] = $this->list_record($request, $record, $request->get('_extended'));
} }
} }
@@ -712,7 +714,7 @@ class API_V1_adapter extends API_V1_Abstract
list($ret, $search_result) = $this->prepare_search_request($request); list($ret, $search_result) = $this->prepare_search_request($request);
foreach ($search_result->getResults() as $record) { foreach ($search_result->getResults() as $record) {
$ret['results'][] = $this->list_record($record, $request->get('_extended')); $ret['results'][] = $this->list_record($request, $record, $request->get('_extended'));
} }
/** /**
@@ -748,7 +750,7 @@ class API_V1_adapter extends API_V1_Abstract
$record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id);
$stories = array_map(function ($story) use ($that, $request) { $stories = array_map(function ($story) use ($that, $request) {
return $that->list_story($story, $request->get('_extended')); return $that->list_story($request, $story, $request->get('_extended'));
}, array_values($record->get_grouping_parents()->get_elements())); }, array_values($record->get_grouping_parents()->get_elements()));
$result->set_datas(array( $result->set_datas(array(
@@ -823,7 +825,7 @@ class API_V1_adapter extends API_V1_Abstract
$mimes = $request->get('mimes', array()); $mimes = $request->get('mimes', array());
foreach ($record->get_embedable_medias($devices, $mimes) as $name => $media) { foreach ($record->get_embedable_medias($devices, $mimes) as $name => $media) {
if (null !== $subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry'])) { if (null !== $subdef = $this->listEmbeddableMedia($request, $record, $media, $this->app['phraseanet.registry'])) {
$ret[] = $subdef; $ret[] = $subdef;
} }
} }
@@ -856,7 +858,7 @@ class API_V1_adapter extends API_V1_Abstract
$mimes = $request->get('mimes', array()); $mimes = $request->get('mimes', array());
foreach ($record->get_embedable_medias($devices, $mimes) as $name => $media) { foreach ($record->get_embedable_medias($devices, $mimes) as $name => $media) {
if (null !== $subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry'])) { if (null !== $subdef = $this->listEmbeddableMedia($request, $record, $media, $this->app['phraseanet.registry'])) {
$ret[] = $subdef; $ret[] = $subdef;
} }
} }
@@ -971,7 +973,7 @@ class API_V1_adapter extends API_V1_Abstract
try { try {
$collection = collection::get_from_base_id($this->app, $request->get('base_id')); $collection = collection::get_from_base_id($this->app, $request->get('base_id'));
$record->move_to_collection($collection, $this->app['phraseanet.appbox']); $record->move_to_collection($collection, $this->app['phraseanet.appbox']);
$result->set_datas(array("record" => $this->list_record($record, $request->get('_extended')))); $result->set_datas(array("record" => $this->list_record($request, $record, $request->get('_extended'))));
} catch (\Exception $e) { } catch (\Exception $e) {
$result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $e->getMessage()); $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $e->getMessage());
} }
@@ -993,7 +995,7 @@ class API_V1_adapter extends API_V1_Abstract
$databox = $this->app['phraseanet.appbox']->get_databox($databox_id); $databox = $this->app['phraseanet.appbox']->get_databox($databox_id);
try { try {
$record = $databox->get_record($record_id); $record = $databox->get_record($record_id);
$result->set_datas(array('record' => $this->list_record($record, $request->get('_extended')))); $result->set_datas(array('record' => $this->list_record($request, $record, $request->get('_extended'))));
} catch (NotFoundHttpException $e) { } catch (NotFoundHttpException $e) {
$result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Record Not Found')); $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Record Not Found'));
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -1017,7 +1019,7 @@ class API_V1_adapter extends API_V1_Abstract
$databox = $this->app['phraseanet.appbox']->get_databox($databox_id); $databox = $this->app['phraseanet.appbox']->get_databox($databox_id);
try { try {
$story = $databox->get_record($story_id); $story = $databox->get_record($story_id);
$result->set_datas(array('story' => $this->list_story($story, $request->get('_extended')))); $result->set_datas(array('story' => $this->list_story($request, $story, $request->get('_extended'))));
} catch (NotFoundHttpException $e) { } catch (NotFoundHttpException $e) {
$result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Story Not Found')); $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Story Not Found'));
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -1135,7 +1137,7 @@ class API_V1_adapter extends API_V1_Abstract
$result->set_datas( $result->set_datas(
array( array(
"basket" => $this->list_basket($Basket), "basket" => $this->list_basket($Basket),
"basket_elements" => $this->list_basket_content($Basket, $request->get('_extended')) "basket_elements" => $this->list_basket_content($request, $Basket, $request->get('_extended'))
) )
); );
@@ -1145,17 +1147,17 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve elements of one basket * Retrieve elements of one basket
* *
* @param Request $request
* @param \Entities\Basket $Basket * @param \Entities\Basket $Basket
* @param bool $extended * @param bool $extended
*
* @return array * @return array
*/ */
protected function list_basket_content(\Entities\Basket $Basket, $extended = false) protected function list_basket_content(Request $request, \Entities\Basket $Basket, $extended = false)
{ {
$ret = array(); $ret = array();
foreach ($Basket->getElements() as $basket_element) { foreach ($Basket->getElements() as $basket_element) {
$ret[] = $this->list_basket_element($basket_element, $extended); $ret[] = $this->list_basket_element($request, $basket_element, $extended);
} }
return $ret; return $ret;
@@ -1164,17 +1166,17 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve detailed information about a basket element * Retrieve detailed information about a basket element
* *
* @param Request $request
* @param \Entities\BasketElement $basket_element * @param \Entities\BasketElement $basket_element
* @param bool $extended * @param bool $extended
*
* @return array * @return array
*/ */
protected function list_basket_element(\Entities\BasketElement $basket_element, $extended = false) protected function list_basket_element(Request $request, \Entities\BasketElement $basket_element, $extended = false)
{ {
$ret = array( $ret = array(
'basket_element_id' => $basket_element->getId(), 'basket_element_id' => $basket_element->getId(),
'order' => $basket_element->getOrd(), 'order' => $basket_element->getOrd(),
'record' => $this->list_record($basket_element->getRecord($this->app), $extended), 'record' => $this->list_record($request, $basket_element->getRecord($this->app), $extended),
'validation_item' => null != $basket_element->getBasket()->getValidation(), 'validation_item' => null != $basket_element->getBasket()->getValidation(),
); );
@@ -1330,7 +1332,13 @@ class API_V1_adapter extends API_V1_Abstract
'feed' => $this->list_publication($feed, $user), 'feed' => $this->list_publication($feed, $user),
'offset_start' => $offset_start, 'offset_start' => $offset_start,
'per_page' => $per_page, 'per_page' => $per_page,
'entries' => $this->list_publications_entries($feed, $request->get('_extended'), $offset_start, $per_page), 'entries' => $this->list_publications_entries(
$request,
$feed,
$request->get('_extended'),
$offset_start,
$per_page
),
); );
$result->set_datas($data); $result->set_datas($data);
@@ -1363,7 +1371,13 @@ class API_V1_adapter extends API_V1_Abstract
'total_entries' => $feed->get_count_total_entries(), 'total_entries' => $feed->get_count_total_entries(),
'offset_start' => $offset_start, 'offset_start' => $offset_start,
'per_page' => $per_page, 'per_page' => $per_page,
'entries' => $this->list_publications_entries($feed, $request->get('_extended'), $offset_start, $per_page), 'entries' => $this->list_publications_entries(
$request,
$feed,
$request->get('_extended'),
$offset_start,
$per_page
),
)); ));
return $result; return $result;
@@ -1391,7 +1405,7 @@ class API_V1_adapter extends API_V1_Abstract
throw new \API_V1_exception_forbidden('You have not access to the parent feed'); throw new \API_V1_exception_forbidden('You have not access to the parent feed');
} }
$data = array('entry' => $this->list_publication_entry($entry),); $data = array('entry' => $this->list_publication_entry($request, $entry),);
$result->set_datas($data); $result->set_datas($data);
@@ -1424,20 +1438,26 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve all entries of one feed * Retrieve all entries of one feed
* *
* @param Request $request
* @param Feed_Abstract $feed * @param Feed_Abstract $feed
* @param bool $extended * @param bool $extended
* @param int $offset_start * @param int $offset_start
* @param int $how_many * @param int $how_many
*
* @return array * @return array
*/ */
protected function list_publications_entries(Feed_Abstract $feed, $extended = false, $offset_start = 0, $how_many = 5) protected function list_publications_entries(
Request $request,
Feed_Abstract $feed,
$extended = false,
$offset_start = 0,
$how_many = 5
)
{ {
$entries = $feed->get_entries($offset_start, $how_many)->get_entries(); $entries = $feed->get_entries($offset_start, $how_many)->get_entries();
$out = array(); $out = array();
foreach ($entries as $entry) { foreach ($entries as $entry) {
$out[] = $this->list_publication_entry($entry, $extended); $out[] = $this->list_publication_entry($request, $entry, $extended);
} }
return $out; return $out;
@@ -1446,16 +1466,16 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve detailed information about one feed entry * Retrieve detailed information about one feed entry
* *
* @param Request $request
* @param Feed_Entry_Adapter $entry * @param Feed_Entry_Adapter $entry
* @param bool $extended * @param bool $extended
*
* @return array * @return array
*/ */
protected function list_publication_entry(Feed_Entry_Adapter $entry, $extended = false) protected function list_publication_entry(Request $request, Feed_Entry_Adapter $entry, $extended = false)
{ {
$items = array(); $items = array();
foreach ($entry->get_content() as $item) { foreach ($entry->get_content() as $item) {
$items[] = $this->list_publication_entry_item($item, $extended); $items[] = $this->list_publication_entry_item($request, $item, $extended);
} }
return array( return array(
@@ -1477,16 +1497,16 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve detailed information about one feed entry item * Retrieve detailed information about one feed entry item
* *
* @param Request $request
* @param Feed_Entry_Item $item * @param Feed_Entry_Item $item
* @param bool $extended * @param bool $extended
*
* @return array * @return array
*/ */
protected function list_publication_entry_item(Feed_Entry_Item $item, $extended = false) protected function list_publication_entry_item(Request $request, Feed_Entry_Item $item, $extended = false)
{ {
$data = array( $data = array(
'item_id' => $item->get_id(), 'item_id' => $item->get_id(),
'record' => $this->list_record($item->get_record(), $extended) 'record' => $this->list_record($request, $item->get_record(), $extended)
); );
return $data; return $data;
@@ -1523,13 +1543,18 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve detailed information about one sub definition * Retrieve detailed information about one sub definition
* *
* @param Request $request
* @param record_adapter $record * @param record_adapter $record
* @param media_subdef $media * @param media_subdef $media
* @param registryInterface $registry * @param registryInterface $registry
*
* @return array|null * @return array|null
*/ */
protected function list_embedable_media(\record_adapter $record, media_subdef $media, registryInterface $registry) protected function listEmbeddableMedia(
Request $request,
\record_adapter $record,
media_subdef $media,
registryInterface $registry
)
{ {
if (!$media->is_physically_present()) { if (!$media->is_physically_present()) {
return null; return null;
@@ -1551,6 +1576,15 @@ class API_V1_adapter extends API_V1_Abstract
$permalink = null; $permalink = null;
} }
$urlTTL = (int)$request->get(
'subdef_url_ttl',
$registry->get('GV_default_subdef_url_ttl')
);
if ($urlTTL < 0) {
$urlTTL = -1;
}
$issuer = $this->app['authentication']->getUser();
return array( return array(
'name' => $media->get_name(), 'name' => $media->get_name(),
'substituted' => $media->is_substituted(), 'substituted' => $media->is_substituted(),
@@ -1563,9 +1597,31 @@ class API_V1_adapter extends API_V1_Abstract
'devices' => $media->getDevices(), 'devices' => $media->getDevices(),
'player_type' => $media->get_type(), 'player_type' => $media->get_type(),
'mime_type' => $media->get_mime(), 'mime_type' => $media->get_mime(),
'url' => $this->generateSubDefinitionUrl($issuer, $media, $urlTTL),
'url_ttl' => $urlTTL,
); );
} }
private function generateSubDefinitionUrl(User_Adapter $issuer, media_subdef $subdef, $url_ttl)
{
$payload = [
'iat' => time(),
'iss' => $issuer->get_id(),
'sdef' => [$subdef->get_sbas_id(), $subdef->get_record_id(), $subdef->get_name()],
];
if ($url_ttl >= 0) {
$payload['exp'] = $payload['iat'] + $url_ttl;
}
/** @var SecretProvider $provider */
$provider = $this->app['provider.secrets'];
$secret = $provider->getSecretForUser($issuer->get_id());
return $this->app->url('media_accessor', [
'token' => JWT::encode($payload, $secret->getToken(), 'HS256', $secret->getId()),
]);
}
/** /**
* Retrieve detailed information about one permalink * Retrieve detailed information about one permalink
* *
@@ -1713,12 +1769,12 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve detailed information about one record * Retrieve detailed information about one record
* *
* @param Request $request
* @param record_adapter $record * @param record_adapter $record
* @param bool $extended * @param bool $extended
*
* @return array * @return array
*/ */
public function list_record(record_adapter $record, $extended = false) public function list_record(Request $request, record_adapter $record, $extended = false)
{ {
$technicalInformation = array(); $technicalInformation = array();
foreach ($record->get_technical_infos() as $name => $value) { foreach ($record->get_technical_infos() as $name => $value) {
@@ -1739,7 +1795,12 @@ class API_V1_adapter extends API_V1_Abstract
'collection_id' => $record->get_collection_id(), 'collection_id' => $record->get_collection_id(),
'base_id' => $record->get_base_id(), 'base_id' => $record->get_base_id(),
'sha256' => $record->get_sha256(), 'sha256' => $record->get_sha256(),
'thumbnail' => $this->list_embedable_media($record, $record->get_thumbnail(), $this->app['phraseanet.registry']), 'thumbnail' => $this->listEmbeddableMedia(
$request,
$record,
$record->get_thumbnail(),
$this->app['phraseanet.registry']
),
'technical_informations' => $technicalInformation, 'technical_informations' => $technicalInformation,
'phrasea_type' => $record->get_type(), 'phrasea_type' => $record->get_type(),
'uuid' => $record->get_uuid(), 'uuid' => $record->get_uuid(),
@@ -1749,7 +1810,7 @@ class API_V1_adapter extends API_V1_Abstract
$subdefs = $caption = array(); $subdefs = $caption = array();
foreach ($record->get_embedable_medias(array(), array()) as $name => $media) { foreach ($record->get_embedable_medias(array(), array()) as $name => $media) {
if (null !== $subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry'])) { if (null !== $subdef = $this->listEmbeddableMedia($request, $record, $media, $this->app['phraseanet.registry'])) {
$subdefs[] = $subdef; $subdefs[] = $subdef;
} }
} }
@@ -1778,21 +1839,22 @@ class API_V1_adapter extends API_V1_Abstract
/** /**
* Retrieve detailed information about one story * Retrieve detailed information about one story
* *
* @param Request $request
* @param record_adapter $story * @param record_adapter $story
* @param bool $extended * @param bool $extended
*
* @return array * @return array
* @throws API_V1_exception_notfound * @throws API_V1_exception_notfound
* @throws Exception
*/ */
public function list_story(record_adapter $story, $extended = false) public function list_story(Request $request, record_adapter $story, $extended = false)
{ {
if (!$story->is_grouping()) { if (!$story->is_grouping()) {
throw new \API_V1_exception_notfound('Story not found'); throw new \API_V1_exception_notfound('Story not found');
} }
$that = $this; $that = $this;
$records = array_map(function (\record_adapter $record) use ($that, $extended) { $records = array_map(function (\record_adapter $record) use ($that, $extended, $request) {
return $that->list_record($record, $extended); return $that->list_record($request, $record, $extended);
}, array_values($story->get_children()->get_elements())); }, array_values($story->get_children()->get_elements()));
$caption = $story->get_caption(); $caption = $story->get_caption();
@@ -1815,7 +1877,12 @@ class API_V1_adapter extends API_V1_Abstract
'updated_on' => $story->get_modification_date()->format(DATE_ATOM), 'updated_on' => $story->get_modification_date()->format(DATE_ATOM),
'created_on' => $story->get_creation_date()->format(DATE_ATOM), 'created_on' => $story->get_creation_date()->format(DATE_ATOM),
'collection_id' => phrasea::collFromBas($this->app, $story->get_base_id()), 'collection_id' => phrasea::collFromBas($this->app, $story->get_base_id()),
'thumbnail' => $this->list_embedable_media($story, $story->get_thumbnail(), $this->app['phraseanet.registry']), 'thumbnail' => $this->listEmbeddableMedia(
$request,
$story,
$story->get_thumbnail(),
$this->app['phraseanet.registry']
),
'uuid' => $story->get_uuid(), 'uuid' => $story->get_uuid(),
'metadatas' => array( 'metadatas' => array(
'@entity@' => self::OBJECT_TYPE_STORY_METADATA_BAG, '@entity@' => self::OBJECT_TYPE_STORY_METADATA_BAG,

View File

@@ -1,5 +1,6 @@
Entities\Secret: Entities\Secret:
type: entity type: entity
repositoryClass: Alchemy\Phrasea\Model\Repositories\SecretRepository
table: Secrets table: Secrets
id: id:
id: id:

View File

@@ -1041,7 +1041,7 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract
/** /**
* @covers \API_V1_adapter::get_record_embed * @covers \API_V1_adapter::get_record_embed
* @covers \API_V1_adapter::list_embedable_media * @covers \API_V1_adapter::listEmbeddableMedia
* @covers \API_V1_adapter::list_permalink * @covers \API_V1_adapter::list_permalink
*/ */
public function testRecordsEmbedRoute() public function testRecordsEmbedRoute()
@@ -1129,7 +1129,7 @@ abstract class ApiAbstract extends \PhraseanetWebTestCaseAbstract
/** /**
* @covers \API_V1_adapter::get_record_embed * @covers \API_V1_adapter::get_record_embed
* @covers \API_V1_adapter::list_embedable_media * @covers \API_V1_adapter::listEmbeddableMedia
* @covers \API_V1_adapter::list_permalink * @covers \API_V1_adapter::list_permalink
*/ */
public function testStoriesEmbedRoute() public function testStoriesEmbedRoute()