From 3f4e767557146419afe3ac9843c58dc6b140c5e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Mon, 20 Apr 2015 11:04:51 +0200 Subject: [PATCH 1/6] Refactor Api OAuth2 Controller --- lib/Alchemy/Phrasea/Application.php | 1 - lib/Alchemy/Phrasea/Application/Api.php | 4 +- .../Controller/Api/OAuth2Controller.php | 206 ++++++++++++++++++ .../Phrasea/ControllerProvider/Api/OAuth2.php | 47 ++++ .../Phrasea/ControllerProvider/Api/Oauth2.php | 178 --------------- .../Repositories/ApiApplicationRepository.php | 10 + 6 files changed, 265 insertions(+), 181 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Controller/Api/OAuth2Controller.php create mode 100644 lib/Alchemy/Phrasea/ControllerProvider/Api/OAuth2.php delete mode 100644 lib/Alchemy/Phrasea/ControllerProvider/Api/Oauth2.php diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index ff9577a6bc..570ce969f0 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -12,7 +12,6 @@ namespace Alchemy\Phrasea; use Alchemy\Geonames\GeonamesServiceProvider; -use Alchemy\Phrasea\ControllerProvider\Admin\TaskManager; use Alchemy\Phrasea\ControllerProvider\Client\Root as ClientRoot; use Alchemy\Phrasea\ControllerProvider\Prod\BasketController; use Alchemy\Phrasea\ControllerProvider\Prod\Bridge; diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index b1d6b04425..3d0f2c55d7 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Api\Result; -use Alchemy\Phrasea\ControllerProvider\Api\Oauth2; +use Alchemy\Phrasea\ControllerProvider\Api\OAuth2; use Alchemy\Phrasea\ControllerProvider\Api\V1; use Alchemy\Phrasea\ControllerProvider\Datafiles; use Alchemy\Phrasea\ControllerProvider\Minifier; @@ -114,7 +114,7 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { ])->createResponse(); }); - $app->mount('/api/oauthv2', new Oauth2()); + $app->mount('/api/oauthv2', new OAuth2()); $app->mount('/datafiles/', new Datafiles()); $app->mount('/api/v1', new V1()); $app->mount('/permalink/', new Permalink()); diff --git a/lib/Alchemy/Phrasea/Controller/Api/OAuth2Controller.php b/lib/Alchemy/Phrasea/Controller/Api/OAuth2Controller.php new file mode 100644 index 0000000000..43357ecc72 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Api/OAuth2Controller.php @@ -0,0 +1,206 @@ +oAuth2Adapter = $app['oauth2-server']; + $this->dispatcher = $app['dispatcher']; + } + + /** + * AUTHORIZE ENDPOINT + * + * Authorization endpoint - used to obtain authorization from the + * resource owner via user-agent redirection. + * @param Request $request + * @return string|Response + */ + public function authorizeAction(Request $request) + { + $context = new Context(Context::CONTEXT_OAUTH2_NATIVE); + $this->dispatcher->dispatch(PhraseaEvents::PRE_AUTHENTICATE, new PreAuthenticate($request, $context)); + + //Check for auth params, send error or redirect if not valid + $params = $this->oAuth2Adapter->getAuthorizationRequestParameters($request); + + $appAuthorized = false; + $error = $request->get('error', ''); + + /** @var ApiApplicationRepository $appRepository */ + $appRepository = $this->app['repo.api-applications']; + if (null === $client = $appRepository->findByClientId($params['client_id'])) { + throw new NotFoundHttpException(sprintf('Application with client id %s could not be found', $params['client_id'])); + } + + $this->oAuth2Adapter->setClient($client); + + $actionAccept = $request->get("action_accept"); + $actionLogin = $request->get("action_login"); + + $template = "api/auth/end_user_authorization.html.twig"; + + $custom_template = sprintf( + "%s/config/templates/web/api/auth/end_user_authorization/%s.html.twig" + , $this->app['root.path'] + , $client->getId() + ); + + if (file_exists($custom_template)) { + $template = sprintf( + 'api/auth/end_user_authorization/%s.html.twig' + , $client->getId() + ); + } + + if (!$this->getAuthenticator()->isAuthenticated()) { + if ($actionLogin !== null) { + try { + /** @var PasswordAuthenticationInterface $authentication */ + $authentication = $this->app['auth.native']; + if (null === $usrId = $authentication->getUsrId($request->get("login"), $request->get("password"), $request)) { + $this->getSession()->getFlashBag() + ->set('error', $this->app->trans('login::erreur: Erreur d\'authentification')); + + return $this->app->redirectPath('oauth2_authorize', array_merge(array('error' => 'login'), $params)); + } + } catch (RequireCaptchaException $e) { + return $this->app->redirectPath('oauth2_authorize', array_merge(array('error' => 'captcha'), $params)); + } catch (AccountLockedException $e) { + return $this->app->redirectPath('oauth2_authorize', array_merge(array('error' => 'account-locked'), $params)); + } + + $user = $this->app['repo.users']->find($usrId); + $this->getAuthenticator()->openAccount($user); + $event = new PostAuthenticate($request, new Response(), $user, $context); + $this->dispatcher->dispatch(PhraseaEvents::POST_AUTHENTICATE, $event); + } else { + $r = new Response($this->render($template, array('error' => $error, "auth" => $this->oAuth2Adapter))); + $r->headers->set('Content-Type', 'text/html'); + + return $r; + } + } + + //check if current client is already authorized by current user + $clients = $appRepository->findAuthorizedAppsByUser($this->getAuthenticatedUser()); + + foreach ($clients as $authClient) { + if ($client->getClientId() == $authClient->getClientId()) { + $appAuthorized = true; + break; + } + } + + $account = $this->oAuth2Adapter->updateAccount($this->getAuthenticatedUser()); + + $params['account_id'] = $account->getId(); + + if (!$appAuthorized && $actionAccept === null) { + $params = [ + "auth" => $this->oAuth2Adapter, + "error" => $error, + ]; + + $r = new Response($this->render($template, $params)); + $r->headers->set('Content-Type', 'text/html'); + + return $r; + } elseif (!$appAuthorized && $actionAccept !== null) { + $appAuthorized = (Boolean) $actionAccept; + if ($appAuthorized) { + $this->getApiAccountManipulator() + ->authorizeAccess($account); + } else { + $this->getApiAccountManipulator() + ->revokeAccess($account); + } + } + + //if native app show template + if ($this->oAuth2Adapter->isNativeApp($params['redirect_uri'])) { + $params = $this->oAuth2Adapter->finishNativeClientAuthorization($appAuthorized, $params); + + $r = new Response($this->render("api/auth/native_app_access_token.html.twig", $params)); + $r->headers->set('Content-Type', 'text/html'); + + return $r; + } + + $this->oAuth2Adapter->finishClientAuthorization($appAuthorized, $params); + + // As OAuth2 library already outputs response content, we need to send an empty + // response to avoid breaking silex controller + return ''; + } + + /** + * TOKEN ENDPOINT + * Token endpoint - used to exchange an authorization grant for an access token. + * @param Request $request + * @return string + */ + public function tokenAction(Request $request) + { + if ( ! $request->isSecure()) { + throw new HttpException(400, 'This route requires the use of the https scheme', null, ['content-type' => 'application/json']); + } + + $this->oAuth2Adapter->grantAccessToken($request); + ob_flush(); + flush(); + + // As OAuth2 library already outputs response content, we need to send an empty + // response to avoid breaking silex controller + return ''; + } + + /** + * @return Session + */ + public function getSession() + { + return $this->app['session']; + } + + /** + * @return ApiAccountManipulator + */ + public function getApiAccountManipulator() + { + return $this->app['manipulator.api-account']; + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Api/OAuth2.php b/lib/Alchemy/Phrasea/ControllerProvider/Api/OAuth2.php new file mode 100644 index 0000000000..f5dc55e6c1 --- /dev/null +++ b/lib/Alchemy/Phrasea/ControllerProvider/Api/OAuth2.php @@ -0,0 +1,47 @@ +share(function (PhraseaApplication $app) { + return new OAuth2Controller($app); + }); + } + + public function boot(Application $app) + { + } + + public function connect(Application $app) + { + /** @var ControllerCollection $controllers */ + $controllers = $app['controllers_factory']; + + $controllers->match('/authorize', 'controller.oauth2:authorizeAction') + ->method('GET|POST') + ->bind('oauth2_authorize'); + + $controllers->post('/token', 'controller.oauth2:tokenAction'); + + return $controllers; + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Api/Oauth2.php b/lib/Alchemy/Phrasea/ControllerProvider/Api/Oauth2.php deleted file mode 100644 index 42e700ec3f..0000000000 --- a/lib/Alchemy/Phrasea/ControllerProvider/Api/Oauth2.php +++ /dev/null @@ -1,178 +0,0 @@ -dispatch(PhraseaEvents::PRE_AUTHENTICATE, new PreAuthenticate($request, $context)); - - //Check for auth params, send error or redirect if not valid - $params = $oauth2Adapter->getAuthorizationRequestParameters($request); - - $appAuthorized = false; - $error = $request->get('error', ''); - - if (null === $client = $app['repo.api-applications']->findByClientId($params['client_id'])) { - throw new NotFoundHttpException(sprintf('Application with client id %s could not be found', $params['client_id'])); - } - - $oauth2Adapter->setClient($client); - - $actionAccept = $request->get("action_accept"); - $actionLogin = $request->get("action_login"); - - $template = "api/auth/end_user_authorization.html.twig"; - - $custom_template = sprintf( - "%s/config/templates/web/api/auth/end_user_authorization/%s.html.twig" - , $app['root.path'] - , $client->getId() - ); - - if (file_exists($custom_template)) { - $template = sprintf( - 'api/auth/end_user_authorization/%s.html.twig' - , $client->getId() - ); - } - - if (!$app['authentication']->isAuthenticated()) { - if ($actionLogin !== null) { - try { - if (null === $usrId = $app['auth.native']->getUsrId($request->get("login"), $request->get("password"), $request)) { - $app['session']->getFlashBag()->set('error', $app->trans('login::erreur: Erreur d\'authentification')); - - return $app->redirectPath('oauth2_authorize', array_merge(array('error' => 'login'), $params)); - } - } catch (RequireCaptchaException $e) { - return $app->redirectPath('oauth2_authorize', array_merge(array('error' => 'captcha'), $params)); - } catch (AccountLockedException $e) { - return $app->redirectPath('oauth2_authorize', array_merge(array('error' => 'account-locked'), $params)); - } - - $user = $app['repo.users']->find($usrId); - $app['authentication']->openAccount($user); - $event = new PostAuthenticate($request, new Response(), $user, $context); - $app['dispatcher']->dispatch(PhraseaEvents::POST_AUTHENTICATE, $event); - } else { - $r = new Response($app['twig']->render($template, array('error' => $error, "auth" => $oauth2Adapter))); - $r->headers->set('Content-Type', 'text/html'); - - return $r; - } - } - - //check if current client is already authorized by current user - $clients = $app['repo.api-applications']->findAuthorizedAppsByUser($app['authentication']->getUser()); - - foreach ($clients as $authClient) { - if ($client->getClientId() == $authClient->getClientId()) { - $appAuthorized = true; - break; - } - } - - $account = $oauth2Adapter->updateAccount($app['authentication']->getUser()); - - $params['account_id'] = $account->getId(); - - if (!$appAuthorized && $actionAccept === null) { - $params = [ - "auth" => $oauth2Adapter, - "error" => $error, - ]; - - $r = new Response($app['twig']->render($template, $params)); - $r->headers->set('Content-Type', 'text/html'); - - return $r; - } elseif (!$appAuthorized && $actionAccept !== null) { - $appAuthorized = (Boolean) $actionAccept; - if ($appAuthorized) { - $app['manipulator.api-account']->authorizeAccess($account); - } else { - $app['manipulator.api-account']->revokeAccess($account); - } - } - - //if native app show template - if ($oauth2Adapter->isNativeApp($params['redirect_uri'])) { - $params = $oauth2Adapter->finishNativeClientAuthorization($appAuthorized, $params); - - $r = new Response($app['twig']->render("api/auth/native_app_access_token.html.twig", $params)); - $r->headers->set('Content-Type', 'text/html'); - - return $r; - } - - $oauth2Adapter->finishClientAuthorization($appAuthorized, $params); - - // As OAuth2 library already outputs response content, we need to send an empty - // response to avoid breaking silex controller - return ''; - }; - - $controllers->match('/authorize', $authorize_func) - ->method('GET|POST') - ->bind('oauth2_authorize'); - - /** - * TOKEN ENDPOINT - * Token endpoint - used to exchange an authorization grant for an access token. - */ - $controllers->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, ['content-type' => 'application/json']); - } - - $app['oauth2-server']->grantAccessToken($request); - ob_flush(); - flush(); - - // As OAuth2 library already outputs response content, we need to send an empty - // response to avoid breaking silex controller - return ''; - }); - - return $controllers; - } -} diff --git a/lib/Alchemy/Phrasea/Model/Repositories/ApiApplicationRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/ApiApplicationRepository.php index aff778ffe0..3645186bef 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/ApiApplicationRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/ApiApplicationRepository.php @@ -2,6 +2,7 @@ namespace Alchemy\Phrasea\Model\Repositories; +use Alchemy\Phrasea\Model\Entities\ApiApplication; use Alchemy\Phrasea\Model\Entities\User; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Query\Expr; @@ -14,6 +15,11 @@ use Doctrine\ORM\Query\Expr; */ class ApiApplicationRepository extends EntityRepository { + /** + * @param $clientId + * @return ApiApplication + * @throws \Doctrine\ORM\NonUniqueResultException + */ public function findByClientId($clientId) { $qb = $this->createQueryBuilder('app'); @@ -41,6 +47,10 @@ class ApiApplicationRepository extends EntityRepository return $qb->getQuery()->getResult(); } + /** + * @param User $user + * @return ApiApplication[] + */ public function findAuthorizedAppsByUser(User $user) { $qb = $this->createQueryBuilder('app'); From 62b8e5a6e47f570b897c7a3146ba5cd55d799815 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Mon, 27 Apr 2015 20:35:36 +0200 Subject: [PATCH 2/6] Refactoring of API V1 Controller --- lib/Alchemy/Phrasea/Application/Api.php | 2 + lib/Alchemy/Phrasea/Border/Manager.php | 4 +- .../Controller/Admin/UserController.php | 3 - .../Phrasea/Controller/Api/V1Controller.php | 2262 +++++++++++++++++ .../Phrasea/ControllerProvider/Api/V1.php | 1991 +-------------- lib/Alchemy/Phrasea/Feed/FeedInterface.php | 4 +- lib/Alchemy/Phrasea/Model/Entities/Feed.php | 4 +- .../Model/Repositories/FeedRepository.php | 3 +- .../SearchEngine/SearchEngineOptions.php | 2 +- lib/classes/caption/record.php | 8 +- lib/classes/databox/field.php | 2 +- lib/classes/record/adapter.php | 6 +- .../Phrasea/Controller/Api/ApiTestCase.php | 9 +- 13 files changed, 2404 insertions(+), 1896 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Controller/Api/V1Controller.php diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index 3d0f2c55d7..e17d30697f 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -32,6 +32,8 @@ use Symfony\Component\HttpFoundation\Response; return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { $app = new PhraseaApplication($environment); + + $app->register(new V1()); $app->loadPlugins(); $app['exception_handler'] = $app->share(function ($app) { diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php index a8bd673bcf..07a3e1e600 100644 --- a/lib/Alchemy/Phrasea/Border/Manager.php +++ b/lib/Alchemy/Phrasea/Border/Manager.php @@ -97,11 +97,11 @@ class Manager * * @param LazaretSession $session The current Lazaret Session * @param File $file A File package object - * @param type $callable A callback to execute after process + * @param callable $callable A callback to execute after process * (arguments are $element (LazaretFile or \record_adapter), * $visa (Visa) * and $code (self::RECORD_CREATED or self::LAZARET_CREATED)) - * @param type $forceBehavior Force a behavior, one of the self::FORCE_* constant + * @param bool $forceBehavior Force a behavior, one of the self::FORCE_* constant * @return int One of the self::RECORD_CREATED or self::LAZARET_CREATED constants */ public function process(LazaretSession $session, File $file, $callable = null, $forceBehavior = null, $nosubdef = false) diff --git a/lib/Alchemy/Phrasea/Controller/Admin/UserController.php b/lib/Alchemy/Phrasea/Controller/Admin/UserController.php index 7dfc23f3e6..b00602e6b8 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/UserController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/UserController.php @@ -10,9 +10,6 @@ namespace Alchemy\Phrasea\Controller\Admin; -use Alchemy\Phrasea\Application; -use Alchemy\Phrasea\Authentication\ACLProvider; -use Alchemy\Phrasea\Authentication\Authenticator; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Core\Response\CSVFileResponse; use Alchemy\Phrasea\Helper\User as UserHelper; diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php new file mode 100644 index 0000000000..5913f2778b --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php @@ -0,0 +1,2262 @@ +getDispatcher(); + $dispatcher->dispatch(PhraseaEvents::PRE_AUTHENTICATE, new PreAuthenticate($request, $context)); + $dispatcher->dispatch(PhraseaEvents::API_OAUTH2_START, new ApiOAuth2StartEvent()); + + $this->getOAuth2Server()->verifyAccessToken(); + + /** @var ApiOauthToken $token */ + if (null === $token = $this->getApiTokenRepository()->find($this->getOAuth2Server()->getToken())) { + throw new NotFoundHttpException('Provided token is not valid.'); + } + $this->getSession()->set('token', $token); + + $oAuth2Account = $token->getAccount(); + $oAuth2App = $oAuth2Account->getApplication(); + + $conf = $this->getConfiguration(); + if ($oAuth2App->getClientId() == \API_OAuth2_Application_Navigator::CLIENT_ID && !$conf->get(['registry', 'api-clients', 'navigator-enabled'])) { + return Result::createError($request, 403, 'The use of Phraseanet Navigator is not allowed')->createResponse(); + } + + if ($oAuth2App->getClientId() == \API_OAuth2_Application_OfficePlugin::CLIENT_ID && !$conf->get(['registry', 'api-clients', 'office-enabled'])) { + return Result::createError($request, 403, 'The use of Office Plugin is not allowed.')->createResponse(); + } + + $this->getAuthenticator()->openAccount($oAuth2Account->getUser()); + $this->getOAuth2Server()->rememberSession($this->getSession()); + $dispatcher->dispatch(PhraseaEvents::API_OAUTH2_END, new ApiOAuth2EndEvent()); + + return null; + } + + public function after(Request $request, Response $response) + { + /** @var ApiOauthToken $token */ + $token = $this->getSession()->get('token'); + $this->getApiLogManipulator()->create($token->getAccount(), $request, $response); + $this->getApiOAuthTokenManipulator()->setLastUsed($token, new \DateTime()); + $this->getSession()->set('token', null); + if (null !== $this->getAuthenticatedUser()) { + $this->getAuthenticator()->closeAccount(); + } + } + + public function getBadRequestAction(Request $request, $message = '') + { + $response = Result::createError($request, 400, $message)->createResponse(); + $response->headers->set('X-Status-Code', $response->getStatusCode()); + + return $response; + } + + /** + * Return an array of key-values information about scheduler + * + * @param Request $request + * @return Response + */ + public function getSchedulerAction(Request $request) + { + /** @var LiveInformation $information */ + $information = $this->app['task-manager.live-information']; + $data = $information->getManager(); + + return Result::create($request, [ + 'scheduler' => [ + 'configuration' => $data['configuration'], + 'state' => $data['actual'], + 'status' => $data['actual'], + 'pid' => $data['process-id'], + 'process-id' => $data['process-id'], + 'updated_on' => (new \DateTime())->format(DATE_ATOM), + ], + ])->createResponse(); + } + + public function indexTasksAction(Request $request) + { + $ret = array_map(function (Task $task) { + return $this->showTask($task); + }, $this->getTaskRepository()->findAll()); + + return Result::create($request, ['tasks' => $ret])->createResponse(); + } + + private function showTask(Task $task) + { + /** @var LiveInformation $information */ + $information = $this->app['task-manager.live-information']; + $data = $information->getTask($task); + + return [ + 'id' => $task->getId(), + 'title' => $task->getName(), + 'name' => $task->getName(), + 'state' => $task->getStatus(), + 'status' => $task->getStatus(), + 'actual-status' => $data['actual'], + 'process-id' => $data['process-id'], + 'pid' => $data['process-id'], + 'jobId' => $task->getJobId(), + 'period' => $task->getPeriod(), + 'last_exec_time' => $task->getLastExecution() ? $task->getLastExecution()->format(DATE_ATOM) : null, + 'last_execution' => $task->getLastExecution() ? $task->getLastExecution()->format(DATE_ATOM) : null, + 'updated' => $task->getUpdated() ? $task->getUpdated()->format(DATE_ATOM) : null, + 'created' => $task->getCreated() ? $task->getCreated()->format(DATE_ATOM) : null, + 'auto_start' => $task->getStatus() === Task::STATUS_STARTED, + 'crashed' => $task->getCrashed(), + ]; + } + + public function showTaskAction(Request $request, Task $task) + { + return Result::create($request, ['task' => $this->showTask($task)])->createResponse(); + } + + public function startTaskAction(Request $request, Task $task) + { + $this->getTaskManipulator()->start($task); + + return $this->showTaskAction($request, $task); + } + + public function stopTaskAction(Request $request, Task $task) + { + $this->getTaskManipulator()->stop($task); + + return $this->showTaskAction($request, $task); + } + + public function setTaskPropertyAction(Request $request, Task $task) + { + $title = $request->get('title'); + $autostart = $request->get('autostart'); + + if (null === $title && null === $autostart) { + return $this->getBadRequestAction($request); + } + + if ($title) { + $task->setName($title); + } + if ($autostart) { + $task->setStatus(Task::STATUS_STARTED); + } + + return $this->showTaskAction($request, $task); + } + + private function getCacheInformation() + { + $caches = [ + 'main' => $this->app['cache'], + 'op_code' => $this->app['opcode-cache'], + 'doctrine_metadatas' => $this->app['orm.em']->getConfiguration()->getMetadataCacheImpl(), + 'doctrine_query' => $this->app['orm.em']->getConfiguration()->getQueryCacheImpl(), + 'doctrine_result' => $this->app['orm.em']->getConfiguration()->getResultCacheImpl(), + ]; + + $ret = []; + + foreach ($caches as $name => $service) { + if ($service instanceof Cache) { + $ret['cache'][$name] = [ + 'type' => $service->getName(), + 'online' => $service->isOnline(), + 'stats' => $service->getStats(), + ]; + } else { + $ret['cache'][$name] = null; + } + } + + return $ret; + } + + private function getConfigInformation() + { + $ret = []; + + /** @var Version $version */ + $version = $this->app['phraseanet.version']; + $ret['phraseanet']['version'] = [ + 'name' => $version->getName(), + 'number' => $version->getNumber(), + ]; + + $ret['phraseanet']['environment'] = $this->app->getEnvironment(); + $ret['phraseanet']['debug'] = $this->app['debug']; + $conf = $this->getConfiguration(); + $ret['phraseanet']['maintenance'] = $conf->get(['main', 'maintenance']); + $ret['phraseanet']['errorsLog'] = $this->app['debug']; + $ret['phraseanet']['serverName'] = $conf->get('servername'); + + return $ret; + } + + private function getGlobalValuesInformation() + { + /** @var SearchEngineInterface $searchEngine */ + $searchEngine = $this->app['phraseanet.SE']; + try { + $SEStatus = $searchEngine->getStatus(); + } catch (\RuntimeException $e) { + $SEStatus = ['error' => $e->getMessage()]; + } + + $conf = $this->getConfiguration(); + $binaries = $conf->get(['main', 'binaries']); + + return [ + 'global_values' => [ + 'serverName' => $conf->get('servername'), + 'title' => $conf->get(['registry', 'general', 'title']), + 'keywords' => $conf->get(['registry', 'general', 'keywords']), + 'description' => $conf->get(['registry', 'general', 'description']), + 'httpServer' => [ + 'phpTimezone' => ini_get('date.timezone'), + 'siteId' => $conf->get(['main', 'key']), + 'defaultLanguage' => $conf->get(['languages', 'default']), + 'allowIndexing' => $conf->get(['registry', 'general', 'allow-indexation']), + 'modes' => [ + 'XsendFile' => $conf->get(['xsendfile', 'enabled']), + 'XsendFileMapping' => $conf->get(['xsendfile', 'mapping']), + 'h264Streaming' => $conf->get(['registry', 'executables', 'h264-streaming-enabled']), + 'authTokenDirectory' => $conf->get(['registry', 'executables', 'auth-token-directory']), + 'authTokenDirectoryPath' => $conf->get(['registry', 'executables', 'auth-token-directory-path']), + 'authTokenPassphrase' => $conf->get(['registry', 'executables', 'auth-token-passphrase']), + ], + ], + 'maintenance' => [ + 'alertMessage' => $conf->get(['registry', 'maintenance', 'message']), + 'displayMessage' => $conf->get(['registry', 'maintenance', 'enabled']), + ], + 'webServices' => [ + 'googleApi' => $conf->get(['registry', 'webservices', 'google-charts-enabled']), + 'googleAnalyticsId' => $conf->get(['registry', 'general', 'analytics']), + 'i18nWebService' => $conf->get(['registry', 'webservices', 'geonames-server']), + 'recaptacha' => [ + 'active' => $conf->get(['registry', 'webservices', 'captcha-enabled']), + 'publicKey' => $conf->get(['registry', 'webservices', 'recaptcha-public-key']), + 'privateKey' => $conf->get(['registry', 'webservices', 'recaptcha-private-key']), + ], + 'youtube' => [ + 'active' => $conf->get(['main', 'bridge', 'youtube', 'enabled']), + 'clientId' => $conf->get(['main', 'bridge', 'youtube', 'client_id']), + 'clientSecret' => $conf->get(['main', 'bridge', 'youtube', 'client_secret']), + 'devKey' => $conf->get(['main', 'bridge', 'youtube', 'developer_key']), + ], + 'flickr' => [ + 'active' => $conf->get(['main', 'bridge', 'flickr', 'enabled']), + 'clientId' => $conf->get(['main', 'bridge', 'flickr', 'client_id']), + 'clientSecret' => $conf->get(['main', 'bridge', 'flickr', 'client_secret']), + ], + 'dailymtotion' => [ + 'active' => $conf->get(['main', 'bridge', 'dailymotion', 'enabled']), + 'clientId' => $conf->get(['main', 'bridge', 'dailymotion', 'client_id']), + 'clientSecret' => $conf->get(['main', 'bridge', 'dailymotion', 'client_secret']), + ] + ], + 'navigator' => ['active' => $conf->get(['registry', 'api-clients', 'navigator-enabled']),], + 'office-plugin' => ['active' => $conf->get(['registry', 'api-clients', 'office-enabled']),], + 'homepage' => ['viewType' => $conf->get(['registry', 'general', 'home-presentation-mode']),], + 'report' => ['anonymous' => $conf->get(['registry', 'modules', 'anonymous-report']),], + 'storage' => ['documents' => $conf->get(['main', 'storage', 'subdefs']),], + 'searchEngine' => [ + 'configuration' => [ + 'defaultQuery' => $conf->get(['registry', 'searchengine', 'default-query']), + 'defaultQueryType' => $conf->get(['registry', 'searchengine', 'default-query-type']), + 'minChar' => $conf->get(['registry', 'searchengine', 'min-letters-truncation']), + ], + 'engine' => [ + 'type' => $searchEngine->getName(), + 'status' => $SEStatus, + 'configuration' => $searchEngine->getConfigurationPanel()->getConfiguration(), + ], + ], + 'binary' => [ + 'phpCli' => isset($binaries['php_binary']) ? $binaries['php_binary'] : null, + 'phpIni' => $conf->get(['registry', 'executables', 'php-conf-path']), + 'swfExtract' => isset($binaries['swf_extract_binary']) ? $binaries['swf_extract_binary'] : null, + 'pdf2swf' => isset($binaries['pdf2swf_binary']) ? $binaries['pdf2swf_binary'] : null, + 'swfRender' => isset($binaries['swf_render_binary']) ? $binaries['swf_render_binary'] : null, + 'unoconv' => isset($binaries['unoconv_binary']) ? $binaries['unoconv_binary'] : null, + 'ffmpeg' => isset($binaries['ffmpeg_binary']) ? $binaries['ffmpeg_binary'] : null, + 'ffprobe' => isset($binaries['ffprobe_binary']) ? $binaries['ffprobe_binary'] : null, + 'mp4box' => isset($binaries['mp4box_binary']) ? $binaries['mp4box_binary'] : null, + 'pdftotext' => isset($binaries['pdftotext_binary']) ? $binaries['pdftotext_binary'] : null, + 'recess' => isset($binaries['recess_binary']) ? $binaries['recess_binary'] : null, + 'pdfmaxpages' => $conf->get(['registry', 'executables', 'pdf-max-pages']), + ], + 'mainConfiguration' => [ + 'viewBasAndCollName' => $conf->get(['registry', 'actions', 'collection-display']), + 'chooseExportTitle' => $conf->get(['registry', 'actions', 'export-title-choice']), + 'defaultExportTitle' => $conf->get(['registry', 'actions', 'default-export-title']), + 'socialTools' => $conf->get(['registry', 'actions', 'social-tools']), + ], + 'modules' => [ + 'thesaurus' => $conf->get(['registry', 'modules', 'thesaurus']), + 'storyMode' => $conf->get(['registry', 'modules', 'stories']), + 'docSubsitution' => $conf->get(['registry', 'modules', 'doc-substitution']), + 'subdefSubstitution' => $conf->get(['registry', 'modules', 'thumb-substitution']), + ], + 'email' => [ + 'defaultMailAddress' => $conf->get(['registry', 'email', 'emitter-email']), + 'smtp' => [ + 'active' => $conf->get(['registry', 'email', 'smtp-enabled']), + 'auth' => $conf->get(['registry', 'email', 'smtp-auth-enabled']), + 'host' => $conf->get(['registry', 'email', 'smtp-host']), + 'port' => $conf->get(['registry', 'email', 'smtp-port']), + 'secure' => $conf->get(['registry', 'email', 'smtp-secure-mode']), + 'user' => $conf->get(['registry', 'email', 'smtp-user']), + 'password' => $conf->get(['registry', 'email', 'smtp-password']), + ], + ], + 'ftp' => [ + 'active' => $conf->get(['registry', 'ftp', 'ftp-enabled']), + 'activeForUser' => $conf->get(['registry', 'ftp', 'ftp-user-access']), + ], + 'client' => [ + 'maxSizeDownload' => $conf->get(['registry', 'actions', 'download-max-size']), + 'tabSearchMode' => $conf->get(['registry', 'classic', 'search-tab']), + 'tabAdvSearchPosition' => $conf->get(['registry', 'classic', 'adv-search-tab']), + 'tabTopicsPosition' => $conf->get(['registry', 'classic', 'topics-tab']), + 'tabOngActifPosition' => $conf->get(['registry', 'classic', 'active-tab']), + 'renderTopicsMode' => $conf->get(['registry', 'classic', 'render-topics']), + 'displayRolloverPreview' => $conf->get(['registry', 'classic', 'stories-preview']), + 'displayRolloverBasket' => $conf->get(['registry', 'classic', 'basket-rollover']), + 'collRenderMode' => $conf->get(['registry', 'classic', 'collection-presentation']), + 'viewSizeBaket' => $conf->get(['registry', 'classic', 'basket-size-display']), + 'clientAutoShowProposals' => $conf->get(['registry', 'classic', 'auto-show-proposals']), + 'needAuth2DL' => $conf->get(['registry', 'actions', 'auth-required-for-export']), + ], + 'inscription' => [ + 'autoSelectDB' => $conf->get(['registry', 'registration', 'auto-select-collections']), + 'autoRegister' => $conf->get(['registry', 'registration', 'auto-register-enabled']), + ], + 'push' => [ + 'validationReminder' => $conf->get(['registry', 'actions', 'validation-reminder-days']), + 'expirationValue' => $conf->get(['registry', 'actions', 'validation-expiration-days']), + ], + ] + ]; + } + + public function showPhraseanetConfigurationAction(Request $request) + { + $ret = array_merge( + $this->getConfigInformation(), + $this->getCacheInformation(), + $this->getGlobalValuesInformation() + ); + + return Result::create($request, $ret)->createResponse(); + } + + public function listDataboxesAction(Request $request) + { + return Result::create($request, ["databoxes" => $this->listDataboxes()])->createResponse(); + } + + private function listDataboxes() + { + return array_map(function (\databox $databox) { + return $this->listDatabox($databox); + }, $this->getApplicationBox()->get_databoxes()); + } + + private function listDatabox(\databox $databox) + { + return [ + 'databox_id' => $databox->get_sbas_id(), + 'name' => $databox->get_dbname(), + 'viewname' => $databox->get_viewname(), + 'labels' => [ + 'en' => $databox->get_label('en'), + 'de' => $databox->get_label('de'), + 'fr' => $databox->get_label('fr'), + 'nl' => $databox->get_label('nl'), + ], + 'version' => $databox->get_version(), + ]; + } + + /** + * Get a Response containing the collections of a \databox + * + * @param Request $request + * @param int $databox_id + * + * @return Response + */ + public function getDataboxCollectionsAction(Request $request, $databox_id) + { + $ret = [ + "collections" => $this->listDataboxCollections($this->findDataboxById($databox_id)) + ]; + + return Result::create($request, $ret)->createResponse(); + } + + private function listDataboxCollections(\databox $databox) + { + return array_map(function (\collection $collection) { + return $this->listCollection($collection); + }, $databox->get_collections()); + } + + private function listCollection(\collection $collection) + { + return [ + 'base_id' => $collection->get_base_id(), + 'collection_id' => $collection->get_coll_id(), + 'name' => $collection->get_name(), + 'labels' => [ + 'fr' => $collection->get_label('fr'), + 'en' => $collection->get_label('en'), + 'de' => $collection->get_label('de'), + 'nl' => $collection->get_label('nl'), + ], + 'record_amount' => $collection->get_record_amount(), + ]; + } + + /** + * Get a Response containing the status of a \databox + * + * @param Request $request + * @param int $databox_id + * + * @return Response + */ + public function getDataboxStatusAction(Request $request, $databox_id) + { + $ret = ["status" => $this->listDataboxStatus($this->findDataboxById($databox_id)->getStatusStructure())]; + + return Result::create($request, $ret)->createResponse(); + } + + private function listDataboxStatus(StatusStructure $statusStructure) + { + $ret = []; + foreach ($statusStructure as $bit => $status) { + $ret[] = [ + 'bit' => $bit, + 'label_on' => $status['labelon'], + 'label_off' => $status['labeloff'], + 'labels' => [ + 'en' => $status['labels_on_i18n']['en'], + 'fr' => $status['labels_on_i18n']['fr'], + 'de' => $status['labels_on_i18n']['de'], + 'nl' => $status['labels_on_i18n']['nl'], + ], + 'img_on' => $status['img_on'], + 'img_off' => $status['img_off'], + 'searchable' => (bool) $status['searchable'], + 'printable' => (bool) $status['printable'], + ]; + } + + return $ret; + } + + /** + * @param Request $request + * @param int $databox_id + * @return Response + */ + public function getDataboxMetadataAction(Request $request, $databox_id) + { + $ret = [ + "document_metadatas" => $this->listDataboxMetadataFields( + $this->findDataboxById($databox_id)->get_meta_structure() + ) + ]; + + return Result::create($request, $ret)->createResponse(); + } + + private function listDataboxMetadataFields(\databox_descriptionStructure $meta_struct) + { + return array_map(function ($meta) { + return $this->listDataboxMetadataFieldProperties($meta); + }, iterator_to_array($meta_struct)); + } + + private function listDataboxMetadataFieldProperties(\databox_field $databox_field) + { + return ['id' => $databox_field->get_id(), + 'namespace' => $databox_field->get_tag()->getGroupName(), + 'source' => $databox_field->get_tag()->getTagname(), + 'tagname' => $databox_field->get_tag()->getName(), + 'name' => $databox_field->get_name(), + 'labels' => [ + 'fr' => $databox_field->get_label('fr'), + 'en' => $databox_field->get_label('en'), + 'de' => $databox_field->get_label('de'), + 'nl' => $databox_field->get_label('nl'), + ], + 'separator' => $databox_field->get_separator(), + 'thesaurus_branch' => $databox_field->get_tbranch(), + 'type' => $databox_field->get_type(), + 'indexable' => $databox_field->is_indexable(), + 'multivalue' => $databox_field->is_multi(), + 'readonly' => $databox_field->is_readonly(), + 'required' => $databox_field->is_required(), + ]; + } + + /** + * Get a Response containing the terms of use of a \databox + * + * @param Request $request + * @param int $databox_id + * + * @return Response + */ + public function getDataboxTermsAction(Request $request, $databox_id) + { + $ret = ["termsOfUse" => $this->listDataboxTerms($this->findDataboxById($databox_id))]; + + return Result::create($request, $ret)->createResponse(); + } + + /** + * Retrieve CGU's for the specified \databox + * + * @param \databox $databox + * + * @return array + */ + private function listDataboxTerms(\databox $databox) + { + $ret = []; + foreach ($databox->get_cgus() as $locale => $array_terms) { + $ret[] = ['locale' => $locale, 'terms' => $array_terms['value']]; + } + + return $ret; + } + + public function listQuarantineAction(Request $request) + { + $offset_start = max($request->get('offset_start', 0), 0); + $per_page = min(max($request->get('per_page', 10), 1), 20); + + $baseIds = array_keys($this->getAclForUser()->get_granted_base(['canaddrecord'])); + + $lazaretFiles = []; + + if (count($baseIds) > 0) { + /** @var LazaretFileRepository $lazaretRepository */ + $lazaretRepository = $this->app['repo.lazaret-files']; + $lazaretFiles = iterator_to_array($lazaretRepository->findPerPage($baseIds, $offset_start, $per_page)); + } + + $ret = array_map(function ($lazaretFile) { + return $this->listLazaretFile($lazaretFile); + }, $lazaretFiles); + + $ret = ['offset_start' => $offset_start, 'per_page' => $per_page, 'quarantine_items' => $ret,]; + + return Result::create($request, $ret)->createResponse(); + } + + /** + * @param int $lazaret_id + * @param Request $request + * @return Response + */ + public function listQuarantineItemAction($lazaret_id, Request $request) + { + /** @var LazaretFileRepository $repository */ + $repository = $this->app['repo.lazaret-files']; + /** @var LazaretFile $lazaretFile */ + $lazaretFile = $repository->find($lazaret_id); + + if (null === $lazaretFile) { + return Result::createError($request, 404, sprintf('Lazaret file id %d not found', $lazaret_id))->createResponse(); + } + + if (!$this->getAclForUser()->has_right_on_base($lazaretFile->getBaseId(), 'canaddrecord')) { + return Result::createError($request, 403, 'You do not have access to this quarantine item')->createResponse(); + } + + $ret = ['quarantine_item' => $this->listLazaretFile($lazaretFile)]; + + return Result::create($request, $ret)->createResponse(); + } + + private function listLazaretFile(LazaretFile $file) + { + $manager = $this->getBorderManager(); + /** @var TranslatorInterface $translator */ + $translator = $this->app['translator']; + + $checks = array_map(function (LazaretCheck $checker) use ($manager, $translator) { + $checkerFQCN = $checker->getCheckClassname(); + return $manager->getCheckerFromFQCN($checkerFQCN)->getMessage($translator); + }, iterator_to_array($file->getChecks())); + + $usr_id = $user = null; + if ($file->getSession()->getUser()) { + $user = $file->getSession()->getUser(); + $usr_id = $user->getId(); + } + + $session = [ + 'id' => $file->getSession()->getId(), + 'usr_id' => $usr_id, + 'user' => $user ? $this->listUser($user) : null, + ]; + + return [ + 'id' => $file->getId(), + 'quarantine_session' => $session, + 'base_id' => $file->getBaseId(), + 'original_name' => $file->getOriginalName(), + 'sha256' => $file->getSha256(), + 'uuid' => $file->getUuid(), + 'forced' => $file->getForced(), + 'checks' => $file->getForced() ? [] : $checks, + 'created_on' => $file->getCreated()->format(DATE_ATOM), + 'updated_on' => $file->getUpdated()->format(DATE_ATOM), + ]; + } + + private function listUser(User $user) + { + switch ($user->getGender()) { + case User::GENDER_MRS: + $gender = 'Mrs'; + break; + case User::GENDER_MISS: + $gender = 'Miss'; + break; + case User::GENDER_MR: + default: + $gender = 'Mr'; + } + + return [ + '@entity@' => self::OBJECT_TYPE_USER, + 'id' => $user->getId(), + 'email' => $user->getEmail() ?: null, + 'login' => $user->getLogin() ?: null, + 'first_name' => $user->getFirstName() ?: null, + 'last_name' => $user->getLastName() ?: null, + 'display_name' => $user->getDisplayName() ?: null, + 'gender' => $gender, + 'address' => $user->getAddress() ?: null, + 'zip_code' => $user->getZipCode() ?: null, + 'city' => $user->getCity() ?: null, + 'country' => $user->getCountry() ?: null, + 'phone' => $user->getPhone() ?: null, + 'fax' => $user->getFax() ?: null, + 'job' => $user->getJob() ?: null, + 'position' => $user->getActivity() ?: null, + 'company' => $user->getCompany() ?: null, + 'geoname_id' => $user->getGeonameId() ?: null, + 'last_connection' => $user->getLastConnection() ? $user->getLastConnection()->format(DATE_ATOM) : null, + 'created_on' => $user->getCreated() ? $user->getCreated()->format(DATE_ATOM) : null, + 'updated_on' => $user->getUpdated() ? $user->getUpdated()->format(DATE_ATOM) : null, + 'locale' => $user->getLocale() ?: null, + ]; + } + + public function addRecordAction(Request $request) + { + if (count($request->files->get('file')) == 0) { + return $this->getBadRequestAction($request, 'Missing file parameter'); + } + + $file = $request->files->get('file'); + if (!$file instanceof UploadedFile) { + return $this->getBadRequestAction($request, 'You can upload one file at time'); + } + + if (!$file->isValid()) { + return $this->getBadRequestAction($request, 'Data corrupted, please try again'); + } + + if (!$request->get('base_id')) { + return $this->getBadRequestAction($request, 'Missing base_id parameter'); + } + + $collection = \collection::get_from_base_id($this->app, $request->get('base_id')); + + if (!$this->getAclForUser()->has_right_on_base($request->get('base_id'), 'canaddrecord')) { + return Result::createError($request, 403, sprintf( + 'You do not have access to collection %s', $collection->get_label($this->app['locale']) + ))->createResponse(); + } + + /** @var MediaVorus $mediavorus */ + $mediavorus = $this->app['mediavorus']; + $media = $mediavorus->guess($file->getPathname()); + + $Package = new File($this->app, $media, $collection, $file->getClientOriginalName()); + + if ($request->get('status')) { + $Package->addAttribute(new Status($this->app, $request->get('status'))); + } + + $session = new LazaretSession(); + $session->setUser($this->getAuthenticatedUser()); + + $entityManager = $this->app['orm.em']; + $entityManager->persist($session); + $entityManager->flush(); + + $reasons = $output = null; + + $translator = $this->app['translator']; + $callback = function ($element, Visa $visa) use ($translator, &$reasons, &$output) { + if (!$visa->isValid()) { + $reasons = array_map(function (CheckerResponse $response) use ($translator) { + return $response->getMessage($translator); + }, $visa->getResponses()); + } + + $output = $element; + }; + + switch ($request->get('forceBehavior')) { + case '0' : + $behavior = Manager::FORCE_RECORD; + break; + case '1' : + $behavior = Manager::FORCE_LAZARET; + break; + case null: + $behavior = null; + break; + default: + return $this->getBadRequestAction($request, sprintf( + 'Invalid forceBehavior value `%s`', $request->get('forceBehavior') + )); + } + + $nosubdef = $request->get('nosubdefs') === '' || \p4field::isyes($request->get('nosubdefs')); + $this->getBorderManager()->process($session, $Package, $callback, $behavior, $nosubdef); + + $ret = ['entity' => null]; + + if ($output instanceof \record_adapter) { + $ret['entity'] = '0'; + $ret['url'] = '/records/' . $output->get_sbas_id() . '/' . $output->get_record_id() . '/'; + $this->getDispatcher()->dispatch(PhraseaEvents::RECORD_UPLOAD, new RecordEdit($output)); + } + if ($output instanceof LazaretFile) { + $ret['entity'] = '1'; + $ret['url'] = '/quarantine/item/' . $output->getId() . '/'; + } + + return Result::create($request, $ret)->createResponse(); + } + + public function substituteAction(Request $request) + { + $ret = array(); + + if (count($request->files->get('file')) == 0) { + return $this->getBadRequestAction($request, 'Missing file parameter'); + } + $file = $request->files->get('file'); + if (!$file instanceof UploadedFile) { + return $this->getBadRequestAction($request, 'You can upload one file at time'); + } + + if (!$file->isValid()) { + return $this->getBadRequestAction($request, 'Data corrupted, please try again'); + } + if (!$request->get('databox_id')) { + $this->getBadRequestAction($request, 'Missing databox_id parameter'); + } + if (!$request->get('record_id')) { + $this->getBadRequestAction($request, 'Missing record_id parameter'); + } + if (!$request->get('name')) { + return $this->getBadRequestAction($request, 'Missing name parameter'); + } + + /** @var MediaVorus $mediavorus */ + $mediavorus = $this->app['mediavorus']; + $media = $mediavorus->guess($file->getPathname()); + $record = $this->findDataboxById($request->get('databox_id'))->get_record($request->get('record_id')); + $base_id = $record->get_base_id(); + $collection = \collection::get_from_base_id($this->app, $base_id); + if (!$this->getAclForUser()->has_right_on_base($base_id, 'canaddrecord')) { + return Result::create($request, 403, sprintf( + 'You do not have access to collection %s', $collection->get_label($this->app['locale.I18n']) + )); + } + $record->substitute_subdef($request->get('name'), $media, $this->app); + foreach ($record->get_embedable_medias() as $name => $media) { + if ($name == $request->get('name') && + null !== ($subdef = $this->listEmbeddableMedia($record, $media, $this->app['phraseanet.registry']))) { + $ret[] = $subdef; + } + } + + return Result::create($request, $ret)->createResponse(); + } + + private function listEmbeddableMedia(\record_adapter $record, \media_subdef $media) + { + if (!$media->is_physically_present()) { + return null; + } + + if ($this->getAuthenticator()->isAuthenticated()) { + $acl = $this->getAclForUser(); + if ($media->get_name() !== 'document' + && false === $acl->has_access_to_subdef($record, $media->get_name()) + ) { + return null; + } + if ($media->get_name() === 'document' + && !$acl->has_right_on_base($record->get_base_id(), 'candwnldhd') + && !$acl->has_hd_grant($record) + ) { + return null; + } + } + + if ($media->get_permalink() instanceof \media_Permalink_Adapter) { + $permalink = $this->listPermalink($media->get_permalink()); + } else { + $permalink = null; + } + + return [ + 'name' => $media->get_name(), + 'permalink' => $permalink, + 'height' => $media->get_height(), + 'width' => $media->get_width(), + 'filesize' => $media->get_size(), + 'devices' => $media->getDevices(), + 'player_type' => $media->get_type(), + 'mime_type' => $media->get_mime(), + 'substituted' => $media->is_substituted(), + 'created_on' => $media->get_creation_date()->format(DATE_ATOM), + 'updated_on' => $media->get_modification_date()->format(DATE_ATOM), + ]; + } + + private function listPermalink(\media_Permalink_Adapter $permalink) + { + $downloadUrl = $permalink->get_url(); + $downloadUrl->getQuery()->set('download', '1'); + + return [ + 'created_on' => $permalink->get_created_on()->format(DATE_ATOM), + 'id' => $permalink->get_id(), + 'is_activated' => $permalink->get_is_activated(), + /** @Ignore */ + 'label' => $permalink->get_label(), + 'updated_on' => $permalink->get_last_modified()->format(DATE_ATOM), + 'page_url' => $permalink->get_page(), + 'download_url' => (string)$downloadUrl, + 'url' => (string)$permalink->get_url(), + ]; + } + + /** + * Search for results + * + * @param Request $request + * + * @return Response + */ + public function searchAction(Request $request) + { + list($ret, $search_result) = $this->prepareSearchRequest($request); + + $ret['results'] = ['records' => [], 'stories' => []]; + + /** @var SearchEngineResult $search_result */ + foreach ($search_result->getResults() as $es_record) { + try { + $record = new \record_adapter($this->app, $es_record->getDataboxId(), $es_record->getRecordId()); + } catch (\Exception $e) { + continue; + } + + + if ($record->is_grouping()) { + $ret['results']['stories'][] = $this->listStory($request, $record); + } else { + $ret['results']['records'][] = $this->listRecord($record); + } + } + + return Result::create($request, $ret)->createResponse(); + } + + /** + * Get a Response containing the results of a records search + * + * @deprecated in favor of search + * + * @param Request $request + * + * @return Response + */ + public function searchRecordsAction(Request $request) + { + list($ret, $search_result) = $this->prepareSearchRequest($request); + + /** @var SearchEngineResult $search_result */ + foreach ($search_result->getResults() as $es_record) { + try { + $record = new \record_adapter($this->app, $es_record->getDataboxId(), $es_record->getRecordId()); + } catch (\Exception $e) { + continue; + } + + $ret['results'][] = $this->listRecord($record); + } + + return Result::create($request, $ret)->createResponse(); + } + + private function prepareSearchRequest(Request $request) + { + $options = SearchEngineOptions::fromRequest($this->app, $request); + + $offsetStart = (int) ($request->get('offset_start') ?: 0); + $perPage = (int) $request->get('per_page') ?: 10; + + $query = (string) $request->get('query'); + $this->getSearchEngine()->resetCache(); + + $search_result = $this->getSearchEngine()->query($query, $offsetStart, $perPage, $options); + + $this->getUserManipulator()->logQuery($this->getAuthenticatedUser(), $search_result->getQuery()); + + foreach ($options->getDataboxes() as $databox) { + $colls = array_map(function (\collection $collection) { + return $collection->get_coll_id(); + }, array_filter($options->getCollections(), function (\collection $collection) use ($databox) { + return $collection->get_databox()->get_sbas_id() == $databox->get_sbas_id(); + })); + + $this->getSearchEngineLogger() + ->log($databox, $search_result->getQuery(), $search_result->getTotal(), $colls); + } + + $this->getSearchEngine()->clearCache(); + + $ret = [ + 'offset_start' => $offsetStart, + 'per_page' => $perPage, + 'available_results' => $search_result->getAvailable(), + 'total_results' => $search_result->getTotal(), + 'error' => (string)$search_result->getError(), + 'warning' => (string)$search_result->getWarning(), + 'query_time' => $search_result->getDuration(), + 'search_indexes' => $search_result->getIndexes(), + 'suggestions' => array_map( + function (SearchEngineSuggestion $suggestion) { + return $suggestion->toArray(); + }, $search_result->getSuggestions()->toArray()), + 'results' => [], + 'query' => $search_result->getQuery(), + ]; + + return [$ret, $search_result]; + } + + /** + * Retrieve detailed information about one record + * + * @param \record_adapter $record + * + * @return array + */ + public function listRecord(\record_adapter $record) + { + $technicalInformation = []; + foreach ($record->get_technical_infos() as $name => $value) { + $technicalInformation[] = ['name' => $name, 'value' => $value]; + } + + return [ + 'databox_id' => $record->get_sbas_id(), + 'record_id' => $record->get_record_id(), + 'mime_type' => $record->get_mime(), + 'title' => $record->get_title(), + 'original_name' => $record->get_original_name(), + 'updated_on' => $record->get_modification_date()->format(DATE_ATOM), + 'created_on' => $record->get_creation_date()->format(DATE_ATOM), + 'collection_id' => \phrasea::collFromBas($this->app, $record->get_base_id()), + 'sha256' => $record->get_sha256(), + 'thumbnail' => $this->listEmbeddableMedia($record, $record->get_thumbnail()), + 'technical_informations' => $technicalInformation, + 'phrasea_type' => $record->get_type(), + 'uuid' => $record->get_uuid(), + ]; + } + + /** + * Retrieve detailed information about one story + * + * @param Request $request + * @param \record_adapter $story + * @return array + * @throws \Exception + */ + public function listStory(Request $request, \record_adapter $story) + { + if (!$story->is_grouping()) { + return Result::createError($request, 404, 'Story not found')->createResponse(); + } + + $records = array_map(function (\record_adapter $record) { + return $this->listRecord($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 [ + '@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->listEmbeddableMedia($story, $story->get_thumbnail()), + 'uuid' => $story->get_uuid(), + 'metadatas' => [ + '@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, + ]; + } + + /** + * @param Request $request + * @param int $databox_id + * @param int $record_id + * @return Response + */ + public function getRecordCaptionAction(Request $request, $databox_id, $record_id) + { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + $fields = $record->get_caption()->get_fields(); + + $ret = [ + 'caption_metadatas' => array_map(function (\caption_field $field) { + return [ + 'meta_structure_id' => $field->get_meta_struct_id(), + 'name' => $field->get_name(), + 'value' => $field->get_serialized_values(";"), + ]; + }, $fields), + ]; + + return Result::create($request, $ret)->createResponse(); + } + + /** + * Get a Response containing the record metadata + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function getRecordMetadataAction(Request $request, $databox_id, $record_id) + { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + $ret = ["record_metadatas" => $this->listRecordCaption($record->get_caption())]; + + return Result::create($request, $ret)->createResponse(); + } + + /** + * List all fields about a specified caption + * + * @param \caption_record $caption + * + * @return array + */ + private function listRecordCaption(\caption_record $caption) + { + $ret = []; + foreach ($caption->get_fields() as $field) { + foreach ($field->get_values() as $value) { + $ret[] = $this->listRecordCaptionField($value, $field); + } + } + + return $ret; + } + + /** + * Retrieve information about a caption field + * + * @param \caption_Field_Value $value + * @param \caption_field $field + * @return array + */ + private function listRecordCaptionField(\caption_Field_Value $value, \caption_field $field) + { + return [ + 'meta_id' => $value->getId(), + 'meta_structure_id' => $field->get_meta_struct_id(), + 'name' => $field->get_name(), + 'labels' => [ + 'fr' => $field->get_databox_field()->get_label('fr'), + 'en' => $field->get_databox_field()->get_label('en'), + 'de' => $field->get_databox_field()->get_label('de'), + 'nl' => $field->get_databox_field()->get_label('nl'), + ], + 'value' => $value->getValue(), + ]; + } + + /** + * Get a Response containing the record status + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function getRecordStatusAction(Request $request, $databox_id, $record_id) + { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + + $ret = ["status" => $this->listRecordStatus($record)]; + + return Result::create($request, $ret)->createResponse(); + } + + /** + * Retrieve detailed information about one status + * + * @param \record_adapter $record + * @return array + */ + private function listRecordStatus(\record_adapter $record) + { + $ret = []; + foreach ($record->getStatusStructure() as $bit => $status) { + $ret[] = [ + 'bit' => $bit, + 'state' => \databox_status::bitIsSet($record->getStatusBitField(), $bit) + ]; + } + + return $ret; + } + + /** + * Get a Response containing the baskets where the record is in + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function getRelatedRecordsAction(Request $request, $databox_id, $record_id) + { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + + $baskets = array_map(function (Basket $basket) { + return $this->listBasket($basket); + }, (array) $record->get_container_baskets($this->app['orm.em'], $this->getAuthenticatedUser())); + + + $stories = array_map(function (\record_adapter $story) use ($request) { + return $this->listStory($request, $story); + }, array_values($record->get_grouping_parents()->get_elements())); + + return Result::create($request, ["baskets" => $baskets, "stories" => $stories])->createResponse(); + } + + /** + * Retrieve information about one basket + * + * @param Basket $basket + * + * @return array + */ + private function listBasket(Basket $basket) + { + $ret = [ + 'basket_id' => $basket->getId(), + 'owner' => $this->listUser($basket->getUser()), + 'created_on' => $basket->getCreated()->format(DATE_ATOM), + 'description' => (string) $basket->getDescription(), + 'name' => $basket->getName(), + 'pusher_usr_id' => $basket->getPusher() ? $basket->getPusher()->getId() : null, + 'pusher' => $basket->getPusher() ? $this->listUser($basket->getPusher()) : null, + 'updated_on' => $basket->getUpdated()->format(DATE_ATOM), + 'unread' => !$basket->getIsRead(), + 'validation_basket' => !!$basket->getValidation(), + ]; + + if ($basket->getValidation()) { + $users = array_map(function (ValidationParticipant $participant) { + $user = $participant->getUser(); + + return [ + 'usr_id' => $user->getId(), + 'usr_name' => $user->getDisplayName(), + 'confirmed' => $participant->getIsConfirmed(), + 'can_agree' => $participant->getCanAgree(), + 'can_see_others' => $participant->getCanSeeOthers(), + 'readonly' => $user->getId() != $this->getAuthenticatedUser()->getId(), + 'user' => $this->listUser($user), + ]; + }, iterator_to_array($basket->getValidation()->getParticipants())); + + $expires_on_atom = $basket->getValidation()->getExpires(); + + if ($expires_on_atom instanceof \DateTime) { + $expires_on_atom = $expires_on_atom->format(DATE_ATOM); + } + + $ret = array_merge([ + 'validation_users' => $users, + 'expires_on' => $expires_on_atom, + 'validation_infos' => $basket->getValidation() + ->getValidationString($this->app, $this->getAuthenticatedUser()), + 'validation_confirmed' => $basket->getValidation() + ->getParticipant($this->getAuthenticatedUser()) + ->getIsConfirmed(), + 'validation_initiator' => $basket->getValidation() + ->isInitiator($this->getAuthenticatedUser()), + 'validation_initiator_user' => $this->listUser($basket->getValidation()->getInitiator()), + ], $ret); + } + + return $ret; + } + + /** + * Get a Response containing the record embed files + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function getEmbeddedRecordAction(Request $request, $databox_id, $record_id) + { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + + $devices = $request->get('devices', []); + $mimes = $request->get('mimes', []); + + $ret = array_filter(array_map(function ($media) use ($record) { + return $this->listEmbeddableMedia($record, $media); + }, $record->get_embedable_medias($devices, $mimes))); + + return Result::create($request, ["embed" => $ret])->createResponse(); + } + + public function setRecordMetadataAction(Request $request, $databox_id, $record_id) + { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + $metadata = $request->get('metadatas'); + + if (!is_array($metadata)) { + return $this->getBadRequestAction($request, 'Metadatas should be an array'); + } + + foreach ($metadata as $item) { + if (!is_array($item)) { + return $this->getBadRequestAction($request, 'Each Metadata value should be an array'); + } + } + + $record->set_metadatas($metadata); + + return Result::create($request, [ + "record_metadatas" => $this->listRecordCaption($record->get_caption()), + ])->createResponse(); + } + + /** + * @param Request $request + * @param int $databox_id + * @param int $record_id + * @return Response + */ + public function setRecordStatusAction(Request $request, $databox_id, $record_id) + { + $databox = $this->findDataboxById($databox_id); + $record = $databox->get_record($record_id); + $statusStructure = $databox->getStatusStructure(); + + $status = $request->get('status'); + + $datas = strrev($record->get_status()); + + if (!is_array($status)) { + return $this->getBadRequestAction($request); + } + foreach ($status as $n => $value) { + if ($n > 31 || $n < 4) { + return $this->getBadRequestAction($request); + } + if (!in_array($value, ['0', '1'])) { + return $this->getBadRequestAction($request); + } + if (!$statusStructure->hasStatus($n)) { + return $this->getBadRequestAction($request); + } + + $datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 2)); + } + + $record->set_binary_status(strrev($datas)); + + // @todo Move event dispatch inside record_adapter class (keeps things encapsulated) + $this->getDispatcher()->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($record)); + + $ret = ["status" => $this->listRecordStatus($record)]; + + return Result::create($request, $ret)->createResponse(); + } + + /** + * Return detailed information about one record + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function getRecordAction(Request $request, $databox_id, $record_id) + { + try { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + + return Result::create($request, ['record' => $this->listRecord($record)])->createResponse(); + } catch (NotFoundHttpException $e) { + return Result::createError($request, 404, $this->app->trans('Record Not Found'))->createResponse(); + } catch (\Exception $e) { + return $this->getBadRequestAction($request, $this->app->trans('An error occurred')); + } + } + + /** + * Move a record to another collection + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function setRecordCollectionAction(Request $request, $databox_id, $record_id) + { + $databox = $this->findDataboxById($databox_id); + $record = $databox->get_record($record_id); + + try { + $collection = \collection::get_from_base_id($this->app, $request->get('base_id')); + $record->move_to_collection($collection, $this->getApplicationBox()); + + return Result::create($request, ["record" => $this->listRecord($record)])->createResponse(); + } catch (\Exception $e) { + return $this->getBadRequestAction($this->app, $request, $e->getMessage()); + } + } + + /** + * Return the baskets list of the authenticated user + * + * @param Request $request + * + * @return Response + */ + public function searchBasketsAction(Request $request) + { + return Result::create($request, ['baskets' => $this->listBaskets()])->createResponse(); + } + + /** + * Return a baskets list + ** + * @return array + */ + private function listBaskets() + { + /** @var BasketRepository $repo */ + $repo = $this->app['repo.baskets']; + + return array_map(function (Basket $basket) { + return $this->listBasket($basket); + }, $repo->findActiveByUser($this->getAuthenticatedUser())); + } + + /** + * Create a new basket + * + * @param Request $request + * + * @return Response + */ + public function createBasketAction(Request $request) + { + $name = $request->get('name'); + + if (trim(strip_tags($name)) === '') { + return $this->getBadRequestAction($request, 'Missing basket name parameter'); + } + + $Basket = new Basket(); + $Basket->setUser($this->getAuthenticatedUser()); + $Basket->setName($name); + + /** @var EntityManager $em */ + $em = $this->app['orm.em']; + $em->persist($Basket); + $em->flush(); + + return Result::create($request, ["basket" => $this->listBasket($Basket)])->createResponse(); + } + + /** + * Retrieve a basket + * + * @param Request $request + * @param Basket $basket + * + * @return Response + */ + public function getBasketAction(Request $request, Basket $basket) + { + $ret = [ + "basket" => $this->listBasket($basket), + "basket_elements" => $this->listBasketContent($basket) + ]; + + return Result::create($request, $ret)->createResponse(); + } + + /** + * @return Validator + */ + protected function getJsonSchemaValidator() + { + return $this->app['json-schema.validator']; + } + + /** + * Retrieve elements of one basket + * + * @param Basket $Basket + * + * @return array + */ + private function listBasketContent(Basket $Basket) + { + return array_map(function (BasketElement $element) { + return $this->listBasketElement($element); + }, iterator_to_array($Basket->getElements())); + } + + /** + * Retrieve detailed information about a basket element + * + * @param BasketElement $basket_element + * + * @return array + */ + private function listBasketElement(BasketElement $basket_element) + { + $ret = [ + 'basket_element_id' => $basket_element->getId(), + 'order' => $basket_element->getOrd(), + 'record' => $this->listRecord($basket_element->getRecord($this->app)), + 'validation_item' => null != $basket_element->getBasket()->getValidation(), + ]; + + if ($basket_element->getBasket()->getValidation()) { + $choices = []; + $agreement = null; + $note = ''; + + /** @var ValidationData $validationData */ + foreach ($basket_element->getValidationDatas() as $validationData) { + $participant = $validationData->getParticipant(); + $user = $participant->getUser(); + $choices[] = [ + 'validation_user' => [ + 'usr_id' => $user->getId(), + 'usr_name' => $user->getDisplayName(), + 'confirmed' => $participant->getIsConfirmed(), + 'can_agree' => $participant->getCanAgree(), + 'can_see_others' => $participant->getCanSeeOthers(), + 'readonly' => $user->getId() != $this->getAuthenticatedUser()->getId(), + 'user' => $this->listUser($user), + ], + 'agreement' => $validationData->getAgreement(), + 'updated_on' => $validationData->getUpdated()->format(DATE_ATOM), + 'note' => null === $validationData->getNote() ? '' : $validationData->getNote(), + ]; + + if ($user->getId() == $this->getAuthenticatedUser()->getId()) { + $agreement = $validationData->getAgreement(); + $note = null === $validationData->getNote() ? '' : $validationData->getNote(); + } + + $ret['validation_choices'] = $choices; + } + + $ret['agreement'] = $agreement; + $ret['note'] = $note; + } + + return $ret; + } + + /** + * Change the name of one basket + * + * @param Request $request + * @param Basket $basket + * + * @return Response + */ + public function setBasketTitleAction(Request $request, Basket $basket) + { + $basket->setName($request->get('name')); + + /** @var EntityManager $em */ + $em = $this->app['orm.em']; + $em->persist($basket); + $em->flush(); + + return Result::create($request, ["basket" => $this->listBasket($basket)])->createResponse(); + } + + /** + * Change the description of one basket + * + * @param Request $request + * @param Basket $basket + * + * @return Response + */ + public function setBasketDescriptionAction(Request $request, Basket $basket) + { + $basket->setDescription($request->get('description')); + + /** @var EntityManager $em */ + $em = $this->app['orm.em']; + $em->persist($basket); + $em->flush(); + + return Result::create($request, ["basket" => $this->listBasket($basket)])->createResponse(); + } + + /** + * Delete a basket + * + * @param Request $request + * @param Basket $basket + * + * @return array + */ + public function deleteBasketAction(Request $request, Basket $basket) + { + /** @var EntityManager $em */ + $em = $this->app['orm.em']; + $em->remove($basket); + $em->flush(); + + return $this->searchBasketsAction($request); + } + + /** + * List all available feeds + * + * @param Request $request + * + * @return Response + */ + public function searchPublicationsAction(Request $request) + { + $user = $this->getAuthenticatedUser(); + /** @var FeedRepository $feedsRepository */ + $feedsRepository = $this->app['repo.feeds']; + $coll = $feedsRepository->getAllForUser($this->getAclForUser($user)); + + $data = array_map(function ($feed) use ($user) { + return $this->listPublication($feed, $user); + }, $coll); + + return Result::create($request, ["feeds" => $data])->createResponse(); + } + + /** + * Retrieve detailed information about one feed + * + * @param Feed $feed + * @param User $user + * + * @return array + */ + private function listPublication(Feed $feed, User $user = null) + { + return [ + 'id' => $feed->getId(), + 'title' => $feed->getTitle(), + 'subtitle' => $feed->getSubtitle(), + 'total_entries' => $feed->getCountTotalEntries(), + 'icon' => $feed->getIconUrl(), + 'public' => $feed->isPublic(), + 'readonly' => !$feed->isPublisher($user), + 'deletable' => $feed->isOwner($user), + 'created_on' => $feed->getCreatedOn()->format(DATE_ATOM), + 'updated_on' => $feed->getUpdatedOn()->format(DATE_ATOM), + ]; + } + + public function getPublicationsAction(Request $request) + { + $user = $this->getAuthenticatedUser(); + $restrictions = (array) ($request->get('feeds') ?: []); + + $feed = Aggregate::createFromUser($this->app, $user, $restrictions); + + $offset_start = (int) ($request->get('offset_start') ?: 0); + $per_page = (int) ($request->get('per_page') ?: 5); + + $per_page = (($per_page >= 1) && ($per_page <= 20)) ? $per_page : 20; + + $data = [ + 'total_entries' => $feed->getCountTotalEntries(), + 'offset_start' => $offset_start, + 'per_page' => $per_page, + 'entries' => $this->listPublicationsEntries($feed, $offset_start, $per_page), + ]; + + return Result::create($request, $data)->createResponse(); + } + + /** + * Retrieve all entries of one feed + * + * @param FeedInterface $feed + * @param int $offset_start + * @param int $how_many + * + * @return array + */ + private function listPublicationsEntries(FeedInterface $feed, $offset_start = 0, $how_many = 5) + { + return array_map(function ($entry) { + return $this->listPublicationEntry($entry); + }, $feed->getEntries($offset_start, $how_many)); + } + + /** + * Retrieve detailed information about one feed entry + * + * @param FeedEntry $entry + * + * @return array + */ + private function listPublicationEntry(FeedEntry $entry) + { + $items = array_map(function ($item) { + return $this->listPublicationEntryItem($item); + }, iterator_to_array($entry->getItems())); + + return [ + 'id' => $entry->getId(), + 'author_email' => $entry->getAuthorEmail(), + 'author_name' => $entry->getAuthorName(), + 'created_on' => $entry->getCreatedOn()->format(DATE_ATOM), + 'updated_on' => $entry->getUpdatedOn()->format(DATE_ATOM), + 'title' => $entry->getTitle(), + 'subtitle' => $entry->getSubtitle(), + 'items' => $items, + 'feed_id' => $entry->getFeed()->getId(), + 'feed_title' => $entry->getFeed()->getTitle(), + 'feed_url' => '/feeds/' . $entry->getFeed()->getId() . '/content/', + 'url' => '/feeds/entry/' . $entry->getId() . '/', + ]; + } + + /** + * Retrieve detailed information about one feed entry item + * + * @param FeedItem $item + * + * @return array + */ + private function listPublicationEntryItem(FeedItem $item) + { + return [ + 'item_id' => $item->getId(), + 'record' => $this->listRecord($item->getRecord($this->app)), + ]; + } + + public function getFeedEntryAction(Request $request, $entry_id) + { + $user = $this->getAuthenticatedUser(); + /** @var FeedEntryRepository $repository */ + $repository = $this->app['repo.feed-entries']; + /** @var FeedEntry $entry */ + $entry = $repository->find($entry_id); + $collection = $entry->getFeed()->getCollection($this->app); + + if (null !== $collection && !$this->getAclForUser($user)->has_access_to_base($collection->get_base_id())) { + return Result::createError($request, 403, 'You have not access to the parent feed')->createResponse(); + } + + return Result::create($request, ['entry' => $this->listPublicationEntry($entry)])->createResponse(); + } + + /** + * Retrieve one feed + * + * @param Request $request + * @param int $feed_id + * + * @return Response + */ + public function getPublicationAction(Request $request, $feed_id) + { + $user = $this->getAuthenticatedUser(); + /** @var FeedRepository $repository */ + $repository = $this->app['repo.feeds']; + /** @var Feed $feed */ + $feed = $repository->find($feed_id); + + if (!$feed->isAccessible($user, $this->app)) { + return Result::create($request, [])->createResponse(); + } + + $offset_start = (int) $request->get('offset_start', 0); + $per_page = (int) $request->get('per_page', 5); + + $per_page = (($per_page >= 1) && ($per_page <= 100)) ? $per_page : 100; + + $data = [ + 'feed' => $this->listPublication($feed, $user), + 'offset_start' => $offset_start, + 'per_page' => $per_page, + 'entries' => $this->listPublicationsEntries($feed, $offset_start, $per_page), + ]; + + return Result::create($request, $data)->createResponse(); + } + + /** + * Get a Response containing the story embed files + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function getStoryEmbedAction(Request $request, $databox_id, $record_id) + { + $record = $this->findDataboxById($databox_id)->get_record($record_id); + + $devices = $request->get('devices', []); + $mimes = $request->get('mimes', []); + + $ret = array_filter(array_map(function ($media) use ($record) { + return $this->listEmbeddableMedia($record, $media); + }, $record->get_embedable_medias($devices, $mimes))); + + return Result::create($request, ["embed" => $ret])->createResponse(); + } + + /** + * Return detailed information about one story + * + * @param Request $request + * @param int $databox_id + * @param int $record_id + * + * @return Response + */ + public function getStoryAction(Request $request, $databox_id, $record_id) + { + try { + $story = $this->findDataboxById($databox_id)->get_record($record_id); + + return Result::create($request, ['story' => $this->listStory($request, $story)])->createResponse(); + } catch (NotFoundHttpException $e) { + return Result::createError($request, 404, $this->app->trans('Story Not Found'))->createResponse(); + } catch (\Exception $e) { + return $this->getBadRequestAction($request, $this->app->trans('An error occurred')); + } + } + + public function createStoriesAction(Request $request) + { + $content = $request->getContent(); + + $data = @json_decode($content); + + if (JSON_ERROR_NONE !== json_last_error()) { + $this->app->abort(400, 'Json response cannot be decoded or the encoded data is deeper than the recursion limit'); + } + + if (!isset($data->{'stories'})) { + $this->app->abort(400, 'Missing "stories" property'); + } + + $jsonSchemaRetriever = $this->getJsonSchemaRetriever(); + $schemaStory = $jsonSchemaRetriever->retrieve('file://'.$this->app['root.path'].'/lib/conf.d/json_schema/story.json'); + $schemaRecordStory = $jsonSchemaRetriever->retrieve('file://'.$this->app['root.path'].'/lib/conf.d/json_schema/story_record.json'); + + $storyData = $data->{'stories'}; + + if (!is_array($storyData)) { + $storyData = array($storyData); + } + + $stories = array(); + foreach ($storyData as $data) { + $stories[] = $this->createStory($data, $schemaStory, $schemaRecordStory); + } + + $result = Result::create($request, array('stories' => array_map(function(\record_adapter $story) { + return sprintf('/stories/%s/%s/', $story->get_sbas_id(), $story->get_record_id()); + }, $stories))); + + return $result->createResponse(); + } + + /** + * @param $data + * @param $schemaStory + * @param $schemaRecordStory + * @return \record_adapter + * @throws \Exception + */ + protected function createStory($data, $schemaStory, $schemaRecordStory) + { + $validator = $this->getJsonSchemaValidator(); + + $validator->check($data, $schemaStory); + + if (false === $validator->isValid()) { + $this->app->abort(400, 'Request body does not contains a valid "story" object'); + } + + $collection = \collection::get_from_base_id($this->app, $data->{'collection_id'}); + + if (!$this->getAclForUser()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) { + $this->app->abort(403, sprintf('You can not create a story on this collection %s', $collection->get_base_id())); + } + + $story = \record_adapter::createStory($this->app, $collection); + + if (isset($data->{'title'})) { + $story->set_original_name((string) $data->{'title'}); + } + + if (isset($data->{'story_records'})) { + $recordsData = (array) $data->{'story_records'}; + foreach ($recordsData as $data) { + $this->addRecordToStory($story, $data, $schemaRecordStory); + } + } + + return $story; + } + + protected function addRecordToStory(\record_adapter $story, $data, $jsonSchema) + { + $validator = $this->getJsonSchemaValidator(); + $validator->check($data, $jsonSchema); + + if (false === $validator->isValid()) { + $this->app->abort(400, 'Request body contains not a valid "record story" object'); + } + + $databox_id = $data->{'databox_id'}; + $record_id = $data->{'record_id'}; + + try { + $record = new \record_adapter($this->app, $databox_id, $record_id); + } catch (\Exception_Record_AdapterNotFound $e) { + $this->app->abort(404, sprintf('Record identified by databox_is %s and record_id %s could not be found', $databox_id, $record_id)); + } + + if (!$story->hasChild($record)) { + $story->appendChild($record); + } + + return $record->get_serialize_key(); + } + + public function createRecordStoryAction(Request $request, $databox_id, $story_id) + { + $content = $request->getContent(); + + $data = @json_decode($content); + + if (JSON_ERROR_NONE !== json_last_error()) { + $this->app->abort(400, 'Json response cannot be decoded or the encoded data is deeper than the recursion limit'); + } + + if (!isset($data->{'story_records'})) { + $this->app->abort(400, 'Missing "story_records" property'); + } + + $recordsData = $data->{'story_records'}; + + if (!is_array($recordsData)) { + $recordsData = array($recordsData); + } + + $story = new \record_adapter($this->app, $databox_id, $story_id); + + $schema = $this->getJsonSchemaRetriever() + ->retrieve('file://'.$this->app['root.path'].'/lib/conf.d/json_schema/story_record.json'); + + $records = array(); + foreach ($recordsData as $data) { + $records[] = $this->addRecordToStory($story, $data, $schema); + } + + $this->getDispatcher()->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($story)); + + $result = Result::create($request, array('records' => $records)); + return $result->createResponse(); + } + + public function getCurrentUserAction(Request $request) + { + $ret = ["user" => $this->listUser($this->getAuthenticatedUser())]; + + return Result::create($request, $ret)->createResponse(); + } + + public function ensureAdmin(Request $request) + { + if (!$user = $this->getApiAuthenticatedUser()->isAdmin()) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + + return null; + } + + public function ensureAccessToDatabox(Request $request) + { + $user = $this->getApiAuthenticatedUser(); + $databox = $this->findDataboxById($request->attributes->get('databox_id')); + + if (!$this->getAclForUser($user)->has_access_to_sbas($databox->get_sbas_id())) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + + return null; + } + + public function ensureCanAccessToRecord(Request $request) + { + $user = $this->getApiAuthenticatedUser(); + $record = $this->findDataboxById($request->attributes->get('databox_id')) + ->get_record($request->attributes->get('record_id')); + if (!$this->getAclForUser($user)->has_access_to_record($record)) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + + return null; + } + + public function ensureCanModifyRecord(Request $request) + { + $user = $this->getApiAuthenticatedUser(); + if (!$this->getAclForUser($user)->has_right('modifyrecord')) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + + return null; + } + + public function ensureCanModifyRecordStatus(Request $request) + { + $user = $this->getApiAuthenticatedUser(); + $record = $this->findDataboxById($request->attributes->get('databox_id')) + ->get_record($request->attributes->get('record_id')); + if (!$this->getAclForUser($user)->has_right_on_base($record->get_base_id(), 'chgstatus')) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + + return null; + } + + public function ensureCanSeeDataboxStructure(Request $request) + { + $user = $this->getApiAuthenticatedUser(); + $databox = $this->findDataboxById($request->attributes->get('databox_id')); + if (!$this->getAclForUser($user)->has_right_on_sbas($databox->get_sbas_id(), 'bas_modify_struct')) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + + return null; + } + + public function ensureCanMoveRecord(Request $request) + { + $user = $this->getApiAuthenticatedUser(); + $record = $this->findDataboxById($request->attributes->get('databox_id')) + ->get_record($request->attributes->get('record_id')); + // TODO: Check comparison. seems to be a mismatch + if ((!$this->getAclForUser($user)->has_right('addrecord') + && !$this->getAclForUser($user)->has_right('deleterecord')) + || !$this->getAclForUser($user)->has_right_on_base($record->get_base_id(), 'candeleterecord') + ) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + + return null; + } + + /** + * @return EventDispatcherInterface + */ + private function getDispatcher() + { + return $this->app['dispatcher']; + } + + /** + * @return \API_OAuth2_Adapter + */ + private function getOAuth2Server() + { + return $this->app['oauth2-server']; + } + + /** + * @return ApiOauthTokenRepository + */ + private function getApiTokenRepository() + { + return $this->app['repo.api-oauth-tokens']; + } + + /** + * @return Session + */ + private function getSession() + { + return $this->app['session']; + } + + /** + * @return PropertyAccess + */ + private function getConfiguration() + { + return $this->app['conf']; + } + + /** + * @return mixed + */ + private function getApiLogManipulator() + { + return $this->app['manipulator.api-log']; + } + + /** + * @return mixed + */ + private function getApiOAuthTokenManipulator() + { + return $this->app['manipulator.api-oauth-token']; + } + + /** + * @return User + */ + private function getApiAuthenticatedUser() + { + /** @var ApiOauthToken $token */ + $token = $this->getSession()->get('token'); + + return $token + ->getAccount() + ->getUser(); + } + + /** + * @return TaskRepository + */ + private function getTaskRepository() + { + return $this->app['repo.tasks']; + } + + /** + * @return TaskManipulator + */ + private function getTaskManipulator() + { + return $this->app['manipulator.task']; + } + + /** + * @return Manager + */ + private function getBorderManager() + { + return $this->app['border-manager']; + } + + /** + * @return SearchEngineInterface + */ + private function getSearchEngine() + { + return $this->app['phraseanet.SE']; + } + + /** + * @return UserManipulator + */ + private function getUserManipulator() + { + return $this->app['manipulator.user']; + } + + /** + * @return LoggerInterface + */ + private function getSearchEngineLogger() + { + /** @var LoggerInterface $logger */ + $logger = $this->app['phraseanet.SE.logger']; + return $logger; + } + + /** + * @return UriRetriever + */ + private function getJsonSchemaRetriever() + { + return $this->app['json-schema.retriever']; + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php b/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php index c71927802d..cfdef0e1a2 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php @@ -11,2055 +11,296 @@ namespace Alchemy\Phrasea\ControllerProvider\Api; -use Alchemy\Phrasea\Authentication\Context; -use Alchemy\Phrasea\Border\Attribute\Status; -use Alchemy\Phrasea\Border\File; -use Alchemy\Phrasea\Border\Manager as BorderManager; -use Alchemy\Phrasea\Border\Manager; -use Alchemy\Phrasea\Cache\Cache as CacheInterface; -use Alchemy\Phrasea\Controller\Api\API_V1_exception_badrequest; -use Alchemy\Phrasea\Controller\Api\API_V1_exception_forbidden; -use Alchemy\Phrasea\Controller\Api\caption_field; -use Alchemy\Phrasea\Controller\Api\caption_record; -use Alchemy\Phrasea\Controller\Api\collection; -use Alchemy\Phrasea\Controller\Api\media_Permalink_Adapter; -use Alchemy\Phrasea\Controller\Api\media_subdef; +use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Api\Result; -use Alchemy\Phrasea\Controller\Api\Symfony; -use Alchemy\Phrasea\Controller\Api\type; -use Alchemy\Phrasea\Core\Event\ApiOAuth2EndEvent; -use Alchemy\Phrasea\Core\Event\ApiOAuth2StartEvent; -use Alchemy\Phrasea\Core\Event\PreAuthenticate; +use Alchemy\Phrasea\Controller\Api\V1Controller; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Feed\Aggregate; use Alchemy\Phrasea\Feed\FeedInterface; -use Alchemy\Phrasea\Model\Entities\ApiOauthToken; use Alchemy\Phrasea\Model\Entities\Basket; use Alchemy\Phrasea\Model\Entities\BasketElement; use Alchemy\Phrasea\Model\Entities\Feed; use Alchemy\Phrasea\Model\Entities\FeedEntry; use Alchemy\Phrasea\Model\Entities\FeedItem; -use Alchemy\Phrasea\Model\Entities\LazaretCheck; -use Alchemy\Phrasea\Model\Entities\LazaretFile; -use Alchemy\Phrasea\Model\Entities\LazaretSession; -use Alchemy\Phrasea\Model\Entities\Task; use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\Entities\ValidationData; use Alchemy\Phrasea\Model\Repositories\BasketRepository; -use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; -use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion; -use Alchemy\Phrasea\Status\StatusStructure; use Silex\Application; +use Silex\ControllerCollection; use Silex\ControllerProviderInterface; -use Symfony\Component\HttpFoundation\File\UploadedFile; +use Silex\ServiceProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\Translation\TranslatorInterface; -class V1 implements ControllerProviderInterface +class V1 implements ControllerProviderInterface, ServiceProviderInterface { const VERSION = '1.4.1'; - const OBJECT_TYPE_USER = 'http://api.phraseanet.com/api/objects/user'; - 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'; - public static $extendedContentTypes = [ 'json' => ['application/vnd.phraseanet.record-extended+json'], 'yaml' => ['application/vnd.phraseanet.record-extended+yaml'], 'jsonp' => ['application/vnd.phraseanet.record-extended+jsonp'], ]; + public function register(Application $app) + { + $app['controller.api.v1'] = $app->share(function (PhraseaApplication $app) { + return new V1Controller($app); + }); + } + + public function boot(Application $app) + { + } + public function connect(Application $app) { - $app['controller.api.v1'] = $this; - + /** @var ControllerCollection $controllers */ $controllers = $app['controllers_factory']; - $controllers->before(function ($request) use ($app) { - return $this->authenticate($app, $request); - }) + $controllers->before('controller.api.v1:authenticate'); + $controllers->after('controller.api.v1:after'); + + $controllers->get('/monitor/scheduler/', 'controller.api.v1:getSchedulerAction') + ->before('controller.api.v1:ensureAdmin') ; - $controllers->after(function (Request $request, Response $response) use ($app) { - /** @var ApiOauthToken $token */ - $token = $app['session']->get('token'); - $app['manipulator.api-log']->create($token->getAccount(), $request, $response); - $app['manipulator.api-oauth-token']->setLastUsed($token, new \DateTime()); - $app['session']->set('token', null); - if (null !== $app['authentication']->getUser()) { - $app['authentication']->closeAccount(); - } - }) + $controllers->get('/monitor/tasks/', 'controller.api.v1:indexTasksAction') + ->before('controller.api.v1:ensureAdmin') ; - $controllers->get('/monitor/scheduler/', 'controller.api.v1:get_scheduler') - ->before([$this, 'ensureAdmin']) - ; - - $controllers->get('/monitor/tasks/', 'controller.api.v1:get_task_list') - ->before([$this, 'ensureAdmin']) - ; - - $controllers->get('/monitor/task/{task}/', 'controller.api.v1:get_task') + $controllers->get('/monitor/task/{task}/', 'controller.api.v1:showTaskAction') ->convert('task', $app['converter.task-callback']) - ->before([$this, 'ensureAdmin']) + ->before('controller.api.v1:ensureAdmin') ->assert('task', '\d+') ; - $controllers->post('/monitor/task/{task}/', 'controller.api.v1:set_task_property') + $controllers->post('/monitor/task/{task}/', 'controller.api.v1:setTaskPropertyAction') ->convert('task', $app['converter.task-callback']) - ->before([$this, 'ensureAdmin']) + ->before('controller.api.v1:ensureAdmin') ->assert('task', '\d+') ; - $controllers->post('/monitor/task/{task}/start/', 'controller.api.v1:start_task') + $controllers->post('/monitor/task/{task}/start/', 'controller.api.v1:startTaskAction') ->convert('task', $app['converter.task-callback']) - ->before([$this, 'ensureAdmin']) + ->before('controller.api.v1:ensureAdmin') ; - $controllers->post('/monitor/task/{task}/stop/', 'controller.api.v1:stop_task') + $controllers->post('/monitor/task/{task}/stop/', 'controller.api.v1:stopTaskAction') ->convert('task', $app['converter.task-callback']) - ->before([$this, 'ensureAdmin']) + ->before('controller.api.v1:ensureAdmin') ; - $controllers->get('/monitor/phraseanet/', 'controller.api.v1:get_phraseanet_monitor') - ->before([$this, 'ensureAdmin']) + $controllers->get('/monitor/phraseanet/', 'controller.api.v1:showPhraseanetConfigurationAction') + ->before('controller.api.v1:ensureAdmin') ; - $controllers->get('/databoxes/list/', 'controller.api.v1:get_databoxes'); + $controllers->get('/databoxes/list/', 'controller.api.v1:listDataboxesAction'); - $controllers->get('/databoxes/{databox_id}/collections/', 'controller.api.v1:get_databox_collections') - ->before([$this, 'ensureAccessToDatabox']) + $controllers->get('/databoxes/{databox_id}/collections/', 'controller.api.v1:getDataboxCollectionsAction') + ->before('controller.api.v1:ensureAccessToDatabox') ->assert('databox_id', '\d+') ; - $controllers->get('/databoxes/{any_id}/collections/', 'controller.api.v1:getBadRequest'); + $controllers->get('/databoxes/{any_id}/collections/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/databoxes/{databox_id}/status/', 'controller.api.v1:get_databox_status') - ->before([$this, 'ensureAccessToDatabox']) - ->before([$this, 'ensureCanSeeDataboxStructure']) + $controllers->get('/databoxes/{databox_id}/status/', 'controller.api.v1:getDataboxStatusAction') + ->before('controller.api.v1:ensureAccessToDatabox') + ->before('controller.api.v1:ensureCanSeeDataboxStructure') ->assert('databox_id', '\d+') ; - $controllers->get('/databoxes/{any_id}/status/', 'controller.api.v1:getBadRequest'); + $controllers->get('/databoxes/{any_id}/status/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/databoxes/{databox_id}/metadatas/', 'controller.api.v1:get_databox_metadatas') - ->before([$this, 'ensureAccessToDatabox']) - ->before([$this, 'ensureCanSeeDataboxStructure']) + $controllers->get('/databoxes/{databox_id}/metadatas/', 'controller.api.v1:getDataboxMetadataAction') + ->before('controller.api.v1:ensureAccessToDatabox') + ->before('controller.api.v1:ensureCanSeeDataboxStructure') ->assert('databox_id', '\d+') ; - $controllers->get('/databoxes/{any_id}/metadatas/', 'controller.api.v1:getBadRequest'); + $controllers->get('/databoxes/{any_id}/metadatas/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/databoxes/{databox_id}/termsOfUse/', 'controller.api.v1:get_databox_terms') - ->before([$this, 'ensureAccessToDatabox']) + $controllers->get('/databoxes/{databox_id}/termsOfUse/', 'controller.api.v1:getDataboxTermsAction') + ->before('controller.api.v1:ensureAccessToDatabox') ->assert('databox_id', '\d+') ; - $controllers->get('/databoxes/{any_id}/termsOfUse/', 'controller.api.v1:getBadRequest'); + $controllers->get('/databoxes/{any_id}/termsOfUse/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/quarantine/list/', 'controller.api.v1:list_quarantine'); + $controllers->get('/quarantine/list/', 'controller.api.v1:listQuarantineAction'); - $controllers->get('/quarantine/item/{lazaret_id}/', 'controller.api.v1:list_quarantine_item'); + $controllers->get('/quarantine/item/{lazaret_id}/', 'controller.api.v1:listQuarantineItemAction'); - $controllers->get('/quarantine/item/{any_id}/', 'controller.api.v1:getBadRequest'); + $controllers->get('/quarantine/item/{any_id}/', 'controller.api.v1:getBadRequestAction'); - $controllers->post('/records/add/', 'controller.api.v1:add_record'); + $controllers->post('/records/add/', 'controller.api.v1:addRecordAction'); - $controllers->post('/embed/substitute/', 'controller.api.v1:substitute'); + $controllers->post('/embed/substitute/', 'controller.api.v1:substituteAction'); - $controllers->match('/search/', 'controller.api.v1:search'); + $controllers->match('/search/', 'controller.api.v1:searchAction'); - $controllers->match('/records/search/', 'controller.api.v1:search_records'); + $controllers->match('/records/search/', 'controller.api.v1:searchRecordsAction'); - $controllers->get('/records/{databox_id}/{record_id}/caption/', 'controller.api.v1:caption_records') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->get('/records/{databox_id}/{record_id}/caption/', 'controller.api.v1:getRecordCaptionAction') + ->before('controller.api.v1:ensureCanAccessToRecord') + ->assert('databox_id', '\d+') + ->assert('record_id', '\d+') + ; + $controllers->get('/records/{any_id}/{anyother_id}/caption/', 'controller.api.v1:getBadRequestAction'); + + $controllers->get('/records/{databox_id}/{record_id}/metadatas/', 'controller.api.v1:getRecordMetadataAction') + ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/records/{any_id}/{anyother_id}/caption/', 'controller.api.v1:getBadRequest'); + $controllers->get('/records/{any_id}/{anyother_id}/metadatas/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/records/{databox_id}/{record_id}/metadatas/', 'controller.api.v1:get_record_metadatas') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->get('/records/{databox_id}/{record_id}/status/', 'controller.api.v1:getRecordStatusAction') + ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/records/{any_id}/{anyother_id}/metadatas/', 'controller.api.v1:getBadRequest'); + $controllers->get('/records/{any_id}/{anyother_id}/status/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/records/{databox_id}/{record_id}/status/', 'controller.api.v1:get_record_status') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->get('/records/{databox_id}/{record_id}/related/', 'controller.api.v1:getRelatedRecordsAction') + ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/records/{any_id}/{anyother_id}/status/', 'controller.api.v1:getBadRequest'); + $controllers->get('/records/{any_id}/{anyother_id}/related/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/records/{databox_id}/{record_id}/related/', 'controller.api.v1:get_record_related') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->get('/records/{databox_id}/{record_id}/embed/', 'controller.api.v1:getEmbeddedRecordAction') + ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/records/{any_id}/{anyother_id}/related/', 'controller.api.v1:getBadRequest'); + $controllers->get('/records/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/records/{databox_id}/{record_id}/embed/', 'controller.api.v1:get_record_embed') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->post('/records/{databox_id}/{record_id}/setmetadatas/', 'controller.api.v1:setRecordMetadataAction') + ->before('controller.api.v1:ensureCanAccessToRecord') + ->before('controller.api.v1:ensureCanModifyRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/records/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequest'); + $controllers->post('/records/{any_id}/{anyother_id}/setmetadatas/', 'controller.api.v1:getBadRequestAction'); - $controllers->post('/records/{databox_id}/{record_id}/setmetadatas/', 'controller.api.v1:set_record_metadatas') - ->before([$this, 'ensureCanAccessToRecord']) - ->before([$this, 'ensureCanModifyRecord']) + $controllers->post('/records/{databox_id}/{record_id}/setstatus/', 'controller.api.v1:setRecordStatusAction') + ->before('controller.api.v1:ensureCanAccessToRecord') + ->before('controller.api.v1:ensureCanModifyRecordStatus') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->post('/records/{any_id}/{anyother_id}/setmetadatas/', 'controller.api.v1:getBadRequest'); - - $controllers->post('/records/{databox_id}/{record_id}/setstatus/', 'controller.api.v1:set_record_status') - ->before([$this, 'ensureCanAccessToRecord']) - ->before([$this, 'ensureCanModifyRecordStatus']) - ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - - $controllers->post('/records/{any_id}/{anyother_id}/setstatus/', 'controller.api.v1:getBadRequest'); + $controllers->post('/records/{any_id}/{anyother_id}/setstatus/', 'controller.api.v1:getBadRequestAction'); $controllers->post( '/records/{databox_id}/{record_id}/setcollection/', - 'controller.api.v1:set_record_collection' + 'controller.api.v1:setRecordCollectionAction' ) - ->before([$this, 'ensureCanAccessToRecord']) - ->before([$this, 'ensureCanMoveRecord']) + ->before('controller.api.v1:ensureCanAccessToRecord') + ->before('controller.api.v1:ensureCanMoveRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; $controllers->post( '/records/{wrong_databox_id}/{wrong_record_id}/setcollection/', - 'controller.api.v1:getBadRequest' - ) - ; + 'controller.api.v1:getBadRequestAction' + ); - $controllers->get('/records/{databox_id}/{record_id}/', 'controller.api.v1:get_record') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->get('/records/{databox_id}/{record_id}/', 'controller.api.v1:getRecordAction') + ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/records/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequest'); + $controllers->get('/records/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/baskets/list/', 'controller.api.v1:search_baskets'); + $controllers->get('/baskets/list/', 'controller.api.v1:searchBasketsAction'); - $controllers->post('/baskets/add/', 'controller.api.v1:create_basket'); + $controllers->post('/baskets/add/', 'controller.api.v1:createBasketAction'); - $controllers->get('/baskets/{basket}/content/', 'controller.api.v1:get_basket') + $controllers->get('/baskets/{basket}/content/', 'controller.api.v1:getBasketAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-access']) ->assert('basket', '\d+') ; - $controllers->get('/baskets/{wrong_basket}/content/', 'controller.api.v1:getBadRequest'); + $controllers->get('/baskets/{wrong_basket}/content/', 'controller.api.v1:getBadRequestAction'); - $controllers->post('/baskets/{basket}/setname/', 'controller.api.v1:set_basket_title') + $controllers->post('/baskets/{basket}/setname/', 'controller.api.v1:setBasketTitleAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) ->assert('basket', '\d+') ; - $controllers->post('/baskets/{wrong_basket}/setname/', 'controller.api.v1:getBadRequest'); + $controllers->post('/baskets/{wrong_basket}/setname/', 'controller.api.v1:getBadRequestAction'); - $controllers->post('/baskets/{basket}/setdescription/', 'controller.api.v1:set_basket_description') + $controllers->post('/baskets/{basket}/setdescription/', 'controller.api.v1:setBasketDescriptionAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) ->assert('basket', '\d+') ; - $controllers->post('/baskets/{wrong_basket}/setdescription/', 'controller.api.v1:getBadRequest'); + $controllers->post('/baskets/{wrong_basket}/setdescription/', 'controller.api.v1:getBadRequestAction'); - $controllers->post('/baskets/{basket}/delete/', 'controller.api.v1:delete_basket') + $controllers->post('/baskets/{basket}/delete/', 'controller.api.v1:deleteBasketAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) ->assert('basket', '\d+') ; - $controllers->post('/baskets/{wrong_basket}/delete/', 'controller.api.v1:getBadRequest'); + $controllers->post('/baskets/{wrong_basket}/delete/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/feeds/list/', 'controller.api.v1:search_publications'); + $controllers->get('/feeds/list/', 'controller.api.v1:searchPublicationsAction'); - $controllers->get('/feeds/content/', 'controller.api.v1:get_publications'); + $controllers->get('/feeds/content/', 'controller.api.v1:getPublicationsAction'); - $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:get_feed_entry') + $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:getFeedEntryAction') ->assert('entry_id', '\d+') ; - $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:getBadRequest'); + $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/feeds/{feed_id}/content/', 'controller.api.v1:get_publication') + $controllers->get('/feeds/{feed_id}/content/', 'controller.api.v1:getPublicationAction') ->assert('feed_id', '\d+') ; - $controllers->get('/feeds/{wrong_feed_id}/content/', 'controller.api.v1:getBadRequest'); + $controllers->get('/feeds/{wrong_feed_id}/content/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/stories/{databox_id}/{record_id}/embed/', 'controller.api.v1:get_story_embed') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->get('/stories/{databox_id}/{record_id}/embed/', 'controller.api.v1:getStoryEmbedAction') + ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/stories/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequest'); + $controllers->get('/stories/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequestAction'); - $controllers->get('/stories/{databox_id}/{record_id}/', 'controller.api.v1:get_story') - ->before([$this, 'ensureCanAccessToRecord']) + $controllers->get('/stories/{databox_id}/{record_id}/', 'controller.api.v1:getStoryAction') + ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') ->assert('record_id', '\d+') ; - $controllers->get('/stories/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequest'); + $controllers->get('/stories/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequestAction'); - $controllers->post('/stories', 'controller.api.v1:createStories'); + $controllers->post('/stories', 'controller.api.v1:createStoriesAction'); - $controllers->post('/stories/{databox_id}/{story_id}/records', 'controller.api.v1:createRecordStory') + $controllers->post('/stories/{databox_id}/{story_id}/records', 'controller.api.v1:createRecordStoryAction') ->assert('databox_id', '\d+') ->assert('story_id', '\d+') ; - $controllers->get('/me/', 'controller.api.v1:get_current_user'); + $controllers->get('/me/', 'controller.api.v1:getCurrentUserAction'); return $controllers; } - - public function getBadRequest(Application $app, Request $request, $message = '') - { - $response = Result::createError($request, 400, $message)->createResponse(); - $response->headers->set('X-Status-Code', $response->getStatusCode()); - - return $response; - } - - /** - * Return an array of key-values informations about scheduler - * - * @param Application $app The silex application - * - * @return Response - */ - public function get_scheduler(Application $app, Request $request) - { - $data = $app['task-manager.live-information']->getManager(); - - return Result::create($request, ['scheduler' => ['configuration' => $data['configuration'], 'state' => $data['actual'], 'status' => $data['actual'], 'pid' => $data['process-id'], 'process-id' => $data['process-id'], 'updated_on' => (new \DateTime())->format(DATE_ATOM),]])->createResponse(); - } - - /** - * Get a list of phraseanet tasks - * - * @param Application $app The API silex application - * - * @return Response - */ - public function get_task_list(Application $app, Request $request) - { - $ret = array_map(function (Task $task) use ($app) { - return $this->list_task($app, $task); - }, $app['repo.tasks']->findAll()); - - return Result::create($request, ['tasks' => $ret])->createResponse(); - } - - private function list_task(Application $app, Task $task) - { - $data = $app['task-manager.live-information']->getTask($task); - - return [ - 'id' => $task->getId(), - 'title' => $task->getName(), - 'name' => $task->getName(), - 'state' => $task->getStatus(), - 'status' => $task->getStatus(), - 'actual-status' => $data['actual'], - 'process-id' => $data['process-id'], - 'pid' => $data['process-id'], - 'jobId' => $task->getJobId(), - 'period' => $task->getPeriod(), - 'last_exec_time' => $task->getLastExecution() ? $task->getLastExecution()->format(DATE_ATOM) : null, - 'last_execution' => $task->getLastExecution() ? $task->getLastExecution()->format(DATE_ATOM) : null, - 'updated' => $task->getUpdated() ? $task->getUpdated()->format(DATE_ATOM) : null, - 'created' => $task->getCreated() ? $task->getCreated()->format(DATE_ATOM) : null, - 'auto_start' => $task->getStatus() === Task::STATUS_STARTED, - 'crashed' => $task->getCrashed(), - ]; - } - - /** - * Get informations about an identified task - * - * @param \Silex\Application $app The API silex application - * @param Task $task - * - * @return Response - */ - public function get_task(Application $app, Request $request, Task $task) - { - return Result::create($request, ['task' => $this->list_task($app, $task)])->createResponse(); - } - - /** - * Start a specified task - * - * @param \Silex\Application $app The API silex application - * @param Task $task The task to start - * - * @return Response - */ - public function start_task(Application $app, Request $request, Task $task) - { - $app['manipulator.task']->start($task); - - return Result::create($request, ['task' => $this->list_task($app, $task)])->createResponse(); - } - - /** - * Stop a specified task - * - * @param \Silex\Application $app The API silex application - * @param Task $task The task to stop - * - * @return Response - */ - public function stop_task(Application $app, Request $request, Task $task) - { - $app['manipulator.task']->stop($task); - - return Result::create($request, ['task' => $this->list_task($app, $task)])->createResponse(); - } - - /** - * Update a task property - * - name - * - autostart - * - * @param \Silex\Application $app Silex application - * @param Task $task The task - * - * @return Response - */ - public function set_task_property(Application $app, Request $request, $task) - { - $title = $app['request']->get('title'); - $autostart = $app['request']->get('autostart'); - - if (null === $title && null === $autostart) { - return $this->getBadRequest($app, $request); - } - - if ($title) { - $task->setName($title); - } - if ($autostart) { - $task->setStatus(Task::STATUS_STARTED); - } - - return Result::create($request, ['task' => $this->list_task($app, $task)])->createResponse(); - } - - /** - * Get Information the cache system used by the instance - * - * @param \Silex\Application $app the silex application - * - * @return array - */ - private function get_cache_info(Application $app) - { - $caches = [ - 'main' => $app['cache'], - 'op_code' => $app['opcode-cache'], - 'doctrine_metadatas' => $app['orm.em']->getConfiguration()->getMetadataCacheImpl(), - 'doctrine_query' => $app['orm.em']->getConfiguration()->getQueryCacheImpl(), - 'doctrine_result' => $app['orm.em']->getConfiguration()->getResultCacheImpl(), - ]; - - $ret = []; - - foreach ($caches as $name => $service) { - if ($service instanceof CacheInterface) { - $ret['cache'][$name] = [ - 'type' => $service->getName(), - 'online' => $service->isOnline(), - 'stats' => $service->getStats(), - ]; - } else { - $ret['cache'][$name] = null; - } - } - - return $ret; - } - - /** - * Provide information about phraseanet configuration - * - * @param \Silex\Application $app the silex application - * - * @return array - */ - private function get_config_info(Application $app) - { - $ret = []; - - $ret['phraseanet']['version'] = [ - 'name' => $app['phraseanet.version']->getName(), - 'number' => $app['phraseanet.version']->getNumber(), - ]; - - $ret['phraseanet']['environment'] = $app->getEnvironment(); - $ret['phraseanet']['debug'] = $app['debug']; - $ret['phraseanet']['maintenance'] = $app['conf']->get(['main', 'maintenance']); - $ret['phraseanet']['errorsLog'] = $app['debug']; - $ret['phraseanet']['serverName'] = $app['conf']->get('servername'); - - return $ret; - } - - /** - * Provide phraseanet global values - * - * @param \Silex\Application $app the silex application - * - * @return array - */ - private function get_gv_info(Application $app) - { - try { - $SEStatus = $app['phraseanet.SE']->getStatus(); - } catch (\RuntimeException $e) { - $SEStatus = ['error' => $e->getMessage()]; - } - - $binaries = $app['conf']->get(['main', 'binaries']); - - return ['global_values' => ['serverName' => $app['conf']->get('servername'), 'title' => $app['conf']->get(['registry', 'general', 'title']), 'keywords' => $app['conf']->get(['registry', 'general', 'keywords']), 'description' => $app['conf']->get(['registry', 'general', 'description']), 'httpServer' => ['phpTimezone' => ini_get('date.timezone'), 'siteId' => $app['conf']->get(['main', 'key']), 'defaultLanguage' => $app['conf']->get(['languages', 'default']), 'allowIndexing' => $app['conf']->get(['registry', 'general', 'allow-indexation']), 'modes' => ['XsendFile' => $app['conf']->get(['xsendfile', 'enabled']), 'XsendFileMapping' => $app['conf']->get(['xsendfile', 'mapping']), 'h264Streaming' => $app['conf']->get(['registry', 'executables', 'h264-streaming-enabled']), 'authTokenDirectory' => $app['conf']->get(['registry', 'executables', 'auth-token-directory']), 'authTokenDirectoryPath' => $app['conf']->get(['registry', 'executables', 'auth-token-directory-path']), 'authTokenPassphrase' => $app['conf']->get(['registry', 'executables', 'auth-token-passphrase']),]], 'maintenance' => ['alertMessage' => $app['conf']->get(['registry', 'maintenance', 'message']), 'displayMessage' => $app['conf']->get(['registry', 'maintenance', 'enabled']),], 'webServices' => ['googleApi' => $app['conf']->get(['registry', 'webservices', 'google-charts-enabled']), 'googleAnalyticsId' => $app['conf']->get(['registry', 'general', 'analytics']), 'i18nWebService' => $app['conf']->get(['registry', 'webservices', 'geonames-server']), 'recaptacha' => ['active' => $app['conf']->get(['registry', 'webservices', 'captcha-enabled']), 'publicKey' => $app['conf']->get(['registry', 'webservices', 'recaptcha-public-key']), 'privateKey' => $app['conf']->get(['registry', 'webservices', 'recaptcha-private-key']),], 'youtube' => ['active' => $app['conf']->get(['main', 'bridge', 'youtube', 'enabled']), 'clientId' => $app['conf']->get(['main', 'bridge', 'youtube', 'client_id']), 'clientSecret' => $app['conf']->get(['main', 'bridge', 'youtube', 'client_secret']), 'devKey' => $app['conf']->get(['main', 'bridge', 'youtube', 'developer_key']),], 'flickr' => ['active' => $app['conf']->get(['main', 'bridge', 'flickr', 'enabled']), 'clientId' => $app['conf']->get(['main', 'bridge', 'flickr', 'client_id']), 'clientSecret' => $app['conf']->get(['main', 'bridge', 'flickr', 'client_secret']),], 'dailymtotion' => ['active' => $app['conf']->get(['main', 'bridge', 'dailymotion', 'enabled']), 'clientId' => $app['conf']->get(['main', 'bridge', 'dailymotion', 'client_id']), 'clientSecret' => $app['conf']->get(['main', 'bridge', 'dailymotion', 'client_secret']),]], 'navigator' => ['active' => $app['conf']->get(['registry', 'api-clients', 'navigator-enabled']),], 'office-plugin' => ['active' => $app['conf']->get(['registry', 'api-clients', 'office-enabled']),], 'homepage' => ['viewType' => $app['conf']->get(['registry', 'general', 'home-presentation-mode']),], 'report' => ['anonymous' => $app['conf']->get(['registry', 'modules', 'anonymous-report']),], 'storage' => ['documents' => $app['conf']->get(['main', 'storage', 'subdefs']),], 'searchEngine' => ['configuration' => ['defaultQuery' => $app['conf']->get(['registry', 'searchengine', 'default-query']), 'defaultQueryType' => $app['conf']->get(['registry', 'searchengine', 'default-query-type']), 'minChar' => $app['conf']->get(['registry', 'searchengine', 'min-letters-truncation']),], 'engine' => ['type' => $app['phraseanet.SE']->getName(), 'status' => $SEStatus, 'configuration' => $app['phraseanet.SE']->getConfigurationPanel()->getConfiguration(),],], 'binary' => ['phpCli' => isset($binaries['php_binary']) ? $binaries['php_binary'] : null, 'phpIni' => $app['conf']->get(['registry', 'executables', 'php-conf-path']), 'swfExtract' => isset($binaries['swf_extract_binary']) ? $binaries['swf_extract_binary'] : null, 'pdf2swf' => isset($binaries['pdf2swf_binary']) ? $binaries['pdf2swf_binary'] : null, 'swfRender' => isset($binaries['swf_render_binary']) ? $binaries['swf_render_binary'] : null, 'unoconv' => isset($binaries['unoconv_binary']) ? $binaries['unoconv_binary'] : null, 'ffmpeg' => isset($binaries['ffmpeg_binary']) ? $binaries['ffmpeg_binary'] : null, 'ffprobe' => isset($binaries['ffprobe_binary']) ? $binaries['ffprobe_binary'] : null, 'mp4box' => isset($binaries['mp4box_binary']) ? $binaries['mp4box_binary'] : null, 'pdftotext' => isset($binaries['pdftotext_binary']) ? $binaries['pdftotext_binary'] : null, 'recess' => isset($binaries['recess_binary']) ? $binaries['recess_binary'] : null, 'pdfmaxpages' => $app['conf']->get(['registry', 'executables', 'pdf-max-pages']),], 'mainConfiguration' => ['viewBasAndCollName' => $app['conf']->get(['registry', 'actions', 'collection-display']), 'chooseExportTitle' => $app['conf']->get(['registry', 'actions', 'export-title-choice']), 'defaultExportTitle' => $app['conf']->get(['registry', 'actions', 'default-export-title']), 'socialTools' => $app['conf']->get(['registry', 'actions', 'social-tools']),], 'modules' => ['thesaurus' => $app['conf']->get(['registry', 'modules', 'thesaurus']), 'storyMode' => $app['conf']->get(['registry', 'modules', 'stories']), 'docSubsitution' => $app['conf']->get(['registry', 'modules', 'doc-substitution']), 'subdefSubstitution' => $app['conf']->get(['registry', 'modules', 'thumb-substitution']),], 'email' => ['defaultMailAddress' => $app['conf']->get(['registry', 'email', 'emitter-email']), 'smtp' => ['active' => $app['conf']->get(['registry', 'email', 'smtp-enabled']), 'auth' => $app['conf']->get(['registry', 'email', 'smtp-auth-enabled']), 'host' => $app['conf']->get(['registry', 'email', 'smtp-host']), 'port' => $app['conf']->get(['registry', 'email', 'smtp-port']), 'secure' => $app['conf']->get(['registry', 'email', 'smtp-secure-mode']), 'user' => $app['conf']->get(['registry', 'email', 'smtp-user']), 'password' => $app['conf']->get(['registry', 'email', 'smtp-password']),],], 'ftp' => ['active' => $app['conf']->get(['registry', 'ftp', 'ftp-enabled']), 'activeForUser' => $app['conf']->get(['registry', 'ftp', 'ftp-user-access']),], 'client' => ['maxSizeDownload' => $app['conf']->get(['registry', 'actions', 'download-max-size']), 'tabSearchMode' => $app['conf']->get(['registry', 'classic', 'search-tab']), 'tabAdvSearchPosition' => $app['conf']->get(['registry', 'classic', 'adv-search-tab']), 'tabTopicsPosition' => $app['conf']->get(['registry', 'classic', 'topics-tab']), 'tabOngActifPosition' => $app['conf']->get(['registry', 'classic', 'active-tab']), 'renderTopicsMode' => $app['conf']->get(['registry', 'classic', 'render-topics']), 'displayRolloverPreview' => $app['conf']->get(['registry', 'classic', 'stories-preview']), 'displayRolloverBasket' => $app['conf']->get(['registry', 'classic', 'basket-rollover']), 'collRenderMode' => $app['conf']->get(['registry', 'classic', 'collection-presentation']), 'viewSizeBaket' => $app['conf']->get(['registry', 'classic', 'basket-size-display']), 'clientAutoShowProposals' => $app['conf']->get(['registry', 'classic', 'auto-show-proposals']), 'needAuth2DL' => $app['conf']->get(['registry', 'actions', 'auth-required-for-export']),], 'inscription' => ['autoSelectDB' => $app['conf']->get(['registry', 'registration', 'auto-select-collections']), 'autoRegister' => $app['conf']->get(['registry', 'registration', 'auto-register-enabled']),], 'push' => ['validationReminder' => $app['conf']->get(['registry', 'actions', 'validation-reminder-days']), 'expirationValue' => $app['conf']->get(['registry', 'actions', 'validation-expiration-days']),],]]; - } - - /** - * Provide - * - cache information - * - global values informations - * - configuration informations - * - * @param \Silex\Application $app the silex application - * - * @return Response - */ - public function get_phraseanet_monitor(Application $app, Request $request) - { - $ret = array_merge( - $this->get_config_info($app), - $this->get_cache_info($app), - $this->get_gv_info($app) - ); - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Get a Result containing the \databoxes - * - * @param Request $request - * - * @return Response - */ - public function get_databoxes(Application $app, Request $request) - { - return Result::create($request, ["databoxes" => $this->list_databoxes($app)])->createResponse(); - } - - /** - * Get a Response containing the collections of a \databox - * - * @param Request $request - * @param int $databox_id - * - * @return Response - */ - public function get_databox_collections(Application $app, Request $request, $databox_id) - { - $ret = ["collections" => $this->list_databox_collections($app['phraseanet.appbox']->get_databox($databox_id))]; - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Get a Response containing the status of a \databox - * - * @param Request $request - * @param int $databox_id - * - * @return Response - */ - public function get_databox_status(Application $app, Request $request, $databox_id) - { - $ret = ["status" => $this->list_databox_status($app['phraseanet.appbox']->get_databox($databox_id)->getStatusStructure())]; - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Get a Response containing the metadatas of a \databox - * - * @param Request $request - * @param int $databox_id - * - * @return Response - */ - public function get_databox_metadatas(Application $app, Request $request, $databox_id) - { - $ret = ["document_metadatas" => $this->list_databox_metadatas_fields($app['phraseanet.appbox']->get_databox($databox_id)->get_meta_structure())]; - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Get a Response containing the terms of use of a \databox - * - * @param Request $request - * @param int $databox_id - * - * @return Response - */ - public function get_databox_terms(Application $app, Request $request, $databox_id) - { - $ret = ["termsOfUse" => $this->list_databox_terms($app['phraseanet.appbox']->get_databox($databox_id))]; - - return Result::create($request, $ret)->createResponse(); - } - - public function caption_records(Application $app, Request $request, $databox_id, $record_id) - { - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - $fields = $record->get_caption()->get_fields(); - - $ret = ['caption_metadatas' => array_map(function ($field) { - return ['meta_structure_id' => $field->get_meta_struct_id(), 'name' => $field->get_name(), 'value' => $field->get_serialized_values(";"),]; - }, $fields)]; - - return Result::create($request, $ret)->createResponse(); - } - - public function add_record(Application $app, Request $request) - { - if (count($request->files->get('file')) == 0) { - return $this->getBadRequest($app, $request, 'Missing file parameter'); - } - - if (!$request->files->get('file') instanceof UploadedFile) { - return $this->getBadRequest($app, $request, 'You can upload one file at time'); - } - - $file = $request->files->get('file'); - /* @var $file UploadedFile */ - - if (!$file->isValid()) { - return $this->getBadRequest($app, $request, 'Datas corrupted, please try again'); - } - - if (!$request->get('base_id')) { - return $this->getBadRequest($app, $request, 'Missing base_id parameter'); - } - - $collection = \collection::get_from_base_id($app, $request->get('base_id')); - - if (!$app['acl']->get($app['authentication']->getUser())->has_right_on_base($request->get('base_id'), 'canaddrecord')) { - return Result::createError($request, 403, sprintf('You do not have access to collection %s', $collection->get_label($app['locale'])))->createResponse(); - } - - $media = $app['mediavorus']->guess($file->getPathname()); - - $Package = new File($app, $media, $collection, $file->getClientOriginalName()); - - if ($request->get('status')) { - $Package->addAttribute(new Status($app, $request->get('status'))); - } - - $session = new LazaretSession(); - $session->setUser($app['authentication']->getUser()); - - $app['orm.em']->persist($session); - $app['orm.em']->flush(); - - $reasons = $output = null; - - $callback = function ($element, $visa, $code) use ($app, &$reasons, &$output) { - if (!$visa->isValid()) { - $reasons = array_map(function ($response) use ($app) { - return $response->getMessage($app['translator']); - }, $visa->getResponses()); - } - - $output = $element; - }; - - switch ($request->get('forceBehavior')) { - case '0' : - $behavior = Manager::FORCE_RECORD; - break; - case '1' : - $behavior = Manager::FORCE_LAZARET; - break; - case null: - $behavior = null; - break; - default: - return $this->getBadRequest($app, $request, sprintf('Invalid forceBehavior value `%s`', $request->get('forceBehavior'))); - } - - $nosubdef = $request->get('nosubdefs')==='' || \p4field::isyes($request->get('nosubdefs')); - $app['border-manager']->process($session, $Package, $callback, $behavior, $nosubdef); - - $ret = ['entity' => null,]; - - if ($output instanceof \record_adapter) { - $ret['entity'] = '0'; - $ret['url'] = '/records/' . $output->get_sbas_id() . '/' . $output->get_record_id() . '/'; - $app['dispatcher']->dispatch(PhraseaEvents::RECORD_UPLOAD, new RecordEdit($output)); - } - if ($output instanceof LazaretFile) { - $ret['entity'] = '1'; - $ret['url'] = '/quarantine/item/' . $output->getId() . '/'; - } - - return Result::create($request, $ret)->createResponse(); - } - - public function substitute(Application $app, Request $request) - { - $ret = array(); - - if (count($request->files->get('file')) == 0) { - throw new API_V1_exception_badrequest('Missing file parameter'); - } - if (!$request->files->get('file') instanceof Symfony\Component\HttpFoundation\File\UploadedFile) { - throw new API_V1_exception_badrequest('You can upload one file at time'); - } - $file = $request->files->get('file'); - // @var $file Symfony\Component\HttpFoundation\File\UploadedFile - if (!$file->isValid()) { - throw new API_V1_exception_badrequest('Datas corrupted, please try again'); - } - if (!$request->get('databox_id')) { - throw new API_V1_exception_badrequest('Missing databox_id parameter'); - } - if (!$request->get('record_id')) { - throw new API_V1_exception_badrequest('Missing record_id parameter'); - } - if (!$request->get('name')) { - throw new API_V1_exception_badrequest('Missing name parameter'); - } - $media = $app['mediavorus']->guess($file->getPathname()); - // @var $record \record_adapter - $record = $this->app['phraseanet.appbox']->get_databox($request->get('databox_id'))->get_record($request->get('record_id')); - $base_id = $record->get_base_id(); - $collection = \collection::get_from_base_id($this->app, $base_id); - if (!$app['authentication']->getUser()->ACL()->has_right_on_base($base_id, 'canaddrecord')) { - throw new API_V1_exception_forbidden(sprintf('You do not have access to collection %s', $collection->get_label($this->app['locale.I18n']))); - } - $record->substitute_subdef($request->get('name'), $media, $app); - foreach ($record->get_embedable_medias() as $name => $media) { - if ($name == $request->get('name') && - null !== ($subdef = $this->list_embedable_media($record, $media, $this->app['phraseanet.registry']))) { - $ret[] = $subdef; - } - } - - return Result::create($request, $ret)->createResponse(); - } - - public function list_quarantine(Application $app, Request $request) - { - $offset_start = max($request->get('offset_start', 0), 0); - $per_page = min(max($request->get('per_page', 10), 1), 20); - - $baseIds = array_keys($app['acl']->get($app['authentication']->getUser())->get_granted_base(['canaddrecord'])); - - $lazaretFiles = []; - - if (count($baseIds) > 0) { - $lazaretRepository = $app['repo.lazaret-files']; - $lazaretFiles = iterator_to_array($lazaretRepository->findPerPage($baseIds, $offset_start, $per_page)); - } - - $ret = array_map(function ($lazaretFile) use ($app) { - return $this->list_lazaret_file($app, $lazaretFile); - }, $lazaretFiles); - - $ret = ['offset_start' => $offset_start, 'per_page' => $per_page, 'quarantine_items' => $ret,]; - - return Result::create($request, $ret)->createResponse(); - } - - public function list_quarantine_item($lazaret_id, Application $app, Request $request) - { - $lazaretFile = $app['repo.lazaret-files']->find($lazaret_id); - - /* @var $lazaretFile LazaretFile */ - if (null === $lazaretFile) { - return Result::createError($request, 404, sprintf('Lazaret file id %d not found', $lazaret_id))->createResponse(); - } - - if (!$app['acl']->get($app['authentication']->getUser())->has_right_on_base($lazaretFile->getBaseId(), 'canaddrecord')) { - return Result::createError($request, 403, 'You do not have access to this quarantine item')->createResponse(); - } - - $ret = ['quarantine_item' => $this->list_lazaret_file($app, $lazaretFile)]; - - return Result::create($request, $ret)->createResponse(); - } - - private function list_lazaret_file(Application $app, LazaretFile $file) - { - /** @var Manager $manager */ - $manager = $app['border-manager']; - /** @var TranslatorInterface $translator */ - $translator = $app['translator']; - - $checks = array_map(function (LazaretCheck $checker) use ($manager, $translator) { - $checkerFQCN = $checker->getCheckClassname(); - return $manager->getCheckerFromFQCN($checkerFQCN)->getMessage($translator); - }, iterator_to_array($file->getChecks())); - - $usr_id = $user = null; - if ($file->getSession()->getUser()) { - $user = $file->getSession()->getUser(); - $usr_id = $user->getId(); - } - - $session = ['id' => $file->getSession()->getId(), 'usr_id' => $usr_id, 'user' => $user ? $this->list_user($user) : null,]; - - return ['id' => $file->getId(), 'quarantine_session' => $session, 'base_id' => $file->getBaseId(), 'original_name' => $file->getOriginalName(), 'sha256' => $file->getSha256(), 'uuid' => $file->getUuid(), 'forced' => $file->getForced(), 'checks' => $file->getForced() ? [] : $checks, 'created_on' => $file->getCreated()->format(DATE_ATOM), 'updated_on' => $file->getUpdated()->format(DATE_ATOM),]; - } - - /** - * Search for results - * - * @param Request $request - * - * @return Response - */ - public function search(Application $app, Request $request) - { - list($ret, $search_result) = $this->prepare_search_request($app, $request); - - $ret['results'] = ['records' => [], 'stories' => []]; - - foreach ($search_result->getResults() as $es_record) { - try { - $record = new \record_adapter($app, $es_record->getDataboxId(), $es_record->getRecordId()); - } catch (\Exception $e) { - - } - - - if ($record->is_grouping()) { - $ret['results']['stories'][] = $this->list_story($app, $request, $record); - } else { - $ret['results']['records'][] = $this->list_record($app, $record); - } - } - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Get a Response containing the results of a records search - * - * Deprecated in favor of search - * - * @param Request $request - * - * @return Response - */ - public function search_records(Application $app, Request $request) - { - list($ret, $search_result) = $this->prepare_search_request($app, $request); - - foreach ($search_result->getResults() as $es_record) { - try { - $record = new \record_adapter($app, $es_record->getDataboxId(), $es_record->getRecordId()); - } catch (\Exception $e) { - - } - - $ret['results'][] = $this->list_record($app, $record); - } - - return Result::create($request, $ret)->createResponse(); - } - - private function prepare_search_request(Application $app, Request $request) - { - $options = SearchEngineOptions::fromRequest($app, $request); - - $offsetStart = (int) ($request->get('offset_start') ?: 0); - $perPage = (int) $request->get('per_page') ?: 10; - - $query = (string) $request->get('query'); - $app['phraseanet.SE']->resetCache(); - - $search_result = $app['phraseanet.SE']->query($query, $offsetStart, $perPage, $options); - - $app['manipulator.user']->logQuery($app['authentication']->getUser(), $search_result->getQuery()); - - foreach ($options->getDataboxes() as $databox) { - $colls = array_map(function (\collection $collection) { - return $collection->get_coll_id(); - }, array_filter($options->getCollections(), function (\collection $collection) use ($databox) { - return $collection->get_databox()->get_sbas_id() == $databox->get_sbas_id(); - })); - - $app['phraseanet.SE.logger']->log($databox, $search_result->getQuery(), $search_result->getTotal(), $colls); - } - - $app['phraseanet.SE']->clearCache(); - - $ret = ['offset_start' => $offsetStart, 'per_page' => $perPage, 'available_results' => $search_result->getAvailable(), 'total_results' => $search_result->getTotal(), 'error' => (string) $search_result->getError(), 'warning' => (string) $search_result->getWarning(), 'query_time' => $search_result->getDuration(), 'search_indexes' => $search_result->getIndexes(), 'suggestions' => array_map(function (SearchEngineSuggestion $suggestion) { - return $suggestion->toArray(); - }, $search_result->getSuggestions()->toArray()), 'results' => [], 'query' => $search_result->getQuery(),]; - - return [$ret, $search_result]; - } - - /** - * Get a Response containing the baskets where the record is in - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function get_record_related(Application $app, Request $request, $databox_id, $record_id) - { - $that = $this; - $baskets = array_map(function (Basket $basket) use ($that, $app) { - return $that->list_basket($app, $basket); - }, (array) $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id)->get_container_baskets($app['orm.em'], $app['authentication']->getUser())); - - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - $stories = array_map(function (\record_adapter $story) use ($that, $app, $request) { - return $that->list_story($app, $request, $story); - }, array_values($record->get_grouping_parents()->get_elements())); - - return Result::create($request, ["baskets" => $baskets, "stories" => $stories])->createResponse(); - } - - /** - * Get a Response containing the record metadatas - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function get_record_metadatas(Application $app, Request $request, $databox_id, $record_id) - { - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - $ret = ["record_metadatas" => $this->list_record_caption($record->get_caption())]; - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Get a Response containing the record status - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function get_record_status(Application $app, Request $request, $databox_id, $record_id) - { - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - $ret = ["status" => $this->list_record_status($record)]; - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Get a Response containing the record embed files - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function get_record_embed(Application $app, Request $request, $databox_id, $record_id) - { - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - $devices = $request->get('devices', []); - $mimes = $request->get('mimes', []); - - $ret = array_filter(array_map(function ($media) use ($record, $app) { - if (null !== $embed = $this->list_embedable_media($app, $record, $media)) { - return $embed; - } - }, $record->get_embedable_medias($devices, $mimes))); - - return Result::create($request, ["embed" => $ret])->createResponse(); - } - - /** - * Get a Response containing the story embed files - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function get_story_embed(Application $app, Request $request, $databox_id, $record_id) - { - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - $devices = $request->get('devices', []); - $mimes = $request->get('mimes', []); - - $ret = array_filter(array_map(function ($media) use ($record, $app) { - if (null !== $embed = $this->list_embedable_media($app, $record, $media)) { - return $embed; - } - }, $record->get_embedable_medias($devices, $mimes))); - - return Result::create($request, ["embed" => $ret])->createResponse(); - } - - public function set_record_metadatas(Application $app, Request $request, $databox_id, $record_id) - { - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - $metadatas = $request->get('metadatas'); - - if (!is_array($metadatas)) { - return $this->getBadRequest($app, $request, 'Metadatas should be an array'); - } - - array_walk($metadatas, function ($metadata) use ($app, $request) { - if (!is_array($metadata)) { - return $this->getBadRequest($app, $request, 'Each Metadata value should be an array'); - } - }); - - $record->set_metadatas($metadatas); - - return Result::create($request, ["record_metadatas" => $this->list_record_caption($record->get_caption())])->createResponse(); - } - - public function set_record_status(Application $app, Request $request, $databox_id, $record_id) - { - $databox = $app['phraseanet.appbox']->get_databox($databox_id); - $record = $databox->get_record($record_id); - $statusStructure = $databox->getStatusStructure(); - - $status = $request->get('status'); - - $datas = strrev($record->get_status()); - - if (!is_array($status)) { - return $this->getBadRequest($app, $request); - } - foreach ($status as $n => $value) { - if ($n > 31 || $n < 4) { - return $this->getBadRequest($app, $request); - } - if (!in_array($value, ['0', '1'])) { - return $this->getBadRequest($app, $request); - } - if (!$statusStructure->hasStatus($n)) { - return $this->getBadRequest($app, $request); - } - - $datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 2)); - } - - $record->set_binary_status(strrev($datas)); - - // @todo Move event dispatch inside record_adapter class (keeps things encapsulated) - $app['dispatcher']->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($record)); - - $ret = ["status" => $this->list_record_status($record)]; - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Move a record to another collection - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function set_record_collection(Application $app, Request $request, $databox_id, $record_id) - { - $databox = $app['phraseanet.appbox']->get_databox($databox_id); - $record = $databox->get_record($record_id); - - try { - $collection = \collection::get_from_base_id($app, $request->get('base_id')); - $record->move_to_collection($collection, $app['phraseanet.appbox']); - - return Result::create($request, ["record" => $this->list_record($app, $record)])->createResponse(); - } catch (\Exception $e) { - return $this->getBadRequest($app, $request, $e->getMessage()); - } - } - - /** - * Return detailed informations about one record - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function get_record(Application $app, Request $request, $databox_id, $record_id) - { - try { - $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - return Result::create($request, ['record' => $this->list_record($app, $record)])->createResponse(); - } catch (NotFoundHttpException $e) { - return Result::createError($request, 404, $app->trans('Record Not Found'))->createResponse(); - } catch (\Exception $e) { - return $this->getBadRequest($app, $request, $app->trans('An error occured')); - } - } - - /** - * Return detailed informations about one story - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return Response - */ - public function get_story(Application $app, Request $request, $databox_id, $record_id) - { - try { - $story = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - return Result::create($request, ['story' => $this->list_story($app, $request, $story)])->createResponse(); - } catch (NotFoundHttpException $e) { - return Result::createError($request, 404, $app->trans('Story Not Found'))->createResponse(); - } catch (\Exception $e) { - return $this->getBadRequest($app, $request, $app->trans('An error occured')); - } - } - - /** - * Return the baskets list of the authenticated user - * - * @param Request $request - * - * @return Response - */ - public function search_baskets(Application $app, Request $request) - { - return Result::create($request, ['baskets' => $this->list_baskets($app)])->createResponse(); - } - - /** - * Return a baskets list - * - * @param int $usr_id - * - * @return array - */ - private function list_baskets(Application $app) - { - $repo = $app['repo.baskets']; - - /* @var $repo BasketRepository */ - - return array_map(function (Basket $basket) use ($app) { - return $this->list_basket($app, $basket); - }, $repo->findActiveByUser($app['authentication']->getUser())); - } - - /** - * Create a new basket - * - * @param Request $request - * - * @return Response - */ - public function create_basket(Application $app, Request $request) - { - $name = $request->get('name'); - - if (trim(strip_tags($name)) === '') { - return $this->getBadRequest($app, $request, 'Missing basket name parameter'); - } - - $Basket = new Basket(); - $Basket->setUser($app['authentication']->getUser()); - $Basket->setName($name); - - $app['orm.em']->persist($Basket); - $app['orm.em']->flush(); - - return Result::create($request, ["basket" => $this->list_basket($app, $Basket)])->createResponse(); - } - - /** - * Delete a basket - * - * @param Request $request - * @param Basket $basket - * - * @return array - */ - public function delete_basket(Application $app, Request $request, Basket $basket) - { - $app['orm.em']->remove($basket); - $app['orm.em']->flush(); - - return $this->search_baskets($app, $request); - } - - /** - * @param Application $app - * @param Request $request - * @return mixed - */ - public function createStories(Application $app, Request $request) - { - $content = $request->getContent(); - - $data = @json_decode($content); - - if (JSON_ERROR_NONE !== json_last_error()) { - $app->abort(400, 'Json response cannot be decoded or the encoded data is deeper than the recursion limit'); - } - - if (!isset($data->{'stories'})) { - $app->abort(400, 'Missing "stories" property'); - } - - $schemaStory = $app['json-schema.retriever']->retrieve('file://'.$app['root.path'].'/lib/conf.d/json_schema/story.json'); - $schemaRecordStory = $app['json-schema.retriever']->retrieve('file://'.$app['root.path'].'/lib/conf.d/json_schema/story_record.json'); - - $storyData = $data->{'stories'}; - - if (!is_array($storyData)) { - $storyData = array($storyData); - } - - $stories = array(); - foreach ($storyData as $data) { - $stories[] = $this->create_story($app, $data, $schemaStory, $schemaRecordStory); - } - - $result = Result::create($request, array('stories' => array_map(function($story) { - return sprintf('/stories/%s/%s/', $story->get_sbas_id(), $story->get_record_id()); - }, $stories))); - - return $result->createResponse(); - } - - public function createRecordStory(Application $app, Request $request, $databox_id, $story_id) - { - $content = $request->getContent(); - - $data = @json_decode($content); - - if (JSON_ERROR_NONE !== json_last_error()) { - $app->abort(400, 'Json response cannot be decoded or the encoded data is deeper than the recursion limit'); - } - - if (!isset($data->{'story_records'})) { - $app->abort(400, 'Missing "story_records" property'); - } - - $recordsData = $data->{'story_records'}; - - if (!is_array($recordsData)) { - $recordsData = array($recordsData); - } - - $story = new \record_adapter($app, $databox_id, $story_id); - - $schema = $app['json-schema.retriever']->retrieve('file://'.$app['root.path'].'/lib/conf.d/json_schema/story_record.json'); - - $records = array(); - foreach ($recordsData as $data) { - $records[] = $this->add_record_to_story($app, $story, $data, $schema); - } - - $app['dispatcher']->dispatch(PhraseaEvents::RECORD_EDIT, new RecordEdit($story)); - - $result = Result::create($request, array('records' => $records)); - return $result->createResponse(); - } - - - protected function create_story(Application $app, $data, $schemaStory, $schemaRecordStory) - { - $app['json-schema.validator']->check($data, $schemaStory); - - if (false === $app['json-schema.validator']->isValid()) { - $app->abort(400, 'Request body does not contains a valid "story" object'); - } - - $collection = \collection::get_from_base_id($app, $data->{'collection_id'}); - - if (!$app['acl']->get($app['authentication']->getUser())->has_right_on_base($collection->get_base_id(), 'canaddrecord')) { - $app->abort(403, sprintf('You can not create a story on this collection %s', $collection->get_base_id())); - } - - $story = \record_adapter::createStory($app, $collection); - - if (isset($data->{'title'})) { - $story->set_original_name((string) $data->{'title'}); - } - - if (isset($data->{'story_records'})) { - $recordsData = (array) $data->{'story_records'}; - foreach ($recordsData as $data) { - $this->add_record_to_story($app, $story, $data, $schemaRecordStory); - } - } - - return $story; - } - - protected function add_record_to_story(Application $app, \record_adapter $story, $data, $jsonSchema) - { - $app['json-schema.validator']->check($data, $jsonSchema); - - if (false === $app['json-schema.validator']->isValid()) { - $app->abort(400, 'Request body contains not a valid "record story" object'); - } - - $databox_id = $data->{'databox_id'}; - $record_id = $data->{'record_id'}; - - try { - $record = new \record_adapter($app, $databox_id, $record_id); - } catch (\Exception_Record_AdapterNotFound $e) { - $app->abort(404, sprintf('Record identified by databox_is %s and record_id %s could not be found', $databox_id, $record_id)); - } - - if (!$story->hasChild($record)) { - $story->appendChild($record); - } - - return $record->get_serialize_key(); - } - - /** - * Retrieve a basket - * - * @param Request $request - * @param Basket $basket - * - * @return Response - */ - public function get_basket(Application $app, Request $request, Basket $basket) - { - $ret = ["basket" => $this->list_basket($app, $basket), "basket_elements" => $this->list_basket_content($app, $basket)]; - - return Result::create($request, $ret)->createResponse(); - } - - public function get_current_user(Application $app, Request $request) - { - $ret = ["user" => $this->list_user($app['authentication']->getUser())]; - - return Result::create($request, $ret)->createResponse(); - } - - /** - * Retrieve elements of one basket - * - * @param Basket $Basket - * - * @return type - */ - private function list_basket_content(Application $app, Basket $Basket) - { - return array_map(function (BasketElement $element) use ($app) { - return $this->list_basket_element($app, $element); - }, iterator_to_array($Basket->getElements())); - } - - /** - * Retrieve detailled informations about a basket element - * - * @param BasketElement $basket_element - * - * @return type - */ - private function list_basket_element(Application $app, BasketElement $basket_element) - { - $ret = ['basket_element_id' => $basket_element->getId(), 'order' => $basket_element->getOrd(), 'record' => $this->list_record($app, $basket_element->getRecord($app)), 'validation_item' => null != $basket_element->getBasket()->getValidation(),]; - - if ($basket_element->getBasket()->getValidation()) { - $choices = []; - $agreement = null; - $note = ''; - - foreach ($basket_element->getValidationDatas() as $validation_datas) { - $participant = $validation_datas->getParticipant(); - $user = $participant->getUser(); - /* @var $validation_datas ValidationData */ - $choices[] = ['validation_user' => ['usr_id' => $user->getId(), 'usr_name' => $user->getDisplayName(), 'confirmed' => $participant->getIsConfirmed(), 'can_agree' => $participant->getCanAgree(), 'can_see_others' => $participant->getCanSeeOthers(), 'readonly' => $user->getId() != $app['authentication']->getUser()->getId(), 'user' => $this->list_user($user),], 'agreement' => $validation_datas->getAgreement(), 'updated_on' => $validation_datas->getUpdated()->format(DATE_ATOM), 'note' => null === $validation_datas->getNote() ? '' : $validation_datas->getNote(),]; - - if ($user->getId() == $app['authentication']->getUser()->getId()) { - $agreement = $validation_datas->getAgreement(); - $note = null === $validation_datas->getNote() ? '' : $validation_datas->getNote(); - } - - $ret['validation_choices'] = $choices; - } - - $ret['agreement'] = $agreement; - $ret['note'] = $note; - } - - return $ret; - } - - /** - * Change the name of one basket - * - * @param Request $request - * @param Basket $basket - * - * @return Response - */ - public function set_basket_title(Application $app, Request $request, Basket $basket) - { - $basket->setName($request->get('name')); - - $app['orm.em']->persist($basket); - $app['orm.em']->flush(); - - return Result::create($request, ["basket" => $this->list_basket($app, $basket)])->createResponse(); - } - - /** - * Change the description of one basket - * - * @param Request $request - * @param Basket $basket - * - * @return Response - */ - public function set_basket_description(Application $app, Request $request, Basket $basket) - { - $basket->setDescription($request->get('description')); - - $app['orm.em']->persist($basket); - $app['orm.em']->flush(); - - return Result::create($request, ["basket" => $this->list_basket($app, $basket)])->createResponse(); - } - - /** - * List all avalaible feeds - * - * @param Request $request - * @param User $user - * - * @return Response - */ - public function search_publications(Application $app, Request $request) - { - $user = $app['authentication']->getUser(); - $coll = $app['repo.feeds']->getAllForUser($app['acl']->get($user)); - - $data = array_map(function ($feed) use ($user) { - return $this->list_publication($feed, $user); - }, $coll); - - return Result::create($request, ["feeds" => $data])->createResponse(); - } - - /** - * Retrieve one feed - * - * @param Request $request - * @param int $publication_id - * @param User $user - * - * @return Response - */ - public function get_publication(Application $app, Request $request, $feed_id) - { - $user = $app['authentication']->getUser(); - $feed = $app['repo.feeds']->find($feed_id); - - if (!$feed->isAccessible($user, $app)) { - return Result::create($request, [])->createResponse(); - } - - $offset_start = (int) $request->get('offset_start', 0); - $per_page = (int) $request->get('per_page', 5); - - $per_page = (($per_page >= 1) && ($per_page <= 100)) ? $per_page : 100; - - $data = ['feed' => $this->list_publication($feed, $user), 'offset_start' => $offset_start, 'per_page' => $per_page, 'entries' => $this->list_publications_entries($app, $feed, $offset_start, $per_page),]; - - return Result::create($request, $data)->createResponse(); - } - - public function get_publications(Application $app, Request $request) - { - $user = $app['authentication']->getUser(); - $restrictions = (array) ($request->get('feeds') ?: []); - - $feed = Aggregate::createFromUser($app, $user, $restrictions); - - $offset_start = (int) ($request->get('offset_start') ?: 0); - $per_page = (int) ($request->get('per_page') ?: 5); - - $per_page = (($per_page >= 1) && ($per_page <= 20)) ? $per_page : 20; - - $data = ['total_entries' => $feed->getCountTotalEntries(), 'offset_start' => $offset_start, 'per_page' => $per_page, 'entries' => $this->list_publications_entries($app, $feed, $offset_start, $per_page),]; - - return Result::create($request, $data)->createResponse(); - } - - public function get_feed_entry(Application $app, Request $request, $entry_id) - { - $user = $app['authentication']->getUser(); - $entry = $app['repo.feed-entries']->find($entry_id); - $collection = $entry->getFeed()->getCollection($app); - - if (null !== $collection && !$app['acl']->get($user)->has_access_to_base($collection->get_base_id())) { - return Result::createError($request, 403, 'You have not access to the parent feed')->createResponse(); - } - - return Result::create($request, ['entry' => $this->list_publication_entry($app, $entry)])->createResponse(); - } - - /** - * Retrieve detailled informations about one feed - * - * @param Feed $feed - * @param type $user - * - * @return array - */ - private function list_publication(Feed $feed, $user) - { - return ['id' => $feed->getId(), 'title' => $feed->getTitle(), 'subtitle' => $feed->getSubtitle(), 'total_entries' => $feed->getCountTotalEntries(), 'icon' => $feed->getIconUrl(), 'public' => $feed->isPublic(), 'readonly' => !$feed->isPublisher($user), 'deletable' => $feed->isOwner($user), 'created_on' => $feed->getCreatedOn()->format(DATE_ATOM), 'updated_on' => $feed->getUpdatedOn()->format(DATE_ATOM),]; - } - - /** - * Retrieve all entries of one feed - * - * @param FeedInterface $feed - * @param int $offset_start - * @param int $how_many - * - * @return array - */ - private function list_publications_entries(Application $app, FeedInterface $feed, $offset_start = 0, $how_many = 5) - { - return array_map(function ($entry) use ($app) { - return $this->list_publication_entry($app, $entry); - }, $feed->getEntries($offset_start, $how_many)); - } - - /** - * Retrieve detailled information about one feed entry - * - * @param FeedEntry $entry - * - * @return array - */ - private function list_publication_entry(Application $app, FeedEntry $entry) - { - $items = array_map(function ($item) use ($app) { - return $this->list_publication_entry_item($app, $item); - }, iterator_to_array($entry->getItems())); - - return ['id' => $entry->getId(), 'author_email' => $entry->getAuthorEmail(), 'author_name' => $entry->getAuthorName(), 'created_on' => $entry->getCreatedOn()->format(DATE_ATOM), 'updated_on' => $entry->getUpdatedOn()->format(DATE_ATOM), 'title' => $entry->getTitle(), 'subtitle' => $entry->getSubtitle(), 'items' => $items, 'feed_id' => $entry->getFeed()->getId(), 'feed_title' => $entry->getFeed()->getTitle(), 'feed_url' => '/feeds/' . $entry->getFeed()->getId() . '/content/', 'url' => '/feeds/entry/' . $entry->getId() . '/',]; - } - - /** - * Retrieve detailled informations about one feed entry item - * - * @param FeedItem $item - * - * @return array - */ - private function list_publication_entry_item(Application $app, FeedItem $item) - { - return ['item_id' => $item->getId(), 'record' => $this->list_record($app, $item->getRecord($app)),]; - } - - /** - * @retrieve detailled informations about one suddef - * - * @param media_subdef $media - * - * @return array - */ - private function list_embedable_media(Application $app, \record_adapter $record, \media_subdef $media) - { - if (!$media->is_physically_present()) { - return null; - } - - if ($app['authentication']->isAuthenticated()) { - if ($media->get_name() !== 'document' && false === $app['acl']->get($app['authentication']->getUser())->has_access_to_subdef($record, $media->get_name())) { - return null; - } - if ($media->get_name() === 'document' && !$app['acl']->get($app['authentication']->getUser())->has_right_on_base($record->get_base_id(), 'candwnldhd') && !$app['acl']->get($app['authentication']->getUser())->has_hd_grant($record)) { - return null; - } - } - - if ($media->get_permalink() instanceof \media_Permalink_Adapter) { - $permalink = $this->list_permalink($media->get_permalink()); - } else { - $permalink = null; - } - - return [ - 'name' => $media->get_name(), - 'permalink' => $permalink, - 'height' => $media->get_height(), - 'width' => $media->get_width(), - 'filesize' => $media->get_size(), - 'devices' => $media->getDevices(), - 'player_type' => $media->get_type(), - 'mime_type' => $media->get_mime(), - 'substituted' => $media->is_substituted(), - 'created_on' => $media->get_creation_date()->format(DATE_ATOM), - 'updated_on' => $media->get_modification_date()->format(DATE_ATOM), - ]; - } - - /** - * Retrieve detailled information about one permalink - * - * @param media_Permalink_Adapter $permalink - * - * @return type - */ - private function list_permalink(\media_Permalink_Adapter $permalink) - { - $downloadUrl = $permalink->get_url(); - $downloadUrl->getQuery()->set('download', '1'); - - return ['created_on' => $permalink->get_created_on()->format(DATE_ATOM), 'id' => $permalink->get_id(), 'is_activated' => $permalink->get_is_activated(), /** @Ignore */ - 'label' => $permalink->get_label(), 'updated_on' => $permalink->get_last_modified()->format(DATE_ATOM), 'page_url' => $permalink->get_page(), 'download_url' => (string) $downloadUrl, 'url' => (string) $permalink->get_url()]; - } - - /** - * Retrieve detailled information about one status - * - * @param \databox $databox - * @param string $status - * - * @return array - */ - private function list_record_status(\record_adapter $record) - { - $ret = []; - foreach ($record->getStatusStructure() as $bit => $status) { - $ret[] = ['bit' => $bit, 'state' => \databox_status::bitIsSet($record->getStatusBitField(), $bit)]; - } - - return $ret; - } - - /** - * List all field about a specified caption - * - * @param caption_record $caption - * - * @return array - */ - private function list_record_caption(\caption_record $caption) - { - $ret = []; - foreach ($caption->get_fields() as $field) { - foreach ($field->get_values() as $value) { - $ret[] = $this->list_record_caption_field($value, $field); - } - } - - return $ret; - } - - /** - * Retrieve information about a caption field - * - * @param caption_field $field - * - * @return array - */ - private function list_record_caption_field(\caption_Field_Value $value, \caption_field $field) - { - return ['meta_id' => $value->getId(), 'meta_structure_id' => $field->get_meta_struct_id(), 'name' => $field->get_name(), 'labels' => ['fr' => $field->get_databox_field()->get_label('fr'), 'en' => $field->get_databox_field()->get_label('en'), 'de' => $field->get_databox_field()->get_label('de'), 'nl' => $field->get_databox_field()->get_label('nl'),], 'value' => $value->getValue(),]; - } - - /** - * Retrieve information about one basket - * - * @param Basket $basket - * - * @return array - */ - private function list_basket(Application $app, Basket $basket) - { - $ret = ['basket_id' => $basket->getId(), 'owner' => $this->list_user($basket->getUser()), 'created_on' => $basket->getCreated()->format(DATE_ATOM), 'description' => (string) $basket->getDescription(), 'name' => $basket->getName(), 'pusher_usr_id' => $basket->getPusher() ? $basket->getPusher()->getId() : null, 'pusher' => $basket->getPusher() ? $this->list_user($basket->getPusher()) : null, 'updated_on' => $basket->getUpdated()->format(DATE_ATOM), 'unread' => !$basket->getIsRead(), 'validation_basket' => !!$basket->getValidation()]; - - if ($basket->getValidation()) { - $users = array_map(function ($participant) use ($app) { - $user = $participant->getUser(); - - return ['usr_id' => $user->getId(), 'usr_name' => $user->getDisplayName(), 'confirmed' => $participant->getIsConfirmed(), 'can_agree' => $participant->getCanAgree(), 'can_see_others' => $participant->getCanSeeOthers(), 'readonly' => $user->getId() != $app['authentication']->getUser()->getId(), 'user' => $this->list_user($user),]; - }, iterator_to_array($basket->getValidation()->getParticipants())); - - $expires_on_atom = $basket->getValidation()->getExpires(); - - if ($expires_on_atom instanceof \DateTime) { - $expires_on_atom = $expires_on_atom->format(DATE_ATOM); - } - - $ret = array_merge(['validation_users' => $users, 'expires_on' => $expires_on_atom, 'validation_infos' => $basket->getValidation()->getValidationString($app, $app['authentication']->getUser()), 'validation_confirmed' => $basket->getValidation()->getParticipant($app['authentication']->getUser())->getIsConfirmed(), 'validation_initiator' => $basket->getValidation()->isInitiator($app['authentication']->getUser()), 'validation_initiator_user' => $this->list_user($basket->getValidation()->getInitiator()),], $ret); - } - - return $ret; - } - - /** - * Retrieve detailled informations about one record - * - * @param \record_adapter $record - * - * @return array - */ - public function list_record(Application $app, \record_adapter $record) - { - $technicalInformation = []; - foreach ($record->get_technical_infos() as $name => $value) { - $technicalInformation[] = ['name' => $name, 'value' => $value]; - } - - return ['databox_id' => $record->get_sbas_id(), 'record_id' => $record->get_record_id(), 'mime_type' => $record->get_mime(), 'title' => $record->get_title(), 'original_name' => $record->get_original_name(), 'updated_on' => $record->get_modification_date()->format(DATE_ATOM), 'created_on' => $record->get_creation_date()->format(DATE_ATOM), 'collection_id' => \phrasea::collFromBas($app, $record->get_base_id()), 'sha256' => $record->get_sha256(), 'thumbnail' => $this->list_embedable_media($app, $record, $record->get_thumbnail()), 'technical_informations' => $technicalInformation, 'phrasea_type' => $record->get_type(), 'uuid' => $record->get_uuid(),]; - } - - /** - * Retrieve detailled informations about one story - * - * @param \record_adapter $story - * - * @return array - */ - public function list_story(Application $app, Request $request, \record_adapter $story) - { - if (!$story->is_grouping()) { - return Result::createError($request, 404, 'Story not found')->createResponse(); - } - - $that = $this; - $records = array_map(function (\record_adapter $record) use ($that, $app) { - return $that->list_record($app, $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 ['@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($app, $story->get_base_id()), 'thumbnail' => $this->list_embedable_media($app, $story, $story->get_thumbnail()), 'uuid' => $story->get_uuid(), 'metadatas' => ['@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 - * - * @return array - */ - private function list_databoxes(Application $app) - { - return array_map(function (\databox $databox) { - return $this->list_databox($databox); - }, $app['phraseanet.appbox']->get_databoxes()); - } - - /** - * Retrieve CGU's for the specified \databox - * - * @param \databox $databox - * - * @return array - */ - private function list_databox_terms(\databox $databox) - { - $ret = []; - foreach ($databox->get_cgus() as $locale => $array_terms) { - $ret[] = ['locale' => $locale, 'terms' => $array_terms['value']]; - } - - return $ret; - } - - /** - * Retrieve detailled informations about one \databox - * - * @param \databox $databox - * - * @return array - */ - private function list_databox(\databox $databox) - { - return ['databox_id' => $databox->get_sbas_id(), 'name' => $databox->get_dbname(), 'viewname' => $databox->get_viewname(), 'labels' => ['en' => $databox->get_label('en'), 'de' => $databox->get_label('de'), 'fr' => $databox->get_label('fr'), 'nl' => $databox->get_label('nl'),], 'version' => $databox->get_version(),]; - } - - /** - * List all available collections for a specified \databox - * - * @param \databox $databox - * - * @return array - */ - private function list_databox_collections(\databox $databox) - { - return array_map(function (\collection $collection) { - return $this->list_collection($collection); - }, $databox->get_collections()); - } - - /** - * Retrieve detailled informations about one collection - * - * @param collection $collection - * - * @return array - */ - private function list_collection(\collection $collection) - { - return ['base_id' => $collection->get_base_id(), 'collection_id' => $collection->get_coll_id(), 'name' => $collection->get_name(), 'labels' => ['fr' => $collection->get_label('fr'), 'en' => $collection->get_label('en'), 'de' => $collection->get_label('de'), 'nl' => $collection->get_label('nl'),], 'record_amount' => $collection->get_record_amount(),]; - } - - /** - * Retrieve informations for a list of status - * - * @param array $status - * - * @return array - */ - private function list_databox_status(StatusStructure $statusStructure) - { - $ret = []; - foreach ($statusStructure as $bit => $status) { - $ret[] = [ - 'bit' => $bit, - 'label_on' => $status['labelon'], - 'label_off' => $status['labeloff'], - 'labels' => [ - 'en' => $status['labels_on_i18n']['en'], - 'fr' => $status['labels_on_i18n']['fr'], - 'de' => $status['labels_on_i18n']['de'], - 'nl' => $status['labels_on_i18n']['nl'], - ], - 'img_on' => $status['img_on'], - 'img_off' => $status['img_off'], - 'searchable' => (bool) $status['searchable'], - 'printable' => (bool) $status['printable'], - ]; - } - - return $ret; - } - - /** - * List all metadatas field using a \databox meta structure - * - * @param \databox_descriptionStructure $meta_struct - * - * @return array - */ - private function list_databox_metadatas_fields(\databox_descriptionStructure $meta_struct) - { - return array_map(function ($meta) { - return $this->list_databox_metadata_field_properties($meta); - }, iterator_to_array($meta_struct)); - } - - /** - * Retrieve informations about one \databox metadata field - * - * @param \databox_field $databox_field - * - * @return array - */ - private function list_databox_metadata_field_properties(\databox_field $databox_field) - { - return ['id' => $databox_field->get_id(), 'namespace' => $databox_field->get_tag()->getGroupName(), 'source' => $databox_field->get_tag()->getTagname(), 'tagname' => $databox_field->get_tag()->getName(), 'name' => $databox_field->get_name(), 'labels' => ['fr' => $databox_field->get_label('fr'), 'en' => $databox_field->get_label('en'), 'de' => $databox_field->get_label('de'), 'nl' => $databox_field->get_label('nl'),], 'separator' => $databox_field->get_separator(), 'thesaurus_branch' => $databox_field->get_tbranch(), 'type' => $databox_field->get_type(), 'indexable' => $databox_field->is_indexable(), 'multivalue' => $databox_field->is_multi(), 'readonly' => $databox_field->is_readonly(), 'required' => $databox_field->is_required(),]; - } - - private function authenticate(Application $app, Request $request) - { - $context = new Context(Context::CONTEXT_OAUTH2_TOKEN); - - $app['dispatcher']->dispatch(PhraseaEvents::PRE_AUTHENTICATE, new PreAuthenticate($request, $context)); - $app['dispatcher']->dispatch(PhraseaEvents::API_OAUTH2_START, new ApiOAuth2StartEvent()); - - $app['oauth2-server']->verifyAccessToken(); - - if (null === $token = $app['repo.api-oauth-tokens']->find($app['oauth2-server']->getToken())) { - throw new NotFoundHttpException('Provided token is not valid.'); - } - $app['session']->set('token', $token); - - $oAuth2Account = $token->getAccount(); - $oAuth2App = $oAuth2Account->getApplication(); - - if ($oAuth2App->getClientId() == \API_OAuth2_Application_Navigator::CLIENT_ID && !$app['conf']->get(['registry', 'api-clients', 'navigator-enabled'])) { - return Result::createError($request, 403, 'The use of Phraseanet Navigator is not allowed')->createResponse(); - } - - if ($oAuth2App->getClientId() == \API_OAuth2_Application_OfficePlugin::CLIENT_ID && !$app['conf']->get(['registry', 'api-clients', 'office-enabled'])) { - return Result::createError($request, 403, 'The use of Office Plugin is not allowed.')->createResponse(); - } - - $app['authentication']->openAccount($oAuth2Account->getUser()); - $app['oauth2-server']->rememberSession($app['session']); - $app['dispatcher']->dispatch(PhraseaEvents::API_OAUTH2_END, new ApiOAuth2EndEvent()); - } - - public function ensureAdmin(Request $request, Application $app) - { - $user = $app['session']->get('token')->getAccount()->getUser(); - if (!$user->isAdmin()) { - return Result::createError($request, 401, 'You are not authorized')->createResponse(); - } - } - - public function ensureAccessToDatabox(Request $request, Application $app) - { - $user = $app['session']->get('token')->getAccount()->getUser(); - $databox = $app['phraseanet.appbox']->get_databox($request->attributes->get('databox_id')); - - if (!$app['acl']->get($user)->has_access_to_sbas($databox->get_sbas_id())) { - return Result::createError($request, 401, 'You are not authorized')->createResponse(); - } - } - - public function ensureCanAccessToRecord(Request $request, Application $app) - { - $user = $app['session']->get('token')->getAccount()->getUser(); - $record = $app['phraseanet.appbox']->get_databox($request->attributes->get('databox_id'))->get_record($request->attributes->get('record_id')); - if (!$app['acl']->get($user)->has_access_to_record($record)) { - return Result::createError($request, 401, 'You are not authorized')->createResponse(); - } - } - - public function ensureCanModifyRecord(Request $request, Application $app) - { - $user = $app['session']->get('token')->getAccount()->getUser(); - if (!$app['acl']->get($user)->has_right('modifyrecord')) { - return Result::createError($request, 401, 'You are not authorized')->createResponse(); - } - } - - public function ensureCanModifyRecordStatus(Request $request, Application $app) - { - $user = $app['session']->get('token')->getAccount()->getUser(); - $record = $app['phraseanet.appbox']->get_databox($request->attributes->get('databox_id'))->get_record($request->attributes->get('record_id')); - if (!$app['acl']->get($user)->has_right_on_base($record->get_base_id(), 'chgstatus')) { - return Result::createError($request, 401, 'You are not authorized')->createResponse(); - } - } - - public function ensureCanSeeDataboxStructure(Request $request, Application $app) - { - $user = $app['session']->get('token')->getAccount()->getUser(); - $databox = $app['phraseanet.appbox']->get_databox($request->attributes->get('databox_id')); - if (!$app['acl']->get($user)->has_right_on_sbas($databox->get_sbas_id(), 'bas_modify_struct')) { - return Result::createError($request, 401, 'You are not authorized')->createResponse(); - } - } - - public function ensureCanMoveRecord(Request $request, Application $app) - { - $user = $app['session']->get('token')->getAccount()->getUser(); - $record = $app['phraseanet.appbox']->get_databox($request->attributes->get('databox_id'))->get_record($request->attributes->get('record_id')); - if ((!$app['acl']->get($user)->has_right('addrecord') && !$app['acl']->get($user)->has_right('deleterecord')) || !$app['acl']->get($user)->has_right_on_base($record->get_base_id(), 'candeleterecord')) { - return Result::createError($request, 401, 'You are not authorized')->createResponse(); - } - } - - private function list_user(User $user) - { - switch ($user->getGender()) { - case User::GENDER_MR; - $gender = 'Mr'; - break; - case User::GENDER_MRS; - $gender = 'Mrs'; - break; - case User::GENDER_MISS; - $gender = 'Miss'; - break; - } - - return [ - '@entity@' => self::OBJECT_TYPE_USER, - 'id' => $user->getId(), - 'email' => $user->getEmail() ?: null, - 'login' => $user->getLogin() ?: null, - 'first_name' => $user->getFirstName() ?: null, - 'last_name' => $user->getLastName() ?: null, - 'display_name' => $user->getDisplayName() ?: null, - 'gender' => $gender, - 'address' => $user->getAddress() ?: null, - 'zip_code' => $user->getZipCode() ?: null, - 'city' => $user->getCity() ?: null, - 'country' => $user->getCountry() ?: null, - 'phone' => $user->getPhone() ?: null, - 'fax' => $user->getFax() ?: null, - 'job' => $user->getJob() ?: null, - 'position' => $user->getActivity() ?: null, - 'company' => $user->getCompany() ?: null, - 'geoname_id' => $user->getGeonameId() ?: null, - 'last_connection' => $user->getLastConnection() ? $user->getLastConnection()->format(DATE_ATOM) : null, - 'created_on' => $user->getCreated() ? $user->getCreated()->format(DATE_ATOM) : null, - 'updated_on' => $user->getUpdated() ? $user->getUpdated()->format(DATE_ATOM) : null, - 'locale' => $user->getLocale() ?: null, - ]; - } } diff --git a/lib/Alchemy/Phrasea/Feed/FeedInterface.php b/lib/Alchemy/Phrasea/Feed/FeedInterface.php index 54fd7e2b34..b95b9525c6 100644 --- a/lib/Alchemy/Phrasea/Feed/FeedInterface.php +++ b/lib/Alchemy/Phrasea/Feed/FeedInterface.php @@ -11,6 +11,8 @@ namespace Alchemy\Phrasea\Feed; +use Alchemy\Phrasea\Model\Entities\FeedEntry; + interface FeedInterface { /** @@ -33,7 +35,7 @@ interface FeedInterface * @param integer $offset_start * @param integer $how_many * - * @return \Doctrine\Common\Collections\Collection + * @return FeedEntry[] */ public function getEntries($offset_start = 0, $how_many = null); diff --git a/lib/Alchemy/Phrasea/Model/Entities/Feed.php b/lib/Alchemy/Phrasea/Model/Entities/Feed.php index 2f78758198..8d926dc00f 100644 --- a/lib/Alchemy/Phrasea/Model/Entities/Feed.php +++ b/lib/Alchemy/Phrasea/Model/Entities/Feed.php @@ -299,7 +299,7 @@ class Feed implements FeedInterface * * @param Application $app * - * @return type + * @return \collection */ public function getCollection(Application $app) { @@ -313,7 +313,7 @@ class Feed implements FeedInterface * * @param \collection $collection * - * @return type + * @return void */ public function setCollection(\collection $collection = null) { diff --git a/lib/Alchemy/Phrasea/Model/Repositories/FeedRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/FeedRepository.php index 708a234107..2a7ad81cf2 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/FeedRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/FeedRepository.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Model\Repositories; +use Alchemy\Phrasea\Model\Entities\Feed; use Doctrine\ORM\EntityRepository; /** @@ -24,7 +25,7 @@ class FeedRepository extends EntityRepository /** * Returns all the feeds a user can access. * - * @return \Doctrine\Common\Collections\Collection + * @return Feed[] */ public function getAllForUser(\ACL $userACL, array $restrictions = []) { diff --git a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php index 4a8d84d854..9516dda53e 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php +++ b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php @@ -245,7 +245,7 @@ class SearchEngineOptions * Returns an array containing all the databoxes where the search will * happen * - * @return array + * @return \databox[] */ public function getDataboxes() { diff --git a/lib/classes/caption/record.php b/lib/classes/caption/record.php index 5bd27c801a..8033758fb5 100644 --- a/lib/classes/caption/record.php +++ b/lib/classes/caption/record.php @@ -58,13 +58,16 @@ class caption_record implements caption_interface, cache_cacheableInterface return $this->record; } + /** + * @return \caption_field[] + * @throws \Doctrine\DBAL\DBALException + */ protected function retrieve_fields() { if (is_array($this->fields)) { return $this->fields; } - $fields = []; try { $fields = $this->get_data_from_cache(); } catch (\Exception $e) { @@ -97,11 +100,10 @@ class caption_record implements caption_interface, cache_cacheableInterface } /** - * * @param array $grep_fields * @param Boolean $IncludeBusiness * - * @return array + * @return \caption_field[] */ public function get_fields(Array $grep_fields = null, $IncludeBusiness = false) { diff --git a/lib/classes/databox/field.php b/lib/classes/databox/field.php index 6b849b9aca..99e54f4f1c 100644 --- a/lib/classes/databox/field.php +++ b/lib/classes/databox/field.php @@ -527,7 +527,7 @@ class databox_field implements cache_cacheableInterface /** * - * @return \PHPExiftool\Driver\Tag + * @return TagInterface */ public function get_tag() { diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php index 537a803a81..8ef47917e6 100644 --- a/lib/classes/record/adapter.php +++ b/lib/classes/record/adapter.php @@ -27,6 +27,7 @@ use Alchemy\Phrasea\SearchEngine\SearchEngineInterface; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Doctrine\ORM\EntityManager; use Doctrine\Common\Collections\ArrayCollection; +use MediaVorus\Media\MediaInterface; use MediaVorus\MediaVorus; use Rhumsaa\Uuid\Uuid; use Alchemy\Phrasea\Model\RecordInterface; @@ -755,7 +756,6 @@ class record_adapter implements RecordInterface, cache_cacheableInterface } /** - * * @return caption_record */ public function get_caption() @@ -1706,8 +1706,8 @@ class record_adapter implements RecordInterface, cache_cacheableInterface public function get_container_baskets(EntityManager $em, User $user) { return $em - ->getRepository('Phraseanet:Basket') - ->findContainingRecordForUser($this, $user); + ->getRepository('Phraseanet:Basket') + ->findContainingRecordForUser($this, $user); } /** diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiTestCase.php b/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiTestCase.php index 8ca5b4d93c..0db8ca31c6 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiTestCase.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiTestCase.php @@ -4,6 +4,7 @@ namespace Alchemy\Tests\Phrasea\Controller\Api; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Border\File; +use Alchemy\Phrasea\Controller\Api\V1Controller; use Alchemy\Phrasea\ControllerProvider\Api\V1; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Authentication\Context; @@ -981,7 +982,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertArrayHasKey('embed', $content['response']); - $embedTypes = array_flip(array_map(function($subdef) {return $subdef['name'];},$content['response']['embed'])); + $embedTypes = array_flip(array_map(function($subdef) {return $subdef['name'];}, $content['response']['embed'])); //access to all subdefs $this->assertArrayHasKey('document', $embedTypes); @@ -1895,7 +1896,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase protected function evaluateGoodUserItem($data, User $user) { foreach ([ - '@entity@' => V1::OBJECT_TYPE_USER, + '@entity@' => V1Controller::OBJECT_TYPE_USER, 'id' => $user->getId(), 'email' => $user->getEmail() ?: null, 'login' => $user->getLogin() ?: null, @@ -2397,7 +2398,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertArrayHasKey('thumbnail', $story); $this->assertArrayHasKey('uuid', $story); $this->assertArrayHasKey('@entity@', $story); - $this->assertEquals(V1::OBJECT_TYPE_STORY, $story['@entity@']); + $this->assertEquals(V1Controller::OBJECT_TYPE_STORY, $story['@entity@']); $this->assertTrue(Uuid::isValid($story['uuid'])); if ( ! is_null($story['thumbnail'])) { @@ -2430,7 +2431,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } $this->assertArrayHasKey('@entity@', $story['metadatas']); - $this->assertEquals(V1::OBJECT_TYPE_STORY_METADATA_BAG, $story['metadatas']['@entity@']); + $this->assertEquals(V1Controller::OBJECT_TYPE_STORY_METADATA_BAG, $story['metadatas']['@entity@']); foreach ($story['records'] as $record) { $this->evaluateGoodRecord($record); From b268b2d07b7cddb299ebc6c8e96c2125404439d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Tue, 28 Apr 2015 10:24:58 +0200 Subject: [PATCH 3/6] Some PHPCS issues --- .../Phrasea/Border/Checker/Response.php | 4 +- .../Phrasea/ControllerProvider/Api/V1.php | 138 +++++------------- 2 files changed, 37 insertions(+), 105 deletions(-) diff --git a/lib/Alchemy/Phrasea/Border/Checker/Response.php b/lib/Alchemy/Phrasea/Border/Checker/Response.php index 2383c98b17..c44b7e0caf 100644 --- a/lib/Alchemy/Phrasea/Border/Checker/Response.php +++ b/lib/Alchemy/Phrasea/Border/Checker/Response.php @@ -24,8 +24,8 @@ class Response /** * Constructor * - * @param boolean $ok True if the response is OK - * @param Checker $checker The checker attachedto the response + * @param boolean $ok True if the response is OK + * @param CheckerInterface $checker The checker attachedto the response */ public function __construct($ok, CheckerInterface $checker) { diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php b/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php index cfdef0e1a2..b6bcd140c7 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Api/V1.php @@ -12,35 +12,19 @@ namespace Alchemy\Phrasea\ControllerProvider\Api; use Alchemy\Phrasea\Application as PhraseaApplication; -use Alchemy\Phrasea\Controller\Api\Result; use Alchemy\Phrasea\Controller\Api\V1Controller; -use Alchemy\Phrasea\Core\Event\RecordEdit; -use Alchemy\Phrasea\Core\PhraseaEvents; -use Alchemy\Phrasea\Feed\Aggregate; -use Alchemy\Phrasea\Feed\FeedInterface; -use Alchemy\Phrasea\Model\Entities\Basket; -use Alchemy\Phrasea\Model\Entities\BasketElement; -use Alchemy\Phrasea\Model\Entities\Feed; -use Alchemy\Phrasea\Model\Entities\FeedEntry; -use Alchemy\Phrasea\Model\Entities\FeedItem; -use Alchemy\Phrasea\Model\Entities\User; -use Alchemy\Phrasea\Model\Entities\ValidationData; -use Alchemy\Phrasea\Model\Repositories\BasketRepository; use Silex\Application; use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class V1 implements ControllerProviderInterface, ServiceProviderInterface { const VERSION = '1.4.1'; public static $extendedContentTypes = [ - 'json' => ['application/vnd.phraseanet.record-extended+json'], - 'yaml' => ['application/vnd.phraseanet.record-extended+yaml'], + 'json' => ['application/vnd.phraseanet.record-extended+json'], + 'yaml' => ['application/vnd.phraseanet.record-extended+yaml'], 'jsonp' => ['application/vnd.phraseanet.record-extended+jsonp'], ]; @@ -64,75 +48,55 @@ class V1 implements ControllerProviderInterface, ServiceProviderInterface $controllers->after('controller.api.v1:after'); $controllers->get('/monitor/scheduler/', 'controller.api.v1:getSchedulerAction') - ->before('controller.api.v1:ensureAdmin') - ; + ->before('controller.api.v1:ensureAdmin'); $controllers->get('/monitor/tasks/', 'controller.api.v1:indexTasksAction') - ->before('controller.api.v1:ensureAdmin') - ; - + ->before('controller.api.v1:ensureAdmin'); $controllers->get('/monitor/task/{task}/', 'controller.api.v1:showTaskAction') ->convert('task', $app['converter.task-callback']) ->before('controller.api.v1:ensureAdmin') - ->assert('task', '\d+') - ; - + ->assert('task', '\d+'); $controllers->post('/monitor/task/{task}/', 'controller.api.v1:setTaskPropertyAction') ->convert('task', $app['converter.task-callback']) ->before('controller.api.v1:ensureAdmin') - ->assert('task', '\d+') - ; - + ->assert('task', '\d+'); $controllers->post('/monitor/task/{task}/start/', 'controller.api.v1:startTaskAction') ->convert('task', $app['converter.task-callback']) - ->before('controller.api.v1:ensureAdmin') - ; - + ->before('controller.api.v1:ensureAdmin'); $controllers->post('/monitor/task/{task}/stop/', 'controller.api.v1:stopTaskAction') ->convert('task', $app['converter.task-callback']) - ->before('controller.api.v1:ensureAdmin') - ; + ->before('controller.api.v1:ensureAdmin'); $controllers->get('/monitor/phraseanet/', 'controller.api.v1:showPhraseanetConfigurationAction') - ->before('controller.api.v1:ensureAdmin') - ; + ->before('controller.api.v1:ensureAdmin'); $controllers->get('/databoxes/list/', 'controller.api.v1:listDataboxesAction'); $controllers->get('/databoxes/{databox_id}/collections/', 'controller.api.v1:getDataboxCollectionsAction') ->before('controller.api.v1:ensureAccessToDatabox') - ->assert('databox_id', '\d+') - ; - + ->assert('databox_id', '\d+'); $controllers->get('/databoxes/{any_id}/collections/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/databoxes/{databox_id}/status/', 'controller.api.v1:getDataboxStatusAction') ->before('controller.api.v1:ensureAccessToDatabox') ->before('controller.api.v1:ensureCanSeeDataboxStructure') - ->assert('databox_id', '\d+') - ; - + ->assert('databox_id', '\d+'); $controllers->get('/databoxes/{any_id}/status/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/databoxes/{databox_id}/metadatas/', 'controller.api.v1:getDataboxMetadataAction') ->before('controller.api.v1:ensureAccessToDatabox') ->before('controller.api.v1:ensureCanSeeDataboxStructure') - ->assert('databox_id', '\d+') - ; - + ->assert('databox_id', '\d+'); $controllers->get('/databoxes/{any_id}/metadatas/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/databoxes/{databox_id}/termsOfUse/', 'controller.api.v1:getDataboxTermsAction') ->before('controller.api.v1:ensureAccessToDatabox') - ->assert('databox_id', '\d+') - ; - + ->assert('databox_id', '\d+'); $controllers->get('/databoxes/{any_id}/termsOfUse/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/quarantine/list/', 'controller.api.v1:listQuarantineAction'); $controllers->get('/quarantine/item/{lazaret_id}/', 'controller.api.v1:listQuarantineItemAction'); - $controllers->get('/quarantine/item/{any_id}/', 'controller.api.v1:getBadRequestAction'); $controllers->post('/records/add/', 'controller.api.v1:addRecordAction'); @@ -146,58 +110,48 @@ class V1 implements ControllerProviderInterface, ServiceProviderInterface $controllers->get('/records/{databox_id}/{record_id}/caption/', 'controller.api.v1:getRecordCaptionAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; + ->assert('record_id', '\d+'); $controllers->get('/records/{any_id}/{anyother_id}/caption/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/records/{databox_id}/{record_id}/metadatas/', 'controller.api.v1:getRecordMetadataAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->get('/records/{any_id}/{anyother_id}/metadatas/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/records/{databox_id}/{record_id}/status/', 'controller.api.v1:getRecordStatusAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->get('/records/{any_id}/{anyother_id}/status/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/records/{databox_id}/{record_id}/related/', 'controller.api.v1:getRelatedRecordsAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->get('/records/{any_id}/{anyother_id}/related/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/records/{databox_id}/{record_id}/embed/', 'controller.api.v1:getEmbeddedRecordAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->get('/records/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequestAction'); - $controllers->post('/records/{databox_id}/{record_id}/setmetadatas/', 'controller.api.v1:setRecordMetadataAction') + $controllers->post( + '/records/{databox_id}/{record_id}/setmetadatas/', + 'controller.api.v1:setRecordMetadataAction' + ) ->before('controller.api.v1:ensureCanAccessToRecord') ->before('controller.api.v1:ensureCanModifyRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->post('/records/{any_id}/{anyother_id}/setmetadatas/', 'controller.api.v1:getBadRequestAction'); $controllers->post('/records/{databox_id}/{record_id}/setstatus/', 'controller.api.v1:setRecordStatusAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->before('controller.api.v1:ensureCanModifyRecordStatus') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->post('/records/{any_id}/{anyother_id}/setstatus/', 'controller.api.v1:getBadRequestAction'); $controllers->post( @@ -207,9 +161,7 @@ class V1 implements ControllerProviderInterface, ServiceProviderInterface ->before('controller.api.v1:ensureCanAccessToRecord') ->before('controller.api.v1:ensureCanMoveRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->post( '/records/{wrong_databox_id}/{wrong_record_id}/setcollection/', 'controller.api.v1:getBadRequestAction' @@ -218,9 +170,7 @@ class V1 implements ControllerProviderInterface, ServiceProviderInterface $controllers->get('/records/{databox_id}/{record_id}/', 'controller.api.v1:getRecordAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->get('/records/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/baskets/list/', 'controller.api.v1:searchBasketsAction'); @@ -230,33 +180,25 @@ class V1 implements ControllerProviderInterface, ServiceProviderInterface $controllers->get('/baskets/{basket}/content/', 'controller.api.v1:getBasketAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-access']) - ->assert('basket', '\d+') - ; - + ->assert('basket', '\d+'); $controllers->get('/baskets/{wrong_basket}/content/', 'controller.api.v1:getBadRequestAction'); $controllers->post('/baskets/{basket}/setname/', 'controller.api.v1:setBasketTitleAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) - ->assert('basket', '\d+') - ; - + ->assert('basket', '\d+'); $controllers->post('/baskets/{wrong_basket}/setname/', 'controller.api.v1:getBadRequestAction'); $controllers->post('/baskets/{basket}/setdescription/', 'controller.api.v1:setBasketDescriptionAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) - ->assert('basket', '\d+') - ; - + ->assert('basket', '\d+'); $controllers->post('/baskets/{wrong_basket}/setdescription/', 'controller.api.v1:getBadRequestAction'); $controllers->post('/baskets/{basket}/delete/', 'controller.api.v1:deleteBasketAction') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) - ->assert('basket', '\d+') - ; - + ->assert('basket', '\d+'); $controllers->post('/baskets/{wrong_basket}/delete/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/feeds/list/', 'controller.api.v1:searchPublicationsAction'); @@ -264,43 +206,33 @@ class V1 implements ControllerProviderInterface, ServiceProviderInterface $controllers->get('/feeds/content/', 'controller.api.v1:getPublicationsAction'); $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:getFeedEntryAction') - ->assert('entry_id', '\d+') - ; - + ->assert('entry_id', '\d+'); $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/feeds/{feed_id}/content/', 'controller.api.v1:getPublicationAction') - ->assert('feed_id', '\d+') - ; - + ->assert('feed_id', '\d+'); $controllers->get('/feeds/{wrong_feed_id}/content/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/stories/{databox_id}/{record_id}/embed/', 'controller.api.v1:getStoryEmbedAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->get('/stories/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequestAction'); $controllers->get('/stories/{databox_id}/{record_id}/', 'controller.api.v1:getStoryAction') ->before('controller.api.v1:ensureCanAccessToRecord') ->assert('databox_id', '\d+') - ->assert('record_id', '\d+') - ; - + ->assert('record_id', '\d+'); $controllers->get('/stories/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequestAction'); $controllers->post('/stories', 'controller.api.v1:createStoriesAction'); $controllers->post('/stories/{databox_id}/{story_id}/records', 'controller.api.v1:createRecordStoryAction') ->assert('databox_id', '\d+') - ->assert('story_id', '\d+') - ; + ->assert('story_id', '\d+'); $controllers->get('/me/', 'controller.api.v1:getCurrentUserAction'); - return $controllers; } } From c90a60b0f629b68efbf791c79589b21d82c202d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Tue, 28 Apr 2015 10:40:54 +0200 Subject: [PATCH 4/6] Missing OAuth Service Provider --- lib/Alchemy/Phrasea/Application/Api.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index e17d30697f..48ac19b0e7 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -33,6 +33,7 @@ use Symfony\Component\HttpFoundation\Response; return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { $app = new PhraseaApplication($environment); + $app->register(new OAuth2()); $app->register(new V1()); $app->loadPlugins(); From d9cbe87c26e216079607382473a4cccba946310e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Thu, 30 Apr 2015 20:23:22 +0200 Subject: [PATCH 5/6] Refactor of Client Root --- lib/Alchemy/Phrasea/Application.php | 5 +- .../Controller/Client/RootController.php | 44 ++++++++++++++++ .../ControllerProvider/Client/Root.php | 52 +++++++------------ 3 files changed, 65 insertions(+), 36 deletions(-) create mode 100644 lib/Alchemy/Phrasea/Controller/Client/RootController.php diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 570ce969f0..af665f7be1 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -12,7 +12,6 @@ namespace Alchemy\Phrasea; use Alchemy\Geonames\GeonamesServiceProvider; -use Alchemy\Phrasea\ControllerProvider\Client\Root as ClientRoot; use Alchemy\Phrasea\ControllerProvider\Prod\BasketController; use Alchemy\Phrasea\ControllerProvider\Prod\Bridge; use Alchemy\Phrasea\ControllerProvider\Prod\DoDownload; @@ -313,6 +312,7 @@ class Application extends SilexApplication 'Alchemy\Phrasea\ControllerProvider\Admin\Subdefs' => [], 'Alchemy\Phrasea\ControllerProvider\Admin\TaskManager' => [], 'Alchemy\Phrasea\ControllerProvider\Admin\Users' => [], + 'Alchemy\Phrasea\ControllerProvider\Client\Root' => [], 'Alchemy\Phrasea\ControllerProvider\Datafiles' => [], 'Alchemy\Phrasea\ControllerProvider\Lightbox' => [], 'Alchemy\Phrasea\ControllerProvider\Minifier' => [], @@ -622,8 +622,6 @@ class Application extends SilexApplication $this->mount('/login/', new Login()); $this->mount('/developers/', new Developers()); - $this->mount('/client/', new ClientRoot()); - $this->mount('/prod/query/', new Query()); $this->mount('/prod/order/', new Order()); $this->mount('/prod/baskets', new BasketController()); @@ -676,6 +674,7 @@ class Application extends SilexApplication '/admin/subdefs' => 'Alchemy\Phrasea\ControllerProvider\Admin\Subdefs', '/admin/task-manager' => 'Alchemy\Phrasea\ControllerProvider\Admin\TaskManager', '/admin/users' => 'Alchemy\Phrasea\ControllerProvider\Admin\Users', + '/client/' => 'Alchemy\Phrasea\ControllerProvider\Client\Root', '/datafiles' => 'Alchemy\Phrasea\ControllerProvider\Datafiles', '/include/minify' => 'Alchemy\Phrasea\ControllerProvider\Minifier', '/lightbox' => 'Alchemy\Phrasea\ControllerProvider\Lightbox', diff --git a/lib/Alchemy/Phrasea/Controller/Client/RootController.php b/lib/Alchemy/Phrasea/Controller/Client/RootController.php new file mode 100644 index 0000000000..e79bf389a1 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Client/RootController.php @@ -0,0 +1,44 @@ +app['firewall']; + } + + /** + * Gets client main page + * + * @param Request $request + * @return Response + */ + public function getClientAction(Request $request) + { + if (!$this->getAuthenticator()->isAuthenticated() && null !== $request->query->get('nolog')) { + return $this->app->redirectPath('login_authenticate_as_guest', ['redirect' => 'client']); + } + if (null !== $response = $this->getFirewall()->requireAuthentication()) { + return $response; + } + + return $this->app->redirect($this->app->path('prod', array('client'))); + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php b/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php index af354d89be..a8e35131fb 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php @@ -11,49 +11,35 @@ namespace Alchemy\Phrasea\ControllerProvider\Client; -use Alchemy\Phrasea\Feed\Aggregate; -use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; -use Alchemy\Phrasea\Exception\SessionNotFound; +use Alchemy\Phrasea\Application as PhraseaApplication; +use Alchemy\Phrasea\Controller\Client\RootController; use Silex\Application; use Silex\ControllerProviderInterface; -use Symfony\Component\Finder\Finder; -use Symfony\Component\HttpFoundation\JsonResponse; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; +use Silex\ServiceProviderInterface; -class Root implements ControllerProviderInterface +class Root implements ControllerProviderInterface, ServiceProviderInterface { + public function register(Application $app) + { + $app['controller.client'] = $app->share( + function (PhraseaApplication $app) { + return new RootController($app); + } + ); + } + + public function boot(Application $app) + { + // no-op + } + public function connect(Application $app) { - $app['controller.client'] = $this; - $controllers = $app['controllers_factory']; - $controllers->before(function (Request $request) use ($app) { - - if (!$app['authentication']->isAuthenticated() && null !== $request->query->get('nolog')) { - return $app->redirectPath('login_authenticate_as_guest', ['redirect' => 'client']); - } - if (null !== $response = $app['firewall']->requireAuthentication()) { - return $response; - } - }); - - $controllers->get('/', 'controller.client:getClient') + $controllers->get('/', 'controller.client:getClientAction') ->bind('get_client'); return $controllers; } - - /** - * Gets client main page - * - * @param Application $app - * @param Request $request - * @return Response - */ - public function getClient(Application $app, Request $request) - { - return $app->redirect($app->path('prod', array('client'))); - } } From 554239d366152e12fffe4d490c2fc25b3a9119fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Burnichon?= Date: Thu, 30 Apr 2015 21:27:59 +0200 Subject: [PATCH 6/6] Add ControllerProviderTrait Ease writing of controller providers and reduce duplication --- .../ControllerProvider/Admin/Collection.php | 9 ++-- .../Admin/ConnectedUsers.php | 9 ++-- .../ControllerProvider/Admin/Databox.php | 9 ++-- .../ControllerProvider/Admin/Databoxes.php | 13 ++--- .../ControllerProvider/Admin/Feeds.php | 13 ++--- .../ControllerProvider/Admin/Fields.php | 13 ++--- .../Phrasea/ControllerProvider/Admin/Root.php | 13 ++--- .../ControllerProvider/Admin/Subdefs.php | 13 ++--- .../ControllerProvider/Admin/TaskManager.php | 13 ++--- .../ControllerProvider/Admin/Users.php | 14 +++--- .../ControllerProvider/Client/Root.php | 8 ++-- .../ControllerProviderTrait.php | 48 +++++++++++++++++++ .../Phrasea/ControllerProvider/Lightbox.php | 7 ++- .../Prod/BasketController.php | 7 +-- .../ControllerProvider/Prod/Bridge.php | 7 +-- .../ControllerProvider/Prod/Download.php | 7 +-- .../Phrasea/ControllerProvider/Prod/Edit.php | 10 ++-- .../ControllerProvider/Prod/Export.php | 8 ++-- .../Phrasea/ControllerProvider/Prod/Feed.php | 7 +-- .../ControllerProvider/Prod/Lazaret.php | 7 +-- .../Prod/MoveCollection.php | 7 +-- .../Phrasea/ControllerProvider/Prod/Order.php | 7 +-- .../ControllerProvider/Prod/Property.php | 7 +-- .../Phrasea/ControllerProvider/Prod/Push.php | 7 +-- .../Phrasea/ControllerProvider/Prod/Query.php | 7 +-- .../ControllerProvider/Prod/Records.php | 7 +-- .../Phrasea/ControllerProvider/Prod/Share.php | 7 +-- .../Phrasea/ControllerProvider/Prod/Story.php | 7 +-- .../Phrasea/ControllerProvider/Prod/Tools.php | 7 +-- .../ControllerProvider/Prod/Tooltip.php | 8 ++-- .../ControllerProvider/Prod/Upload.php | 7 +-- .../ControllerProvider/Prod/UsrLists.php | 7 +-- .../ControllerProvider/Prod/WorkZone.php | 7 +-- .../ControllerProvider/Report/Activity.php | 7 +-- .../Report/Informations.php | 7 +-- .../ControllerProvider/Report/Root.php | 7 +-- .../ControllerProvider/Root/Account.php | 7 +-- .../ControllerProvider/Root/Developers.php | 7 +-- .../Thesaurus/Thesaurus.php | 7 +-- .../ControllerProvider/Thesaurus/Xmlhttp.php | 13 ++--- .../ControllerProvider/User/Notifications.php | 6 +-- .../ControllerProvider/User/Preferences.php | 6 +-- 42 files changed, 223 insertions(+), 171 deletions(-) create mode 100644 lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderTrait.php diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php index d6fd6f8110..ba6bfe76cc 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Collection.php @@ -13,13 +13,15 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\CollectionController; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class Collection implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.collection'] = $app->share(function (PhraseaApplication $app) { @@ -33,10 +35,7 @@ class Collection implements ControllerProviderInterface, ServiceProviderInterfac public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function () use ($app) { $app['firewall']->requireAccessToModule('admin') diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/ConnectedUsers.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/ConnectedUsers.php index e30460e433..a81a02caa7 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/ConnectedUsers.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/ConnectedUsers.php @@ -13,13 +13,15 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\ConnectedUsersController; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class ConnectedUsers implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.connected-users'] = $app->share(function (PhraseaApplication $app) { @@ -43,10 +45,7 @@ class ConnectedUsers implements ControllerProviderInterface, ServiceProviderInte public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function () use ($app) { $app['firewall']->requireAccessToModule('Admin'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php index 91301a1732..4c46c67458 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databox.php @@ -13,15 +13,17 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\DataboxController; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Security\Firewall; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; use Symfony\Component\HttpFoundation\Request; class Databox implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.databox'] = $app->share(function (PhraseaApplication $app) { @@ -35,10 +37,7 @@ class Databox implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers ->before(function (Request $request) use ($app) { diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databoxes.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databoxes.php index b99d79ecb0..345e317379 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databoxes.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Databoxes.php @@ -13,14 +13,15 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\DataboxesController; -use Alchemy\Phrasea\Security\Firewall; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class Databoxes implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.databoxes'] = $app->share(function (PhraseaApplication $app) { @@ -34,12 +35,8 @@ class Databoxes implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - /** @var Firewall $firewall */ - $firewall = $app['firewall']; - $firewall->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); $controllers->before(function () use ($firewall) { $firewall->requireAccessToModule('admin'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Feeds.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Feeds.php index 8035a2896e..7ee2580532 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Feeds.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Feeds.php @@ -13,14 +13,15 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\FeedController; -use Alchemy\Phrasea\Security\Firewall; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class Feeds implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.feeds'] = $app->share(function (PhraseaApplication $app) { @@ -34,12 +35,8 @@ class Feeds implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - /** @var Firewall $firewall */ - $firewall = $app['firewall']; - $firewall->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); $controllers->before(function () use ($firewall) { $firewall diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Fields.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Fields.php index 8dae2e0cad..9633c80175 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Fields.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Fields.php @@ -13,14 +13,15 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\FieldsController; -use Alchemy\Phrasea\Security\Firewall; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class Fields implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.fields'] = $app->share(function (PhraseaApplication $app) { @@ -34,12 +35,8 @@ class Fields implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - /** @var Firewall $firewall */ - $firewall = $app['firewall']; - $firewall->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); $controllers->before(function () use ($firewall) { $firewall diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Root.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Root.php index f65875328d..8e04f136c9 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Root.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Root.php @@ -13,14 +13,15 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\RootController; -use Alchemy\Phrasea\Security\Firewall; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class Root implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.root'] = $app->share(function (PhraseaApplication $app) { @@ -34,12 +35,8 @@ class Root implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - /** @var Firewall $firewall */ - $firewall = $app['firewall']; - $firewall->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); $controllers->before(function () use ($firewall) { $firewall->requireAccessToModule('admin'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Subdefs.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Subdefs.php index 14d5c4bfb8..55deef159e 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Subdefs.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Subdefs.php @@ -13,15 +13,16 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Controller\Admin\SubdefsController; -use Alchemy\Phrasea\Security\Firewall; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; use Symfony\Component\HttpFoundation\Request; class Subdefs implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.subdefs'] = $app->share(function (PhraseaApplication $app) { @@ -35,12 +36,8 @@ class Subdefs implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - /** @var Firewall $firewall */ - $firewall = $app['firewall']; - $firewall->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); $controllers->before(function (Request $request) use ($firewall) { $firewall->requireAccessToModule('admin') diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/TaskManager.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/TaskManager.php index 2267cb9454..1614c40be1 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/TaskManager.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/TaskManager.php @@ -12,15 +12,16 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Controller\Admin\TaskManagerController; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Converter\TaskConverter; -use Alchemy\Phrasea\Security\Firewall; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class TaskManager implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.task'] = $app->share(function (\Alchemy\Phrasea\Application $app) { @@ -34,12 +35,8 @@ class TaskManager implements ControllerProviderInterface, ServiceProviderInterfa public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; - - /** @var Firewall $firewall */ - $firewall = $app['firewall']; - $firewall->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); $converter = function ($task) use ($app) { /** @var TaskConverter $converter */ diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Users.php b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Users.php index 30f1a2f89c..2500007575 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Admin/Users.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Admin/Users.php @@ -12,13 +12,15 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin; use Alchemy\Phrasea\Controller\Admin\UserController; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; -use Silex\ControllerCollection; use Silex\ControllerProviderInterface; use Silex\ServiceProviderInterface; class Users implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.admin.users'] = $app->share(function () use ($app) { @@ -32,13 +34,11 @@ class Users implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - /** @var ControllerCollection $controllers */ - $controllers = $app['controllers_factory']; + $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); - $app['firewall']->addMandatoryAuthentication($controllers); - - $controllers->before(function () use ($app) { - $app['firewall']->requireAccessToModule('admin') + $controllers->before(function () use ($firewall) { + $firewall->requireAccessToModule('admin') ->requireRight('manageusers'); }); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php b/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php index a8e35131fb..94aa07cfe7 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Client/Root.php @@ -21,11 +21,9 @@ class Root implements ControllerProviderInterface, ServiceProviderInterface { public function register(Application $app) { - $app['controller.client'] = $app->share( - function (PhraseaApplication $app) { - return new RootController($app); - } - ); + $app['controller.client'] = $app->share(function (PhraseaApplication $app) { + return new RootController($app); + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderTrait.php b/lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderTrait.php new file mode 100644 index 0000000000..bfd09a6192 --- /dev/null +++ b/lib/Alchemy/Phrasea/ControllerProvider/ControllerProviderTrait.php @@ -0,0 +1,48 @@ +getFirewall($app)->addMandatoryAuthentication($controllers); + + return $controllers; + } + + /** + * @param Application $app + * @return ControllerCollection + */ + protected function createCollection(Application $app) + { + return $app['controllers_factory']; + } + + /** + * @param Application $app + * @return Firewall + */ + protected function getFirewall(Application $app) + { + return $app['firewall']; + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Lightbox.php b/lib/Alchemy/Phrasea/ControllerProvider/Lightbox.php index a4b9d3b894..4f00cca366 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Lightbox.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Lightbox.php @@ -23,6 +23,8 @@ use Symfony\Component\HttpFoundation\Request; class Lightbox implements ControllerProviderInterface, ServiceProviderInterface { + use ControllerProviderTrait; + public function register(Application $app) { $app['controller.lightbox'] = $app->share(function (PhraseaApplication $app) { @@ -36,11 +38,12 @@ class Lightbox implements ControllerProviderInterface, ServiceProviderInterface public function connect(Application $app) { - $controllers = $app['controllers_factory']; + $controllers = $this->createCollection($app); $controllers->before([$this, 'redirectOnLogRequests']); - $app['firewall']->addMandatoryAuthentication($controllers); + $firewall = $this->getFirewall($app); + $firewall->addMandatoryAuthentication($controllers); $controllers // Silex\Route::convert is not used as this should be done prior the before middleware diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/BasketController.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/BasketController.php index ce26694168..4799754983 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/BasketController.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/BasketController.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Entities\Basket as BasketEntity; use Alchemy\Phrasea\Model\Entities\BasketElement; use Alchemy\Phrasea\Model\Entities\ValidationData; @@ -23,13 +24,13 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class BasketController implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.basket'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers // Silex\Route::convert is not used as this should be done prior the before middleware diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Bridge.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Bridge.php index 6bd482886b..0f2a969362 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Bridge.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Bridge.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\Prod\HttpException; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Helper\Record as RecordHelper; use Silex\Application; use Silex\ControllerProviderInterface; @@ -20,13 +21,13 @@ use Symfony\Component\HttpFoundation\Request; class Bridge implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['bridge.controller'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireRight('bas_chupub'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Download.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Download.php index 98347f0317..be3ffda6bf 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Download.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Download.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Event\ExportEvent; use Alchemy\Phrasea\Core\PhraseaEvents; use Silex\Application; @@ -20,6 +21,8 @@ use Symfony\Component\HttpFoundation\RedirectResponse; class Download implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * {@inheritDoc} */ @@ -27,9 +30,7 @@ class Download implements ControllerProviderInterface { $app['controller.prod.download'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->post('/', 'controller.prod.download:checkDownload') ->bind('check_download'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Edit.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Edit.php index ab87c3d775..06a7ec0d48 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Edit.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Edit.php @@ -11,25 +11,25 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; -use Alchemy\Phrasea\Controller\Prod\record_adapter; +use record_adapter; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Vocabulary\Controller as VocabularyController; use Alchemy\Phrasea\Controller\RecordsRequest; -use Alchemy\Phrasea\Metadata\Tag\TfEditdate; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; class Edit implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.edit'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall'] diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Export.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Export.php index 99a030a842..c17ae250f1 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Export.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Export.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Event\ExportFailureEvent; use Alchemy\Phrasea\Core\PhraseaEvents; use Silex\Application; @@ -25,6 +26,8 @@ use Symfony\Component\HttpFoundation\Response; class Export implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * {@inheritDoc} */ @@ -32,10 +35,7 @@ class Export implements ControllerProviderInterface { $app['controller.prod.export'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); - + $controllers = $this->createAuthenticatedCollection($app); $controllers->post('/multi-export/', 'controller.prod.export:displayMultiExport') ->bind('export_multi_export'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Feed.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Feed.php index 4302911c6c..a9bc9d8314 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Feed.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Feed.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Event\FeedEntryEvent; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Feed\Aggregate; @@ -27,13 +28,13 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class Feed implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.feed'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->post('/requestavailable/', function (Application $app, Request $request) { $feeds = $app['repo.feeds']->getAllForUser( diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Lazaret.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Lazaret.php index 1672d97d97..3a6d6bd8dc 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Lazaret.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Lazaret.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Entities\LazaretFile; use Alchemy\Phrasea\Border; use Alchemy\Phrasea\Border\Attribute\AttributeInterface; @@ -23,6 +24,8 @@ use Symfony\Component\Filesystem\Exception\IOException; class Lazaret implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * Connect the ControllerCollection to the Silex Application * @@ -33,9 +36,7 @@ class Lazaret implements ControllerProviderInterface { $app['controller.prod.lazaret'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireRight('addrecord'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/MoveCollection.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/MoveCollection.php index c1d2bd6b09..db1e66d3a1 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/MoveCollection.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/MoveCollection.php @@ -12,19 +12,20 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; class MoveCollection implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.move-collection'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireRight('addrecord') diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Order.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Order.php index 69d8cf8619..3d30691fed 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Order.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Order.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Event\OrderDeliveryEvent; use Alchemy\Phrasea\Core\Event\OrderEvent; use Alchemy\Phrasea\Core\PhraseaEvents; @@ -30,6 +31,8 @@ use Symfony\Component\HttpFoundation\Response; class Order implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * {@inheritDoc} */ @@ -37,9 +40,7 @@ class Order implements ControllerProviderInterface { $app['controller.prod.order'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireRight('order'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Property.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Property.php index 69e299ce28..663cd85f54 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Property.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Property.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\Prod\type; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\JsonResponse; @@ -21,6 +22,8 @@ use Symfony\Component\HttpFoundation\Response; class Property implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * {@inheritDoc} */ @@ -28,9 +31,7 @@ class Property implements ControllerProviderInterface { $app['controller.prod.property'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireNotGuest(); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php index 10666ea1f9..bed7d93d5e 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Push.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\Prod\record_adapter; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Event\PushEvent; use Alchemy\Phrasea\Core\Event\ValidationEvent; use Alchemy\Phrasea\Core\PhraseaEvents; @@ -33,6 +34,8 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Push implements ControllerProviderInterface { + use ControllerProviderTrait; + protected function getUserFormatter(Application $app) { return function (User $user) use ($app) { @@ -105,9 +108,7 @@ class Push implements ControllerProviderInterface { $app['controller.prod.push'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireRight('push'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Query.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Query.php index ee4bd34c19..7f1100aeb3 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Query.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Query.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use Silex\Application; @@ -21,13 +22,13 @@ use Symfony\Component\HttpFoundation\Response; class Query implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.query'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->post('/', 'controller.prod.query:query') ->bind('prod_query'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Records.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Records.php index a432bc174e..3d1c3a6d25 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Records.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Records.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Silex\Application; use Silex\ControllerProviderInterface; @@ -20,6 +21,8 @@ use Symfony\Component\HttpFoundation\JsonResponse; class Records implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * {@inheritDoc} */ @@ -27,9 +30,7 @@ class Records implements ControllerProviderInterface { $app['controller.prod.records'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->match('/', 'controller.prod.records:getRecord') ->bind('record_details') diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Share.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Share.php index a423bddf89..7de9370697 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Share.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Share.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; @@ -18,6 +19,8 @@ use Symfony\Component\HttpFoundation\Response; class Share implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * {@inheritDoc} */ @@ -25,9 +28,7 @@ class Share implements ControllerProviderInterface { $app['controller.prod.share'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireNotGuest(); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Story.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Story.php index ee6b216c27..84f8e60116 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Story.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Story.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\Exception as ControllerException; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Entities\StoryWZ; use Alchemy\Phrasea\Core\Event\RecordEdit; use Alchemy\Phrasea\Core\PhraseaEvents; @@ -24,13 +25,13 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class Story implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.story'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->get('/create/', function (Application $app) { return $app['twig']->render('prod/Story/Create.html.twig', []); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tools.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tools.php index 3ef4dc7b38..f59deffcdb 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tools.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tools.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Exception\RuntimeException; use DataURI; use PHPExiftool\Exception\ExceptionInterface as PHPExiftoolException; @@ -21,13 +22,13 @@ use Symfony\Component\HttpFoundation\Request; class Tools implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.tools'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireRight('doctools'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tooltip.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tooltip.php index b63b5208b2..7c1bf4e54c 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tooltip.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Tooltip.php @@ -11,21 +11,21 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Entities\Basket; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; -use Symfony\Component\HttpFoundation\Request; use Silex\Application; use Silex\ControllerProviderInterface; class Tooltip implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.tooltip'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->post('/basket/{basket}/', 'controller.prod.tooltip:displayBasket') ->assert('basket', '\d+') diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Upload.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Upload.php index 8af201d5a1..78e88ebc0f 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/Upload.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/Upload.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; use Alchemy\Phrasea\Border\File; use Alchemy\Phrasea\Border\Attribute\Status; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Event\LazaretEvent; use Alchemy\Phrasea\Core\Event\RecordEdit;use Alchemy\Phrasea\Core\PhraseaEvents; use DataURI\Parser; @@ -28,6 +29,8 @@ use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; class Upload implements ControllerProviderInterface { + use ControllerProviderTrait; + /** * Connect the ControllerCollection to the Silex Application * @@ -38,9 +41,7 @@ class Upload implements ControllerProviderInterface { $app['controller.prod.upload'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireRight('addrecord'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/UsrLists.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/UsrLists.php index f787b62182..9281699b0b 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/UsrLists.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/UsrLists.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Entities\UsrList; use Alchemy\Phrasea\Model\Entities\UsrListEntry; use Alchemy\Phrasea\Model\Entities\UsrListOwner; @@ -23,13 +24,13 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; class UsrLists implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.usr-lists'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->get('/all/', 'controller.prod.usr-lists:getAll') ->bind('prod_lists_all'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Prod/WorkZone.php b/lib/Alchemy/Phrasea/ControllerProvider/Prod/WorkZone.php index 8afb3253bf..70c176be18 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Prod/WorkZone.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Prod/WorkZone.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Prod; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Entities\Basket; use Alchemy\Phrasea\Model\Entities\StoryWZ; use Alchemy\Phrasea\Helper\WorkZone as WorkzoneHelper; @@ -23,13 +24,13 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class WorkZone implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.prod.workzone'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers // Silex\Route::convert is not used as this should be done prior the before middleware diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Report/Activity.php b/lib/Alchemy/Phrasea/ControllerProvider/Report/Activity.php index c43c386812..6f25eb2f32 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Report/Activity.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Report/Activity.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Report; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Response\CSVFileResponse; use Goodby\CSV\Export\Standard\Collection\CallbackCollection; use Silex\Application; @@ -21,13 +22,13 @@ use Symfony\Component\HttpFoundation\JsonResponse; class Activity implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.report.activity'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function () use ($app) { $app['firewall']->requireAccessToModule('report'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Report/Informations.php b/lib/Alchemy/Phrasea/ControllerProvider/Report/Informations.php index 7b6a847aec..81a9128098 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Report/Informations.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Report/Informations.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Report; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Response\CSVFileResponse; use Goodby\CSV\Export\Standard\Collection\CallbackCollection; use Silex\Application; @@ -20,13 +21,13 @@ use Symfony\Component\HttpFoundation\JsonResponse; class Informations implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.report.informations'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function () use ($app) { $app['firewall']->requireAccessToModule('report'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Report/Root.php b/lib/Alchemy/Phrasea/ControllerProvider/Report/Root.php index 5f8097c6b1..3cb15c7478 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Report/Root.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Report/Root.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Report; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Core\Response\CSVFileResponse; use Goodby\CSV\Export\Standard\Collection\CallbackCollection; use Silex\Application; @@ -21,13 +22,13 @@ use Symfony\Component\HttpFoundation\JsonResponse; class Root implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.report'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function () use ($app) { $app['firewall']->requireAccessToModule('report'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Root/Account.php b/lib/Alchemy/Phrasea/ControllerProvider/Root/Account.php index c5a9109991..a33d432d61 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Root/Account.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Root/Account.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Root; use Alchemy\Geonames\Exception\ExceptionInterface as GeonamesExceptionInterface; use Alchemy\Phrasea\Application as PhraseaApplication; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\ControllerProvider\Root\Login; use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Model\Entities\FtpCredential; @@ -29,13 +30,13 @@ use Symfony\Component\HttpFoundation\Response; class Account implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { - $controllers = $app['controllers_factory']; - $app['account.controller'] = $this; - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); // Displays current logged in user account $controllers->get('/', 'account.controller:displayAccount') diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Root/Developers.php b/lib/Alchemy/Phrasea/ControllerProvider/Root/Developers.php index 1e2fecb91b..bff7296a9a 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Root/Developers.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Root/Developers.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Root; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Model\Entities\ApiApplication; use Silex\Application; @@ -21,13 +22,13 @@ use Symfony\Component\HttpFoundation\Response; class Developers implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.account.developers'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->get('/applications/', 'controller.account.developers:listApps') ->bind('developers_applications'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php b/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php index e45ac4dafa..e7ca3bbfb4 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Thesaurus; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Doctrine\DBAL\Driver\Connection; use Silex\Application; use Silex\ControllerProviderInterface; @@ -19,13 +20,13 @@ use Symfony\Component\HttpFoundation\Response; class Thesaurus implements ControllerProviderInterface { + use ControllerProviderTrait; + public function connect(Application $app) { $app['controller.thesaurus'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function () use ($app) { $app['firewall']->requireAccessToModule('thesaurus'); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Xmlhttp.php b/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Xmlhttp.php index 942ad18a58..23054548e6 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Xmlhttp.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Xmlhttp.php @@ -11,9 +11,10 @@ namespace Alchemy\Phrasea\ControllerProvider\Thesaurus; -use Alchemy\Phrasea\Controller\Thesaurus\caption_field; -use Alchemy\Phrasea\Controller\Thesaurus\caption_Field_Value; -use Alchemy\Phrasea\Controller\Thesaurus\databox; +use caption_field; +use caption_Field_Value; +use databox; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Alchemy\Phrasea\Model\Entities\User; use Silex\Application; use Silex\ControllerProviderInterface; @@ -22,15 +23,15 @@ use Symfony\Component\HttpFoundation\Response; class Xmlhttp implements ControllerProviderInterface { + use ControllerProviderTrait; + const SEARCH_REPLACE_MAXREC = 25; public function connect(Application $app) { $app['controller.thesaurus.xmlhttp'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->match('acceptcandidates.j.php', 'controller.thesaurus.xmlhttp:AcceptCandidatesJson') ->before(function () use ($app) { diff --git a/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php b/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php index 4f82147c1a..348221602a 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/User/Notifications.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\User; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; @@ -18,6 +19,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; class Notifications implements ControllerProviderInterface { + use ControllerProviderTrait; /** * {@inheritDoc} @@ -26,9 +28,7 @@ class Notifications implements ControllerProviderInterface { $app['controller.user.notifications'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->before(function (Request $request) use ($app) { $app['firewall']->requireNotGuest(); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/User/Preferences.php b/lib/Alchemy/Phrasea/ControllerProvider/User/Preferences.php index 73bb361e52..bf8026501a 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/User/Preferences.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/User/Preferences.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\ControllerProvider\User; +use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; @@ -18,6 +19,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; class Preferences implements ControllerProviderInterface { + use ControllerProviderTrait; /** * {@inheritDoc} @@ -26,9 +28,7 @@ class Preferences implements ControllerProviderInterface { $app['controller.user.preferences'] = $this; - $controllers = $app['controllers_factory']; - - $app['firewall']->addMandatoryAuthentication($controllers); + $controllers = $this->createAuthenticatedCollection($app); $controllers->post('/', 'controller.user.preferences:saveUserPref') ->bind('save_pref');