diff --git a/config/configuration.sample.yml b/config/configuration.sample.yml index 56aee3c5be..92f738ce90 100644 --- a/config/configuration.sample.yml +++ b/config/configuration.sample.yml @@ -16,7 +16,6 @@ main: driver: pdo_sqlite path: '/tmp/db.sqlite' charset: UTF8 - api-timers: false cache: type: MemcacheCache options: diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index 4619de4a00..72d6ce0895 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -12,17 +12,18 @@ namespace Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application as PhraseaApplication; -use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Controller\Api\Oauth2; +use Alchemy\Phrasea\Controller\Api\Result; use Alchemy\Phrasea\Controller\Api\V1; -use Alchemy\Phrasea\Core\Event\ApiLoadEndEvent; -use Alchemy\Phrasea\Core\Event\ApiLoadStartEvent; +use Alchemy\Phrasea\Core\Event\ApiResultEvent; use Alchemy\Phrasea\Core\Event\Subscriber\ApiOauth2ErrorsSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber; +use Alchemy\Phrasea\Core\PhraseaEvents; use Monolog\Logger; use Monolog\Processor\WebProcessor; use Silex\Application as SilexApplication; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { @@ -38,22 +39,15 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { return $monolog; })); - $app->register(new \API_V1_Timer()); - $app['dispatcher']->dispatch(PhraseaEvents::API_LOAD_START, new ApiLoadStartEvent()); - $app->get('/api/', function (Request $request, SilexApplication $app) { - $apiAdapter = new \API_V1_adapter($app); - - $result = new \API_V1_result($app, $request, $apiAdapter); - - return $result->set_datas([ + return Result::create($request, [ 'name' => $app['conf']->get(['registry', 'general', 'title']), 'type' => 'phraseanet', 'description' => $app['conf']->get(['registry', 'general', 'description']), 'documentation' => 'https://docs.phraseanet.com/Devel', 'versions' => [ '1' => [ - 'number' => $apiAdapter->get_version(), + 'number' => V1::VERSION, 'uri' => '/api/v1/', 'authenticationProtocol' => 'OAuth2', 'authenticationVersion' => 'draft#v9', @@ -63,14 +57,20 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) { ] ] ] - ])->get_response(); + ])->createResponse(); }); $app->mount('/api/oauthv2', new Oauth2()); $app->mount('/api/v1', new V1()); - $app['dispatcher']->addSubscriber(new ApiOauth2ErrorsSubscriber($app['phraseanet.exception_handler'], $app['translator'])); - $app['dispatcher']->dispatch(PhraseaEvents::API_LOAD_END, new ApiLoadEndEvent()); + $app['dispatcher'] = $app->share($app->extend('dispatcher', function ($dispatcher, PhraseaApplication $app) { + $dispatcher->addSubscriber(new ApiOauth2ErrorsSubscriber($app['phraseanet.exception_handler'], $app['translator'])); + + return $dispatcher; + })); + $app->after(function (Request $request, Response $response) use ($app) { + $app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new ApiResultEvent($request, $response)); + }); return $app; }, isset($environment) ? $environment : PhraseaApplication::ENV_PROD); diff --git a/lib/classes/API/V1/Log.php b/lib/Alchemy/Phrasea/Controller/Api/Logger.php similarity index 83% rename from lib/classes/API/V1/Log.php rename to lib/Alchemy/Phrasea/Controller/Api/Logger.php index dfcd17702c..6370446fde 100644 --- a/lib/classes/API/V1/Log.php +++ b/lib/Alchemy/Phrasea/Controller/Api/Logger.php @@ -9,80 +9,82 @@ * file that was distributed with this source code. */ +namespace Alchemy\Phrasea\Controller\Api; + use Alchemy\Phrasea\Application; -class API_V1_Log +class Logger { - const DATABOXES_RESSOURCE = 'databoxes'; - const RECORDS_RESSOURCE = 'record'; - const BASKETS_RESSOURCE = 'baskets'; - const FEEDS_RESSOURCE = 'feeds'; + const DATABOXES_RESOURCE = 'databoxes'; + const RECORDS_RESOURCE = 'record'; + const BASKETS_RESOURCE = 'baskets'; + const FEEDS_RESOURCE = 'feeds'; /** * * @var int */ - protected $id; + private $id; /** * * @var int */ - protected $account_id; + private $account_id; /** * * @var DateTime */ - protected $date; + private $date; /** * * @var int */ - protected $status_code; + private $status_code; /** * * @var string */ - protected $format; + private $format; /** * * @var string */ - protected $ressource; + private $resource; /** * * @var string */ - protected $general; + private $general; /** * * @var string */ - protected $aspect; + private $aspect; /** * * @var string */ - protected $action; + private $action; /** * * @var API_OAuth2_Account */ - protected $account; + private $account; /** * * @var Application */ - protected $app; + private $app; /** * @@ -102,7 +104,7 @@ class API_V1_Log api_log_date, api_log_status_code, api_log_format, - api_log_ressource, + api_log_resource, api_log_general, api_log_aspect, api_log_action @@ -113,16 +115,16 @@ class API_V1_Log $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql); $stmt->execute([':log_id' => $this->id]); - $row = $stmt->fetch(PDO::FETCH_ASSOC); + $row = $stmt->fetch(\PDO::FETCH_ASSOC); $stmt->closeCursor(); $this->account_id = $row['api_account_id']; - $this->account = new API_OAuth2_Account($this->app, (int) $row['api_account_id']); + $this->account = new \API_OAuth2_Account($this->app, (int) $row['api_account_id']); $this->aspect = $row['api_log_aspect']; - $this->date = new DateTime($row['api_log_date']); + $this->date = new \DateTime($row['api_log_date']); $this->format = $row['api_log_format']; $this->general = $row['api_log_general']; - $this->ressource = $row['api_log_ressource']; + $this->resource = $row['api_log_resource']; $this->status_code = (int) $row['api_log_status_code']; return $this; @@ -212,7 +214,7 @@ class API_V1_Log { if ( ! in_array($format, ['json', 'jsonp', 'yaml', 'unknow'])) - throw new Exception_InvalidArgument(); + throw new \Exception_InvalidArgument(); $this->format = $format; @@ -232,25 +234,25 @@ class API_V1_Log return $this; } - public function get_ressource() + public function get_resource() { - return $this->ressource; + return $this->resource; } - public function set_ressource($ressource) + public function set_resource($resource) { - if ( ! in_array($format, [self::DATABOXES_RESSOURCE, self::BASKETS_RESSOURCE, self::FEEDS_RESSOURCE, self::RECORDS_RESSOURCE])) - throw new Exception_InvalidArgument(); + if ( ! in_array($resource, [self::DATABOXES_RESOURCE, self::BASKETS_RESOURCE, self::FEEDS_RESOURCE, self::RECORDS_RESOURCE])) + throw new \Exception_InvalidArgument(); - $this->ressource = $ressource; + $this->resource = $resource; $sql = 'UPDATE api_log - SET api_log_ressource = :ressource + SET api_log_resource = :resource WHERE api_log_id = :log_id'; $params = [ - ':ressource' => $this->ressource - , ':log_id' => $this->id + ':resource' => $this->resource, + ':log_id' => $this->id, ]; $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql); @@ -340,7 +342,7 @@ class API_V1_Log return $this->account; } - public static function create(Application $app, API_OAuth2_Account $account, $route, $status_code, $format, $ressource, $general = null, $aspect = null, $action = null) + public static function create(Application $app, \API_OAuth2_Account $account, $route, $status_code, $format, $resource, $general = null, $aspect = null, $action = null) { $sql = ' INSERT INTO @@ -351,7 +353,7 @@ class API_V1_Log api_log_date, api_log_status_code, api_log_format, - api_log_ressource, + api_log_resource, api_log_general, api_log_aspect, api_log_action @@ -363,7 +365,7 @@ class API_V1_Log NOW(), :status_code, :format, - :ressource, + :resource, :general, :aspect, :action @@ -374,7 +376,7 @@ class API_V1_Log ':route' => $route, ':status_code' => $status_code, ':format' => $format, - ':ressource' => $ressource, + ':resource' => $resource, ':general' => $general, ':aspect' => $aspect, ':action' => $action diff --git a/lib/Alchemy/Phrasea/Controller/Api/Result.php b/lib/Alchemy/Phrasea/Controller/Api/Result.php new file mode 100644 index 0000000000..8decf263e7 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Api/Result.php @@ -0,0 +1,267 @@ +request = $request; + $this->responseTime = $date->format(DATE_ATOM); + $this->data = new \stdClass(); + + $this->parseResponseType(); + + $this->setData($data); + $this->code = $code; + $this->errorType = $errorType; + $this->errorMessage = $errorMessage; + $this->errorDetails = $errorDetails; + + return $this; + } + + /** + * Creates a Symfony Response + * + * @return Response + */ + public function createResponse() + { + $response = new Response($this->format(), $this->getStatusCode(), ['Content-Type' => $this->getContentType()]); + $response->setCharset('UTF-8'); + + return $response; + } + + /** + * @param Request $request + * @param $data + * + * @return Result + */ + public static function create(Request $request, $data) + { + return new static($request, $data); + } + + /** + * @param Request $request + * @param $code + * @param $message + * + * @return Result + * + * @throws InvalidArgumentException + */ + public static function createError(Request $request, $code, $message) + { + $errorDetails = $message; + + switch ($code) { + case 400: + $errorType = self::ERROR_BAD_REQUEST; + $errorMessage = 'Parameter is invalid or missing'; + break; + case 401: + $errorType = self::ERROR_UNAUTHORIZED; + $errorMessage = 'The OAuth token was provided but was invalid.'; + break; + case 403: + $errorType = self::ERROR_FORBIDDEN; + $errorMessage = 'Access to the requested resource is forbidden'; + break; + case 404: + $errorType = self::ERROR_NOTFOUND; + $errorMessage = 'Requested resource is not found'; + break; + case 405: + $errorType = self::ERROR_METHODNOTALLOWED; + $errorMessage = 'Attempting to use POST with a GET-only endpoint, or vice-versa'; + break; + case 500: + $errorType = self::ERROR_INTERNALSERVERERROR; + $errorMessage = 'Internal Server Error'; + break; + case 503: + $errorType = self::ERROR_MAINTENANCE; + $errorMessage = 'Server is offline for maintenance, try again soon.'; + break; + default: + throw new \InvalidArgumentException('Unable to generate a response.'); + } + + return new static($request, null, $code, $errorType, $errorMessage, $errorDetails); + } + + private function parseResponseType() + { + if (trim($this->request->get('callback')) !== '') { + return $this->responseType = self::FORMAT_JSONP; + } + + $responseTypes = array_map('strtolower', $this->request->getAcceptableContentTypes()); + + if (in_array('application/json', $responseTypes)) { + return $this->responseType = self::FORMAT_JSON; + } + if (in_array('application/yaml', $responseTypes)) { + return $this->responseType = self::FORMAT_YAML; + } + if (in_array('text/yaml', $responseTypes)) { + return $this->responseType = self::FORMAT_YAML; + } + + return $this->responseType = self::FORMAT_JSON; + } + + /** + * Sets data to the response. + * + * If no datas provided, a stdClass if set, + * so the serialized datas will be objects + * + * @param array $datas + * + * @return Result + */ + private function setData(array $data = null) + { + if (null === $data || count($data) === 0) { + $data = new \stdClass(); + } + + $this->data = $data; + + return $this; + } + + /** + * Formats the data and return serialized string + * + * @return string + */ + private function format() + { + $request_uri = sprintf('%s %s', $this->request->getMethod(), $this->request->getBasePath().$this->request->getPathInfo()); + + $ret = [ + 'meta' => [ + 'api_version' => V1::VERSION, + 'request' => $request_uri, + 'response_time' => $this->responseTime, + 'http_code' => $this->code, + 'error_type' => $this->errorType, + 'error_message' => $this->errorMessage, + 'error_details' => $this->errorDetails, + 'charset' => 'UTF-8', + ], + 'response' => $this->data, + ]; + + switch ($this->responseType) { + case self::FORMAT_JSON: + default: + $return_value = \p4string::jsonencode($ret); + break; + case self::FORMAT_YAML: + if ($ret['response'] instanceof \stdClass) { + $ret['response'] = []; + } + + $dumper = new Dumper(); + $return_value = $dumper->dump($ret, 8); + break; + case self::FORMAT_JSONP: + $callback = trim($this->request->get('callback')); + $return_value = $callback . '(' . \p4string::jsonencode($ret) . ')'; + break; + } + + return $return_value; + } + + /** + * Returns serialized data content type + * + * @return string + */ + private function getContentType() + { + switch ($this->responseType) { + case self::FORMAT_JSON: + default: + return 'application/json'; + case self::FORMAT_YAML: + return 'application/yaml'; + case self::FORMAT_JSONP: + return 'text/javascript'; + } + } + + /** + * Returns the correct http code depending on the errors + * + * @return integer + */ + private function getStatusCode() + { + if ($this->responseType == self::FORMAT_JSONP && $this->code != 500) { + return 200; + } + + return $this->code; + } +} diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1.php b/lib/Alchemy/Phrasea/Controller/Api/V1.php index c5ff5b05a8..6b998834f2 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V1.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V1.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\Controller\Api; use Silex\ControllerProviderInterface; +use Alchemy\Phrasea\Cache\Cache as CacheInterface; use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Authentication\Context; use Alchemy\Phrasea\Core\Event\PreAuthenticate; @@ -21,736 +22,2052 @@ use Alchemy\Phrasea\Model\Entities\Basket; use Silex\Application as SilexApplication; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; +use Alchemy\Phrasea\Feed\Aggregate; +use Alchemy\Phrasea\Feed\FeedInterface; +use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; +use Alchemy\Phrasea\SearchEngine\SearchEngineSuggestion; +use Alchemy\Phrasea\Border\File; +use Alchemy\Phrasea\Border\Attribute\Status; +use Alchemy\Phrasea\Border\Manager as BorderManager; +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\LazaretFile; +use Alchemy\Phrasea\Model\Entities\Task; +use Alchemy\Phrasea\Model\Entities\User; +use Alchemy\Phrasea\Model\Entities\UserQuery; +use Alchemy\Phrasea\Model\Entities\ValidationData; +use Silex\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpFoundation\File\UploadedFile; +use Alchemy\Phrasea\Model\Repositories\BasketRepository; +use Alchemy\Phrasea\Model\Entities\LazaretSession; class V1 implements ControllerProviderInterface { + const VERSION = '1.3'; + + 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 function connect(SilexApplication $app) { $app['controller.api.v1'] = $this; $controllers = $app['controllers_factory']; - /** - * @var API_OAuth2_Token - */ - $app['token'] = null; - - /** - * Api Service - * @var Closure - */ - $app['api'] = function () use ($app) { - return new \API_V1_adapter($app); - }; - - /** - * oAuth token verification process - * - Check if oauth_token exists && is valid - * - Check if request comes from phraseanet Navigator && phraseanet Navigator - * is enbale on current instance - * - restore user session - * - * @ throws \API_V1_exception_unauthorized - * @ throws \API_V1_exception_forbidden - */ $controllers->before(function ($request) use ($app) { - $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()); - $oauth2_adapter = new \API_OAuth2_Adapter($app); - $oauth2_adapter->verifyAccessToken(); - - $app['token'] = \API_OAuth2_Token::load_by_oauth_token($app, $oauth2_adapter->getToken()); - - $oAuth2App = $app['token']->get_account()->get_application(); - /* @var $oAuth2App \API_OAuth2_Application */ - - if ($oAuth2App->get_client_id() == \API_OAuth2_Application_Navigator::CLIENT_ID - && !$app['conf']->get(['registry', 'api-clients', 'navigator-enabled'])) { - throw new \API_V1_exception_forbidden('The use of phraseanet Navigator is not allowed'); - } - - if ($oAuth2App->get_client_id() == \API_OAuth2_Application_OfficePlugin::CLIENT_ID - && ! $app['conf']->get(['registry', 'api-clients', 'office-enabled'])) { - throw new \API_V1_exception_forbidden('The use of Office Plugin is not allowed.'); - } - - if ($app['authentication']->isAuthenticated()) { - $app['dispatcher']->dispatch(PhraseaEvents::API_OAUTH2_END, new ApiOAuth2EndEvent()); - - return; - } - - $user = $app['manipulator.user']->getRepository()->find($oauth2_adapter->get_usr_id()); - - $app['authentication']->openAccount($user); - $oauth2_adapter->remember_this_ses_id($app['session']->get('session_id')); - $app['dispatcher']->dispatch(PhraseaEvents::API_OAUTH2_END, new ApiOAuth2EndEvent()); - - return; + return $this->authenticate($app, $request); }); - /** - * OAuth log process - * - * Parse the requested route to fetch - * - the ressource (databox, basket, record etc ..) - * - general action (list, add, search) - * - the action (setstatus, setname etc..) - * - the aspect (collections, related, content etc..) - * - * @return array - */ - $parseRoute = function ($route, Response $response) { - $ressource = $general = $aspect = $action = null; - $exploded_route = explode('/', \p4string::delFirstSlash(\p4string::delEndSlash($route))); - if (sizeof($exploded_route) > 0 && $response->isOk()) { - $ressource = $exploded_route[0]; - - if (sizeof($exploded_route) == 2 && (int) $exploded_route[1] == 0) { - $general = $exploded_route[1]; - } else { - switch ($ressource) { - case \API_V1_Log::DATABOXES_RESSOURCE : - if ((int) $exploded_route[1] > 0 && sizeof($exploded_route) == 3) - $aspect = $exploded_route[2]; - break; - case \API_V1_Log::RECORDS_RESSOURCE : - if ((int) $exploded_route[1] > 0 && sizeof($exploded_route) == 4) { - if (!isset($exploded_route[3])) - $aspect = "record"; - elseif (preg_match("/^set/", $exploded_route[3])) - $action = $exploded_route[3]; - else - $aspect = $exploded_route[3]; - } - break; - case \API_V1_Log::BASKETS_RESSOURCE : - if ((int) $exploded_route[1] > 0 && sizeof($exploded_route) == 3) { - if (preg_match("/^set/", $exploded_route[2]) || preg_match("/^delete/", $exploded_route[2])) - $action = $exploded_route[2]; - else - $aspect = $exploded_route[2]; - } - break; - case \API_V1_Log::FEEDS_RESSOURCE : - if ((int) $exploded_route[1] > 0 && sizeof($exploded_route) == 3) - $aspect = $exploded_route[2]; - break; - } - } - } - - return ['ressource' => $ressource, 'general' => $general, 'aspect' => $aspect, 'action' => $action]; - }; - - /** - * Log occurs in after filter - */ - $controllers->after(function (Request $request, Response $response) use ($app, $parseRoute) { - $account = $app['token']->get_account(); - $pathInfo = $request->getPathInfo(); - $route = $parseRoute($pathInfo, $response); - \API_V1_Log::create( - $app - , $account - , $request->getMethod() . " " . $pathInfo - , $response->getStatusCode() - , $response->headers->get('content-type') - , $route['ressource'] - , $route['general'] - , $route['aspect'] - , $route['action'] - ); + $controllers->after(function (Request $request, Response $response) use ($app) { + $this->logQuery($app, $request, $response); + $this->logout($app); }); - $controllers->after(function () use ($app) { - $app['authentication']->closeAccount(); - }); + $controllers->get('/monitor/scheduler/', 'controller.api.v1:get_scheduler') + ->before(array($this, 'ensureAdmin')); - /** - * Method Not Allowed Closure - */ - $bad_request_exception = function () { - throw new \API_V1_exception_badrequest(); - }; + $controllers->get('/monitor/tasks/', 'controller.api.v1:get_task_list') + ->before(array($this, 'ensureAdmin')); - /** - * Check wether the current user is Admin or not - */ - $mustBeAdmin = function (Request $request) use ($app) { - $user = $app['token']->get_account()->get_user(); - if (!$app['acl']->get($user)->is_admin()) { - throw new \API_V1_exception_unauthorized('You are not authorized'); - } - }; - - /** - * Get scheduler informations - * - * Route : /monitor/scheduler/ - * - * Method : GET - * - * Parameters : - * - */ - $controllers->get('/monitor/scheduler/', function (SilexApplication $app, Request $request) { - return $app['api']->get_scheduler($app)->get_response(); - })->before($mustBeAdmin); - - /** - * Get all tasks information - * - * Route : /monitor/tasks/ - * - * Method : GET - * - * Parameters : - * - */ - $controllers->get('/monitor/tasks/', function (SilexApplication $app, Request $request) { - return $app['api']->get_task_list($app)->get_response(); - })->before($mustBeAdmin); - - /** - * Get task informations - * - * Route : /monitor/task/{task}/ - * - * Method : GET - * - * Parameters : - * - */ - $controllers->get('/monitor/task/{task}/', function (SilexApplication $app, Request $request, $task) { - return $app['api']->get_task($app, $task)->get_response(); - }) + $controllers->get('/monitor/task/{task}/', 'controller.api.v1:get_task') ->convert('task', [$app['converter.task'], 'convert']) - ->before($mustBeAdmin)->assert('task', '\d+'); + ->before(array($this, 'ensureAdmin')) + ->assert('task', '\d+'); - /** - * Start task - * - * Route : /monitor/task/{task}/ - * - * Method : POST - * - * Parameters : - * - name (string) change the name of the task - * - autostart (boolean) start task when scheduler starts - */ - $controllers->post('/monitor/task/{task}/', function (SilexApplication $app, Request $request, $task) { - return $app['api']->set_task_property($app, $task)->get_response(); - }) + $controllers->post('/monitor/task/{task}/', 'controller.api.v1:set_task_property') ->convert('task', [$app['converter.task'], 'convert']) - ->before($mustBeAdmin)->assert('task', '\d+'); + ->before(array($this, 'ensureAdmin')) + ->assert('task', '\d+'); - /** - * Start task - * - * Route : /monitor/task/{task}/start/ - * - * Method : POST - * - * Parameters : - * - */ - $controllers->post('/monitor/task/{task}/start/', function (SilexApplication $app, Request $request, $task) { - return $app['api']->start_task($app, $task)->get_response(); - }) + $controllers->post('/monitor/task/{task}/start/', 'controller.api.v1:start_task') ->convert('task', [$app['converter.task'], 'convert']) - ->before($mustBeAdmin); + ->before(array($this, 'ensureAdmin')); - /** - * Stop task - * - * Route : /monitor/task/{task}/stop/ - * - * Method : POST - * - * Parameters : - * - */ - $controllers->post('/monitor/task/{task}/stop/', function (SilexApplication $app, Request $request, $task) { - return $app['api']->stop_task($app, $task)->get_response(); - }) + $controllers->post('/monitor/task/{task}/stop/', 'controller.api.v1:stop_task') ->convert('task', [$app['converter.task'], 'convert']) - ->before($mustBeAdmin); + ->before(array($this, 'ensureAdmin')); - /** - * Get some information about phraseanet - * - * Route : /monitor/phraseanet/ - * - * Method : GET - * - * Parameters : - * - */ - $controllers->get('/monitor/phraseanet/', function (SilexApplication $app, Request $request) { - return $app['api']->get_phraseanet_monitor($app)->get_response(); - })->before($mustBeAdmin); + $controllers->get('/monitor/phraseanet/', 'controller.api.v1:get_phraseanet_monitor') + ->before(array($this, 'ensureAdmin')); - /** - * Route : /databoxes/list/ - * - * Method : GET - * - * Parameters : - * - */ - $controllers->get('/databoxes/list/', function (SilexApplication $app, Request $request) { - return $app['api']->get_databoxes($request)->get_response(); - }); + $controllers->get('/databoxes/list/', 'controller.api.v1:get_databoxes'); - /** - * Route /databoxes/DATABOX_ID/collections/ - * - * Method : GET - * - * Parameters ; - * DATABOX_ID : required INT - */ - $controllers->get('/databoxes/{databox_id}/collections/', function (SilexApplication $app, $databox_id) { - return $app['api'] - ->get_databox_collections($app['request'], $databox_id) - ->get_response(); - })->assert('databox_id', '\d+'); + $controllers->get('/databoxes/{databox_id}/collections/', 'controller.api.v1:get_databox_collections') + ->assert('databox_id', '\d+'); - $controllers->get('/databoxes/{any_id}/collections/', $bad_request_exception); + $controllers->get('/databoxes/{any_id}/collections/', 'controller.api.v1:getBadRequest'); - /** - * Route /databoxes/DATABOX_ID/status/ - * - * Method : GET - * - * Parameters ; - * DATABOX_ID : required INT - * - */ - $controllers->get('/databoxes/{databox_id}/status/', function (SilexApplication $app, $databox_id) { - return $app['api'] - ->get_databox_status($app['request'], $databox_id) - ->get_response(); - })->assert('databox_id', '\d+'); + $controllers->get('/databoxes/{databox_id}/status/', 'controller.api.v1:get_databox_status') + ->assert('databox_id', '\d+'); - $controllers->get('/databoxes/{any_id}/status/', $bad_request_exception); + $controllers->get('/databoxes/{any_id}/status/', 'controller.api.v1:getBadRequest'); - /** - * Route /databoxes/DATABOX_ID/metadatas/ - * - * Method : GET - * - * Parameters ; - * DATABOX_ID : required INT - */ - $controllers->get('/databoxes/{databox_id}/metadatas/', function (SilexApplication $app, $databox_id) { - return $app['api'] - ->get_databox_metadatas($app['request'], $databox_id) - ->get_response(); - })->assert('databox_id', '\d+'); + $controllers->get('/databoxes/{databox_id}/metadatas/', 'controller.api.v1:get_databox_metadatas') + ->assert('databox_id', '\d+'); - $controllers->get('/databoxes/{any_id}/metadatas/', $bad_request_exception); + $controllers->get('/databoxes/{any_id}/metadatas/', 'controller.api.v1:getBadRequest'); - /** - * Route /databoxes/DATABOX_ID/termsOfUse/ - * - * Method : GET - * - * Parameters ; - * DATABOX_ID : required INT - */ - $controllers->get('/databoxes/{databox_id}/termsOfUse/', function (SilexApplication $app, $databox_id) { - return $app['api'] - ->get_databox_terms($app['request'], $databox_id) - ->get_response(); - })->assert('databox_id', '\d+'); + $controllers->get('/databoxes/{databox_id}/termsOfUse/', 'controller.api.v1:get_databox_terms') + ->assert('databox_id', '\d+'); - $controllers->get('/databoxes/{any_id}/termsOfUse/', $bad_request_exception); + $controllers->get('/databoxes/{any_id}/termsOfUse/', 'controller.api.v1:getBadRequest'); - $controllers->get('/quarantine/list/', function (SilexApplication $app, Request $request) { - return $app['api']->list_quarantine($app, $request)->get_response(); - }); + $controllers->get('/quarantine/list/', 'controller.api.v1:list_quarantine'); - $controllers->get('/quarantine/item/{lazaret_id}/', function ($lazaret_id, SilexApplication $app, Request $request) { - return $app['api']->list_quarantine_item($lazaret_id, $app, $request)->get_response(); - }); + $controllers->get('/quarantine/item/{lazaret_id}/', 'controller.api.v1:list_quarantine_item'); - /** - * Route : /records/add/ - * - * Method : POST - * - * Parameters : - * - */ - $controllers->post('/records/add/', function (SilexApplication $app, Request $request) { - return $app['api']->add_record($app, $request)->get_response(); - }); + $controllers->post('/records/add/', 'controller.api.v1:add_record'); - /** - * Route : /search/ - * - * Method : GET or POST - * - * Parameters : - * bases[] : array - * status[] : array - * fields[] : array - * record_type : boolean - * media_type : string - * - * Response : - * Array containing an array of records and stories collection - * - */ - $controllers->match('/search/', function () use ($app) { - return $app['api']->search($app['request'])->get_response(); - }); + $controllers->match('/search/', 'controller.api.v1:search'); - /** - * Route : /records/search/ - * - * Method : GET or POST - * - * Parameters : - * bases[] : array - * status[] : array - * fields[] : array - * record_type : boolean - * media_type : string - * - * Response : - * Array of record objects - * - */ - $controllers->match('/records/search/', function (SilexApplication $app) { - return $app['api']->search_records($app['request'])->get_response(); - }); + $controllers->match('/records/search/', 'controller.api.v1:search_records'); - $controllers->get('/records/{databox_id}/{record_id}/caption/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->caption_records($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->get('/records/{databox_id}/{record_id}/caption/', 'controller.api.v1:caption_records') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->get('/records/{any_id}/{anyother_id}/caption/', $bad_request_exception); + $controllers->get('/records/{any_id}/{anyother_id}/caption/', 'controller.api.v1:getBadRequest'); - /** - * Route : /records/DATABOX_ID/RECORD_ID/metadatas/ - * - * Method : GET - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->get('/records/{databox_id}/{record_id}/metadatas/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->get_record_metadatas($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->get('/records/{databox_id}/{record_id}/metadatas/', 'controller.api.v1:get_record_metadatas') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->get('/records/{any_id}/{anyother_id}/metadatas/', $bad_request_exception); + $controllers->get('/records/{any_id}/{anyother_id}/metadatas/', 'controller.api.v1:getBadRequest'); - /** - * Route : /records/DATABOX_ID/RECORD_ID/status/ - * - * Method : GET - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->get('/records/{databox_id}/{record_id}/status/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->get_record_status($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->get('/records/{databox_id}/{record_id}/status/', 'controller.api.v1:get_record_status') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->get('/records/{any_id}/{anyother_id}/status/', $bad_request_exception); + $controllers->get('/records/{any_id}/{anyother_id}/status/', 'controller.api.v1:getBadRequest'); - /** - * Route : /records/DATABOX_ID/RECORD_ID/related/ - * - * Method : GET - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->get('/records/{databox_id}/{record_id}/related/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->get_record_related($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->get('/records/{databox_id}/{record_id}/related/', 'controller.api.v1:get_record_related') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->get('/records/{any_id}/{anyother_id}/related/', $bad_request_exception); + $controllers->get('/records/{any_id}/{anyother_id}/related/', 'controller.api.v1:getBadRequest'); - /** - * Route : /records/DATABOX_ID/RECORD_ID/embed/ - * - * Method : GET - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->get('/records/{databox_id}/{record_id}/embed/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->get_record_embed($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->get('/records/{databox_id}/{record_id}/embed/', 'controller.api.v1:get_record_embed') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->get('/records/{any_id}/{anyother_id}/embed/', $bad_request_exception); + $controllers->get('/records/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequest'); - /** - * Route : /records/DATABOX_ID/RECORD_ID/setmetadatas/ - * - * Method : POST - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->post('/records/{databox_id}/{record_id}/setmetadatas/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->set_record_metadatas($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->post('/records/{databox_id}/{record_id}/setmetadatas/', 'controller.api.v1:set_record_metadatas') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->post('/records/{any_id}/{anyother_id}/setmetadatas/', $bad_request_exception); + $controllers->post('/records/{any_id}/{anyother_id}/setmetadatas/', 'controller.api.v1:getBadRequest'); - /** - * Route : /records/DATABOX_ID/RECORD_ID/setstatus/ - * - * Method : POST - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->post('/records/{databox_id}/{record_id}/setstatus/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->set_record_status($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->post('/records/{databox_id}/{record_id}/setstatus/', 'controller.api.v1:set_record_status') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->post('/records/{any_id}/{anyother_id}/setstatus/', $bad_request_exception); + $controllers->post('/records/{any_id}/{anyother_id}/setstatus/', 'controller.api.v1:getBadRequest'); - /** - * Route : /records/DATABOX_ID/RECORD_ID/setcollection/ - * - * Method : POST - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->post('/records/{databox_id}/{record_id}/setcollection/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->set_record_collection($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->post('/records/{databox_id}/{record_id}/setcollection/', 'controller.api.v1:set_record_collection') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->post('/records/{wrong_databox_id}/{wrong_record_id}/setcollection/', $bad_request_exception); + $controllers->post('/records/{wrong_databox_id}/{wrong_record_id}/setcollection/', 'controller.api.v1:getBadRequest'); - $controllers->get('/records/{databox_id}/{record_id}/', function (SilexApplication $app, $databox_id, $record_id) { - return $app['api'] - ->get_record($app['request'], $databox_id, $record_id) - ->get_response(); - })->assert('databox_id', '\d+')->assert('record_id', '\d+'); + $controllers->get('/records/{databox_id}/{record_id}/', 'controller.api.v1:get_record') + ->assert('databox_id', '\d+')->assert('record_id', '\d+'); - $controllers->get('/records/{any_id}/{anyother_id}/', $bad_request_exception); + $controllers->get('/records/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequest'); - /** - * Route : /baskets/list/ - * - * Method : POST - * - * Parameters : - * - */ - $controllers->get('/baskets/list/', function (SilexApplication $app) { - return $app['api']->search_baskets($app['request'])->get_response(); - }); + $controllers->get('/baskets/list/', 'controller.api.v1:search_baskets'); - /** - * Route : /baskets/add/ - * - * Method : POST - * - * Parameters : - * - */ - $controllers->post('/baskets/add/', function (SilexApplication $app) { - return $app['api']->create_basket($app['request'])->get_response(); - }); + $controllers->post('/baskets/add/', 'controller.api.v1:create_basket'); - /** - * Route : /baskets/BASKET_ID/content/ - * - * Method : GET - * - * Parameters : - * BASKET_ID : required INT - * - */ - $controllers->get('/baskets/{basket}/content/', function (SilexApplication $app, Basket $basket) { - return $app['api']->get_basket($app['request'], $basket)->get_response(); - }) + $controllers->get('/baskets/{basket}/content/', 'controller.api.v1:get_basket') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-access']) ->assert('basket', '\d+'); - $controllers->get('/baskets/{wrong_basket}/content/', $bad_request_exception); + $controllers->get('/baskets/{wrong_basket}/content/', 'controller.api.v1:getBadRequest'); - /** - * Route : /baskets/BASKET_ID/settitle/ - * - * Method : GET - * - * Parameters : - * BASKET_ID : required INT - * - */ - $controllers->post('/baskets/{basket}/setname/', function (SilexApplication $app, Basket $basket) { - return $app['api'] - ->set_basket_title($app['request'], $basket) - ->get_response(); - }) + $controllers->post('/baskets/{basket}/setname/', 'controller.api.v1:set_basket_title') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) ->assert('basket', '\d+'); - $controllers->post('/baskets/{wrong_basket}/setname/', $bad_request_exception); + $controllers->post('/baskets/{wrong_basket}/setname/', 'controller.api.v1:getBadRequest'); - /** - * Route : /baskets/BASKET_ID/setdescription/ - * - * Method : POST - * - * Parameters : - * BASKET_ID : required INT - * - */ - $controllers->post('/baskets/{basket}/setdescription/', function (SilexApplication $app, Basket $basket) { - return $app['api'] - ->set_basket_description($app['request'], $basket) - ->get_response(); - }) + $controllers->post('/baskets/{basket}/setdescription/', 'controller.api.v1:set_basket_description') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) ->assert('basket', '\d+'); - $controllers->post('/baskets/{wrong_basket}/setdescription/', $bad_request_exception); + $controllers->post('/baskets/{wrong_basket}/setdescription/', 'controller.api.v1:getBadRequest'); - /** - * Route : /baskets/BASKET_ID/delete/ - * - * Method : POST - * - * Parameters : - * BASKET_ID : required INT - * - */ - $controllers->post('/baskets/{basket}/delete/', function (SilexApplication $app, Basket $basket) { - return $app['api']->delete_basket($app['request'], $basket)->get_response(); - }) + $controllers->post('/baskets/{basket}/delete/', 'controller.api.v1:delete_basket') ->before($app['middleware.basket.converter']) ->before($app['middleware.basket.user-is-owner']) ->assert('basket', '\d+'); - $controllers->post('/baskets/{wrong_basket}/delete/', $bad_request_exception); + $controllers->post('/baskets/{wrong_basket}/delete/', 'controller.api.v1:getBadRequest'); - /** - * Route : /feeds/list/ - * - * Method : POST - * - * Parameters : - * - */ - $controllers->get('/feeds/list/', function (SilexApplication $app) { - return $app['api'] - ->search_publications($app['request'], $app['authentication']->getUser()) - ->get_response(); - }); + $controllers->get('/feeds/list/', 'controller.api.v1:search_publications'); - $controllers->get('/feeds/content/', function (SilexApplication $app) { - return $app['api'] - ->get_publications($app['request'], $app['authentication']->getUser()) - ->get_response(); - }); + $controllers->get('/feeds/content/', 'controller.api.v1:get_publications'); - $controllers->get('/feeds/entry/{entry_id}/', function (SilexApplication $app, $entry_id) { - return $app['api'] - ->get_feed_entry($app['request'], $entry_id, $app['authentication']->getUser()) - ->get_response(); - })->assert('entry_id', '\d+'); + $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:get_feed_entry') + ->assert('entry_id', '\d+'); - $controllers->get('/feeds/entry/{entry_id}/', $bad_request_exception); + $controllers->get('/feeds/entry/{entry_id}/', 'controller.api.v1:getBadRequest'); - /** - * Route : /feeds/PUBLICATION_ID/content/ - * - * Method : GET - * - * Parameters : - * PUBLICATION_ID : required INT - * - */ - $controllers->get('/feeds/{feed_id}/content/', function (SilexApplication $app, $feed_id) { - return $app['api'] - ->get_publication($app['request'], $feed_id, $app['authentication']->getUser()) - ->get_response(); - })->assert('feed_id', '\d+'); + $controllers->get('/feeds/{feed_id}/content/', 'controller.api.v1:get_publication') + ->assert('feed_id', '\d+'); - $controllers->get('/feeds/{wrong_feed_id}/content/', $bad_request_exception); + $controllers->get('/feeds/{wrong_feed_id}/content/', 'controller.api.v1:getBadRequest'); - /** - * Route : /stories/DATABOX_ID/RECORD_ID/embed/ - * - * Method : GET - * - * Parameters : - * DATABOX_ID : required INT - * RECORD_ID : required INT - * - */ - $controllers->get('/stories/{databox_id}/{story_id}/embed/', function ($databox_id, $story_id) use ($app) { - $result = $app['api']->get_story_embed($app['request'], $databox_id, $story_id); + $controllers->get('/stories/{databox_id}/{story_id}/embed/', 'controller.api.v1:get_story_embed') + ->assert('databox_id', '\d+')->assert('story_id', '\d+'); - return $result->get_response(); - } - )->assert('databox_id', '\d+')->assert('story_id', '\d+'); + $controllers->get('/stories/{any_id}/{anyother_id}/embed/', 'controller.api.v1:getBadRequest'); - $controllers->get('/stories/{any_id}/{anyother_id}/embed/', $bad_request_exception); + $controllers->get('/stories/{databox_id}/{story_id}/', 'controller.api.v1:get_story') + ->assert('databox_id', '\d+')->assert('story_id', '\d+'); - $controllers->get('/stories/{databox_id}/{story_id}/', function ($databox_id, $story_id) use ($app) { - $result = $app['api']->get_story($app['request'], $databox_id, $story_id); + $controllers->get('/stories/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequest'); - return $result->get_response(); - })->assert('databox_id', '\d+')->assert('story_id', '\d+'); + $controllers->get('/stories/{databox_id}/{story_id}/', 'controller.api.v1:get_story') + ->assert('databox_id', '\d+')->assert('story_id', '\d+'); - $controllers->get('/stories/{any_id}/{anyother_id}/', $bad_request_exception); - - $controllers->get('/stories/{databox_id}/{story_id}/', function ($databox_id, $story_id) use ($app) { - $result = $app['api']->get_story($app['request'], $databox_id, $story_id); - - return $result->get_response(); - })->assert('databox_id', '\d+')->assert('story_id', '\d+'); - $controllers->get('/stories/{any_id}/{anyother_id}/', $bad_request_exception); + $controllers->get('/stories/{any_id}/{anyother_id}/', 'controller.api.v1:getBadRequest'); 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['manipulator.task']->getRepository()->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(), + 'status' => $task->getStatus(), + ]; + } + + /** + * 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['EM']->getConfiguration()->getMetadataCacheImpl(), + 'doctrine_query' => $app['EM']->getConfiguration()->getQueryCacheImpl(), + 'doctrine_result' => $app['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']), + ], + 'filesystem' => [ + 'noWeb' => $app['conf']->get(['main', 'storage', 'subdefs', 'default-dir']), + ], + '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)->get_statusbits())]; + + 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['EM']->persist($session); + $app['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 = BorderManager::FORCE_RECORD; + break; + case '1' : + $behavior = BorderManager::FORCE_LAZARET; + break; + case null: + $behavior = null; + break; + default: + return $this->getBadRequest($app, $request, sprintf('Invalid forceBehavior value `%s`', $request->get('forceBehavior'))); + } + + $app['border-manager']->process($session, $Package, $callback, $behavior); + + $ret = [ + 'entity' => null, + ]; + + if ($output instanceof \record_adapter) { + $ret['entity'] = '0'; + $ret['url'] = '/records/' . $output->get_sbas_id() . '/' . $output->get_record_id() . '/'; + $app['phraseanet.SE']->addRecord($output); + } + if ($output instanceof LazaretFile) { + $ret['entity'] = '1'; + $ret['url'] = '/quarantine/item/' . $output->getId() . '/'; + } + + 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['EM']->getRepository('Phraseanet:LazaretFile'); + $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['EM']->find('Phraseanet:LazaretFile', $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) + { + $checks = array_map(function ($checker) use ($app) { + return $checker->getMessage($app['translator']); + }, iterator_to_array($file->getChecks())); + + $usr_id = null; + if ($file->getSession()->getUser()) { + $usr_id = $file->getSession()->getUser()->getId(); + } + + $session = [ + 'id' => $file->getSession()->getId(), + 'usr_id' => $usr_id, + ]; + + 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 $record) { + 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 $record) { + $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); + + $userQuery = new UserQuery(); + $userQuery->setUser($app['authentication']->getUser()); + $userQuery->setQuery($query); + + $app['EM']->persist($userQuery); + $app['EM']->flush(); + + 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' => $search_result->getError(), + 'warning' => $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['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($app['phraseanet.appbox']->get_databox($databox_id), $record->get_status())]; + + 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) { + if (null !== $embed = $this->list_embedable_media($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, $story_id) + { + $record = $app['phraseanet.appbox'] + ->get_databox($databox_id) + ->get_record($story_id); + + $devices = $request->get('devices', []); + $mimes = $request->get('mimes', []); + + $ret = array_filter(array_map(function ($media) { + if (null !== $embed = $this->list_embedable_media($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); + $status_bits = $databox->get_statusbits(); + + $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 (!isset($status_bits[$n])) { + return $this->getBadRequest($app, $request); + } + + $datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 2)); + } + + $record->set_binary_status(strrev($datas)); + $app['phraseanet.SE']->updateRecord($record); + + $ret = ["status" => $this->list_record_status($databox, $record->get_status())]; + + 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 $story_id + * @return Response + */ + public function get_story(Application $app, Request $request, $databox_id, $story_id) + { + try { + $story = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($story_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['EM']->getRepository('Phraseanet:Basket'); + /* @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['EM']->persist($Basket); + $app['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['EM']->remove($basket); + $app['EM']->flush(); + + return $this->search_baskets($app, $request); + } + + /** + * 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(); + } + + /** + * 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(), + ], + '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['EM']->persist($basket); + $app['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['EM']->persist($basket); + $app['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['EM']->getRepository('Phraseanet:Feed')->getAllForUser($app['acl']->get($user)); + + $datas = array_map(function ($feed) use ($user) { + return $this->list_publication($feed, $user); + }, $coll); + + return Result::create($request, ["feeds" => $datas])->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['EM']->getRepository('Phraseanet:Feed')->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 <= 20)) ? $per_page : 5; + + $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(); + $feed = Aggregate::createFromUser($app, $user); + + $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 : 5; + + $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['EM']->getRepository('Phraseanet:FeedEntry')->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_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(\media_subdef $media) + { + if (!$media->is_physically_present()) { + 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(), + ]; + } + + /** + * Retrieve detailled information about one permalink + * + * @param media_Permalink_Adapter $permalink + * + * @return type + */ + private function list_permalink(\media_Permalink_Adapter $permalink) + { + 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' => $permalink->get_url() . '&download', + 'url' => $permalink->get_url() + ]; + } + + /** + * Retrieve detailled information about one status + * + * @param \databox $databox + * @param string $status + * @return array + */ + private function list_record_status(\databox $databox, $status) + { + $status = strrev($status); + + $ret = []; + foreach ($databox->get_statusbits() as $bit => $status_datas) { + $ret[] = ['bit' => $bit, 'state' => !!substr($status, ($bit - 1), 1)]; + } + + 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(), + 'created_on' => $basket->getCreated()->format(DATE_ATOM), + 'description' => (string) $basket->getDescription(), + 'name' => $basket->getName(), + 'pusher_usr_id' => $basket->getPusher() ? $basket->getPusher()->getId() : 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(), + ]; + }, 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()), + ], $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($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($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(array $status) + { + $ret = []; + foreach ($status as $n => $datas) { + $ret[] = [ + 'bit' => $n, + 'label_on' => $datas['labelon'], + 'label_off' => $datas['labeloff'], + 'labels' => [ + 'en' => $datas['labels_on_i18n']['en'], + 'fr' => $datas['labels_on_i18n']['fr'], + 'de' => $datas['labels_on_i18n']['de'], + 'nl' => $datas['labels_on_i18n']['nl'], + ], + 'img_on' => $datas['img_on'], + 'img_off' => $datas['img_off'], + 'searchable' => !!$datas['searchable'], + 'printable' => !!$datas['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)); + } + + /** + * Retirve 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()); + + $oauth2_adapter = new \API_OAuth2_Adapter($app); + $oauth2_adapter->verifyAccessToken(); + + $token = \API_OAuth2_Token::load_by_oauth_token($app, $oauth2_adapter->getToken()); + $app['session']->set('token', $token); + + $oAuth2App = $token->get_account()->get_application(); + /* @var $oAuth2App \API_OAuth2_Application */ + + if ($oAuth2App->get_client_id() == \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->get_client_id() == \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(); + } + + $user = $app['manipulator.user']->getRepository()->find($oauth2_adapter->get_usr_id()); + $app['authentication']->openAccount($user); + $oauth2_adapter->remember_this_ses_id($app['session']->get('session_id')); + $app['dispatcher']->dispatch(PhraseaEvents::API_OAUTH2_END, new ApiOAuth2EndEvent()); + } + + public function ensureAdmin(Request $request, Application $app) + { + $user = $app['session']->get('token')->get_account()->get_user(); + if (!$app['acl']->get($user)->is_admin()) { + return Result::createError($request, 401, 'You are not authorized')->createResponse(); + } + } + + private function logQuery(Application $app, Request $request, Response $response) + { + $infos = $this->parseRoute($request->getPathInfo(), $response); + + Logger::create( + $app, + $app['session']->get('token')->get_account(), + $request->getMethod() . " " . $request->getPathInfo(), + $response->getStatusCode(), + $response->headers->get('content-type'), + $infos['ressource'], + $infos['general'], + $infos['aspect'], + $infos['action'] + ); + } + + /** + * Parses the requested route to fetch + * - the ressource (databox, basket, record etc ..) + * - general action (list, add, search) + * - the action (setstatus, setname etc..) + * - the aspect (collections, related, content etc..) + * + * @return array + */ + private function parseRoute($route, Response $response) + { + $ressource = $general = $aspect = $action = null; + $exploded_route = explode('/', trim($route, '/')); + + if ($response->isOk() && sizeof($exploded_route) > 0) { + $ressource = $exploded_route[0]; + + if (count($exploded_route) == 2 && (int) $exploded_route[1] == 0) { + $general = $exploded_route[1]; + } else { + switch ($ressource) { + case Logger::DATABOXES_RESOURCE : + if ((int) $exploded_route[1] > 0 && count($exploded_route) == 3) { + $aspect = $exploded_route[2]; + } + break; + case Logger::RECORDS_RESOURCE : + if ((int) $exploded_route[1] > 0 && count($exploded_route) == 4) { + if (!isset($exploded_route[3])) { + $aspect = "record"; + } elseif (preg_match("/^set/", $exploded_route[3])) { + $action = $exploded_route[3]; + } else { + $aspect = $exploded_route[3]; + } + } + break; + case Logger::BASKETS_RESOURCE : + if ((int) $exploded_route[1] > 0 && count($exploded_route) == 3) { + if (preg_match("/^set/", $exploded_route[2]) || preg_match("/^delete/", $exploded_route[2])) { + $action = $exploded_route[2]; + } else { + $aspect = $exploded_route[2]; + } + } + break; + case Logger::FEEDS_RESOURCE : + if ((int) $exploded_route[1] > 0 && count($exploded_route) == 3) { + $aspect = $exploded_route[2]; + } + break; + } + } + } + + return [ + 'ressource' => $ressource, + 'general' => $general, + 'aspect' => $aspect, + 'action' => $action + ]; + } + + private function logout(Application $app) + { + if (null !== $app['authentication']->getUser()) { + $app['authentication']->closeAccount(); + } + } } diff --git a/lib/Alchemy/Phrasea/Core/Event/ApiLoadEndEvent.php b/lib/Alchemy/Phrasea/Core/Event/ApiLoadEndEvent.php deleted file mode 100644 index f9a93ab7d4..0000000000 --- a/lib/Alchemy/Phrasea/Core/Event/ApiLoadEndEvent.php +++ /dev/null @@ -1,23 +0,0 @@ -request = $request; + $this->response = $response; + } + + /** + * @return Request + */ + public function getRequest() + { + return $this->request; + } + + /** + * @return Response + */ + public function getResponse() + { + return $this->response; + } + + /** + * @return string + */ public function getName() { return PhraseaEvents::API_RESULT; diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php index eeeb7b86be..e970991257 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber; use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Controller\Api\Result; use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\EventDispatcher\EventSubscriberInterface; @@ -43,43 +44,32 @@ class ApiExceptionHandlerSubscriber implements EventSubscriberInterface $headers = []; $e = $event->getException(); - if ($e instanceof \API_V1_exception_methodnotallowed) { - $code = \API_V1_result::ERROR_METHODNOTALLOWED; - } elseif ($e instanceof MethodNotAllowedHttpException) { - $code = \API_V1_result::ERROR_METHODNOTALLOWED; + if ($e instanceof MethodNotAllowedHttpException) { + $code = 405; } elseif ($e instanceof BadRequestHttpException) { - $code = \API_V1_result::ERROR_BAD_REQUEST; - } elseif ($e instanceof \API_V1_exception_badrequest) { - $code = \API_V1_result::ERROR_BAD_REQUEST; - } elseif ($e instanceof \API_V1_exception_forbidden) { - $code = \API_V1_result::ERROR_FORBIDDEN; - } elseif ($e instanceof \API_V1_exception_unauthorized) { - $code = \API_V1_result::ERROR_UNAUTHORIZED; - } elseif ($e instanceof \API_V1_exception_internalservererror) { - $code = \API_V1_result::ERROR_INTERNALSERVERERROR; + $code = 400; } elseif ($e instanceof AccessDeniedHttpException) { - $code = \API_V1_result::ERROR_FORBIDDEN; + $code = 403; } elseif ($e instanceof UnauthorizedHttpException) { - $code = \API_V1_result::ERROR_UNAUTHORIZED; + $code = 401; } elseif ($e instanceof NotFoundHttpException) { - $code = \API_V1_result::ERROR_NOTFOUND; + $code = 404; } elseif ($e instanceof HttpExceptionInterface) { if (503 === $e->getStatusCode()) { - $code = \API_V1_result::ERROR_MAINTENANCE; + $code = 503; } else { - $code = \API_V1_result::ERROR_INTERNALSERVERERROR; + $code = 500; } } else { - $code = \API_V1_result::ERROR_INTERNALSERVERERROR; + $code = 500; } if ($e instanceof HttpExceptionInterface) { $headers = $e->getHeaders(); } - $result = $this->app['api']->get_error_message($event->getRequest(), $code, $e->getMessage()); - $response = $result->get_response(); - $response->headers->set('X-Status-Code', $result->get_http_code()); + $response = Result::createError($event->getRequest(), $code, $e->getMessage())->createResponse(); + $response->headers->set('X-Status-Code', $response->getStatusCode()); foreach ($headers as $key => $value) { $response->headers->set($key, $value); diff --git a/lib/classes/API/OAuth2/Token.php b/lib/classes/API/OAuth2/Token.php index 2a8c3b7d87..234e2bb00e 100644 --- a/lib/classes/API/OAuth2/Token.php +++ b/lib/classes/API/OAuth2/Token.php @@ -276,12 +276,11 @@ class API_OAuth2_Token $row = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); - if ( ! $row) + if (!$row) { throw new NotFoundHttpException('Account not found'); + } - $account = new API_OAuth2_Account($app, $row['api_account_id']); - - return new self($app['phraseanet.appbox'], $account); + return new self($app['phraseanet.appbox'], new API_OAuth2_Account($app, $row['api_account_id'])); } /** diff --git a/lib/classes/API/V1/Abstract.php b/lib/classes/API/V1/Abstract.php deleted file mode 100644 index 2115d10777..0000000000 --- a/lib/classes/API/V1/Abstract.php +++ /dev/null @@ -1,15 +0,0 @@ -starting = microtime(true); - } - - public function register(Application $app) - { - $app['api.timers'] = new ArrayCollection(); - $app['api.timers.start'] = $this->starting; - - $callback = function (Event $event) use ($app) { - $name = $event->getName(); - $n = 1; - while (isset($app['api.timers']->{$name})) { - $n++; - $name = $event->getName() . '#' . $n; - } - $app['api.timers']->add([ - 'name' => $name, - 'memory' => memory_get_usage(), - 'time' => microtime(true) - $app['api.timers.start'], - ]); - }; - - $app['dispatcher']->addListener(KernelEvents::CONTROLLER, $callback, -999999); - $app['dispatcher']->addListener(KernelEvents::REQUEST, $callback, 999999); - $app['dispatcher']->addListener(KernelEvents::REQUEST, $callback, -999999); - $app['dispatcher']->addListener(KernelEvents::RESPONSE, $callback, -999999); - $app['dispatcher']->addListener(KernelEvents::EXCEPTION, $callback, 999999); - $app['dispatcher']->addListener(PhraseaEvents::API_OAUTH2_START, $callback); - $app['dispatcher']->addListener(PhraseaEvents::API_OAUTH2_END, $callback); - $app['dispatcher']->addListener(PhraseaEvents::API_LOAD_END, $callback); - $app['dispatcher']->addListener(PhraseaEvents::API_RESULT, $callback); - } - - public function boot(Application $app) - { - } -} diff --git a/lib/classes/API/V1/adapter.php b/lib/classes/API/V1/adapter.php deleted file mode 100644 index f6d7f8560c..0000000000 --- a/lib/classes/API/V1/adapter.php +++ /dev/null @@ -1,2092 +0,0 @@ -app = $app; - - return $this; - } - - /** - * Retrieve http status error code according to the message - * - * @param Request $request - * @param string $error - * @param string $message - * - * @return API_V1_result ` - */ - public function get_error_message(Request $request, $error, $message) - { - $result = new API_V1_result($this->app, $request, $this); - $result->set_error_message($error, $message); - - return $result; - } - - /** - * Retrieve http status error message according to the http status error code - * @param Request $request - * @param int $code - * @return API_V1_result - */ - public function get_error_code(Request $request, $code) - { - $result = new API_V1_result($this->app, $request, $this); - $result->set_error_code($code); - - return $result; - } - - /** - * Get the current version - * - * @return string - */ - public function get_version() - { - return $this->version; - } - - /** - * Return an array of key-values informations about scheduler - * - * @param Application $app The silex application - * @return \API_V1_result - */ - public function get_scheduler(Application $app) - { - $result = new \API_V1_result($app, $app['request'], $this); - $date = new \DateTime(); - $data = $app['task-manager.live-information']->getManager(); - - $result->set_datas(['scheduler' => [ - 'configuration' => $data['configuration'], - 'state' => $data['actual'], - 'status' => $data['actual'], - 'pid' => $data['process-id'], - 'process-id' => $data['process-id'], - 'updated_on' => $date->format(DATE_ATOM), - ]]); - - return $result; - } - - /** - * Get a list of phraseanet tasks - * - * @param Application $app The API silex application - * - * @return \API_V1_result - */ - public function get_task_list(Application $app) - { - $result = new \API_V1_result($app, $app['request'], $this); - - $ret = []; - foreach ($app['manipulator.task']->getRepository()->findAll() as $task) { - $ret[] = $this->list_task($app, $task); - } - - $result->set_datas(['tasks' => $ret]); - - return $result; - } - - protected 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(), - 'status' => $task->getStatus(), - ]; - } - - /** - * Get informations about an identified task - * - * @param \Silex\Application $app The API silex application - * @param Task $task - * @return \API_V1_result - */ - public function get_task(Application $app, Task $task) - { - $result = new \API_V1_result($app, $app['request'], $this); - $ret = ['task' => $this->list_task($app, $task)]; - $result->set_datas($ret); - - return $result; - } - - /** - * Start a specified task - * - * @param \Silex\Application $app The API silex application - * @param Task $task The task to start - * @return \API_V1_result - */ - public function start_task(Application $app, Task $task) - { - $result = new \API_V1_result($app, $app['request'], $this); - - $app['manipulator.task']->start($task); - $result->set_datas(['task' => $this->list_task($app, $task)]); - - return $result; - } - - /** - * Stop a specified task - * - * @param \Silex\Application $app The API silex application - * @param Task $task The task to stop - * @return \API_V1_result - */ - public function stop_task(Application $app, Task $task) - { - $result = new API_V1_result($app, $app['request'], $this); - - $app['manipulator.task']->stop($task); - $result->set_datas(['task' => $this->list_task($app, $task)]); - - return $result; - } - - /** - * Update a task property - * - name - * - autostart - * - * @param \Silex\Application $app Silex application - * @param Task $task The task - * @return \API_V1_result - * @throws \API_V1_exception_badrequest - */ - public function set_task_property(Application $app, $task) - { - $result = new API_V1_result($app, $app['request'], $this); - - $title = $app['request']->get('title'); - $autostart = $app['request']->get('autostart'); - - if (null === $title && null === $autostart) { - throw new \API_V1_exception_badrequest(); - } - - if ($title) { - $task->setName($title); - } - if ($autostart) { - $task->setStatus(Task::STATUS_STARTED); - } - - $result->set_datas(['task' => $this->list_task($app, $task)]); - - return $result; - } - - /** - * Get Information the cache system used by the instance - * - * @param \Silex\Application $app the silex application - * @return array - */ - protected function get_cache_info(Application $app) - { - $caches = [ - 'main' => $app['cache'], - 'op_code' => $app['opcode-cache'], - 'doctrine_metadatas' => $this->app['EM']->getConfiguration()->getMetadataCacheImpl(), - 'doctrine_query' => $this->app['EM']->getConfiguration()->getQueryCacheImpl(), - 'doctrine_result' => $this->app['EM']->getConfiguration()->getResultCacheImpl(), - ]; - - $ret = []; - - foreach ($caches as $name => $service) { - if ($service instanceof \Alchemy\Phrasea\Cache\Cache) { - $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 - */ - protected 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 - */ - protected 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']), - ], - 'filesystem' => [ - 'noWeb' => $app['conf']->get(['main', 'storage', 'subdefs', 'default-dir']), - ], - '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 \API_V1_result - */ - public function get_phraseanet_monitor(Application $app) - { - $result = new API_V1_result($app, $app['request'], $this); - - $ret = array_merge( - $this->get_config_info($app), $this->get_cache_info($app), $this->get_gv_info($app) - ); - - $result->set_datas($ret); - - return $result; - } - - /** - * Get an API_V1_result containing the databoxes - * - * @param Request $request - * - * @return API_V1_result - */ - public function get_databoxes(Request $request) - { - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas(["databoxes" => $this->list_databoxes()]); - - return $result; - } - - /** - * Get an API_V1_result containing the collections of a databox - * - * @param Request $request - * @param int $databox_id - * - * @return API_V1_result - */ - public function get_databox_collections(Request $request, $databox_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas( - [ - "collections" => $this->list_databox_collections( - $this->app['phraseanet.appbox']->get_databox($databox_id) - ) - ] - ); - - return $result; - } - - /** - * Get an API_V1_result containing the status of a databox - * - * @param Request $request - * @param int $databox_id - * - * @return API_V1_result - */ - public function get_databox_status(Request $request, $databox_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas( - [ - "status" => - $this->list_databox_status( - $this->app['phraseanet.appbox']->get_databox($databox_id)->get_statusbits() - ) - ] - ); - - return $result; - } - - /** - * Get an API_V1_result containing the metadatas of a databox - * - * @param Request $request - * @param int $databox_id - * - * @return API_V1_result - */ - public function get_databox_metadatas(Request $request, $databox_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas( - [ - "document_metadatas" => - $this->list_databox_metadatas_fields( - $this->app['phraseanet.appbox']->get_databox($databox_id) - ->get_meta_structure() - ) - ] - ); - - return $result; - } - - /** - * Get an API_V1_result containing the terms of use of a databox - * - * @param Request $request - * @param int $databox_id - * - * @return API_V1_result - */ - public function get_databox_terms(Request $request, $databox_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas( - [ - "termsOfUse" => - $this->list_databox_terms($this->app['phraseanet.appbox']->get_databox($databox_id)) - ] - ); - - return $result; - } - - public function caption_records(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - $fields = $record->get_caption()->get_fields(); - - $ret = ['caption_metadatas' => []]; - - foreach ($fields as $field) { - $ret['caption_metadatas'][] = [ - 'meta_structure_id' => $field->get_meta_struct_id(), - 'name' => $field->get_name(), - 'value' => $field->get_serialized_values(";"), - ]; - } - - $result->set_datas($ret); - - return $result; - } - - public function add_record(Application $app, Request $request) - { - 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('base_id')) { - throw new API_V1_exception_badrequest('Missing base_id parameter'); - } - - $collection = \collection::get_from_base_id($this->app, $request->get('base_id')); - - if (!$app['acl']->get($app['authentication']->getUser())->has_right_on_base($request->get('base_id'), 'canaddrecord')) { - throw new API_V1_exception_forbidden(sprintf('You do not have access to collection %s', $collection->get_label($this->app['locale']))); - } - - $media = $app['mediavorus']->guess($file->getPathname()); - - $Package = new File($this->app, $media, $collection, $file->getClientOriginalName()); - - if ($request->get('status')) { - $Package->addAttribute(new Status($app, $request->get('status'))); - } - - $session = new Alchemy\Phrasea\Model\Entities\LazaretSession(); - $session->setUser($app['authentication']->getUser()); - - $app['EM']->persist($session); - $app['EM']->flush(); - - $reasons = $output = null; - - $callback = function ($element, $visa, $code) use ($app, &$reasons, &$output) { - if (!$visa->isValid()) { - $reasons = []; - - foreach ($visa->getResponses() as $response) { - $reasons[] = $response->getMessage($app['translator']); - } - } - - $output = $element; - }; - - switch ($request->get('forceBehavior')) { - case '0' : - $behavior = BorderManager::FORCE_RECORD; - break; - case '1' : - $behavior = BorderManager::FORCE_LAZARET; - break; - case null: - $behavior = null; - break; - default: - throw new API_V1_exception_badrequest(sprintf('Invalid forceBehavior value `%s`', $request->get('forceBehavior'))); - break; - } - - $app['border-manager']->process($session, $Package, $callback, $behavior); - - $ret = [ - 'entity' => null, - ]; - - if ($output instanceof \record_adapter) { - $ret['entity'] = '0'; - $ret['url'] = '/records/' . $output->get_sbas_id() . '/' . $output->get_record_id() . '/'; - $app['phraseanet.SE']->addRecord($output); - } - if ($output instanceof LazaretFile) { - $ret['entity'] = '1'; - $ret['url'] = '/quarantine/item/' . $output->getId() . '/'; - } - - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas($ret); - - return $result; - } - - 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['EM']->getRepository('Phraseanet:LazaretFile'); - - $lazaretFiles = $lazaretRepository->findPerPage( - $baseIds, $offset_start, $per_page - ); - } - - $ret = []; - - foreach ($lazaretFiles as $lazaretFile) { - $ret[] = $this->list_lazaret_file($lazaretFile); - } - - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas([ - 'offset_start' => $offset_start, - 'per_page' => $per_page, - 'quarantine_items' => $ret, - ]); - - return $result; - } - - public function list_quarantine_item($lazaret_id, Application $app, Request $request) - { - $lazaretFile = $app['EM']->find('Phraseanet:LazaretFile', $lazaret_id); - - /* @var $lazaretFile LazaretFile */ - if (null === $lazaretFile) { - throw new \API_V1_exception_notfound(sprintf('Lazaret file id %d not found', $lazaret_id)); - } - - if (!$app['acl']->get($app['authentication']->getUser())->has_right_on_base($lazaretFile->getBaseId(), 'canaddrecord')) { - throw new \API_V1_exception_forbidden('You do not have access to this quarantine item'); - } - - $ret = ['quarantine_item' => $this->list_lazaret_file($lazaretFile)]; - - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas($ret); - - return $result; - } - - protected function list_lazaret_file(LazaretFile $file) - { - $checks = []; - - if ($file->getChecks()) { - foreach ($file->getChecks() as $checker) { - - $checks[] = $checker->getMessage($this->app['translator']); - } - } - - $usr_id = null; - if ($file->getSession()->getUser()) { - $usr_id = $file->getSession()->getUser()->getId(); - } - - $session = [ - 'id' => $file->getSession()->getId(), - 'usr_id' => $usr_id, - ]; - - 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 \API_V1_result - */ - public function search(Request $request) - { - $result = new API_V1_result($this->app, $request, $this); - - list($ret, $search_result) = $this->prepare_search_request($request); - - $ret['results'] = ['records' => [], 'stories' => []]; - - foreach ($search_result->getResults() as $record) { - if ($record->is_grouping()) { - $ret['results']['stories'][] = $this->list_story($record); - } else { - $ret['results']['records'][] = $this->list_record($record); - } - } - - /** - * @todo donner des highlights - */ - $result->set_datas($ret); - - return $result; - } - - /** - * Get an API_V1_result containing the results of a records search - * - * Deprecated in favor of search - * - * @param Request $request - * - * @return API_V1_result - */ - public function search_records(Request $request) - { - $result = new API_V1_result($this->app, $request, $this); - - list($ret, $search_result) = $this->prepare_search_request($request); - - foreach ($search_result->getResults() as $record) { - $ret['results'][] = $this->list_record($record); - } - - /** - * @todo donner des highlights - */ - $result->set_datas($ret); - - return $result; - } - - private function prepare_search_request(Request $request) - { - $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->app['phraseanet.SE']->resetCache(); - - $search_result = $this->app['phraseanet.SE']->query($query, $offsetStart, $perPage, $options); - - $userQuery = new UserQuery(); - $userQuery->setUser($this->app['authentication']->getUser()); - $userQuery->setQuery($query); - - $this->app['EM']->persist($userQuery); - $this->app['EM']->flush(); - - 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->app['phraseanet.SE.logger']->log($databox, $search_result->getQuery(), $search_result->getTotal(), $colls); - } - - $this->app['phraseanet.SE']->clearCache(); - - $ret = [ - 'offset_start' => $offsetStart, - 'per_page' => $perPage, - 'available_results' => $search_result->getAvailable(), - 'total_results' => $search_result->getTotal(), - 'error' => $search_result->getError(), - 'warning' => $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 an API_V1_result containing the baskets where the record is in - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return API_V1_result - */ - public function get_record_related(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $that = $this; - $baskets = array_map(function ($basket) use ($that) { - return $that->list_basket($basket); - }, (array) $this->app['phraseanet.appbox'] - ->get_databox($databox_id) - ->get_record($record_id) - ->get_container_baskets($this->app['EM'], $this->app['authentication']->getUser()) - ); - - $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - $stories = array_map(function ($story) use ($that) { - return $that->list_story($story); - }, array_values($record->get_grouping_parents()->get_elements())); - - $result->set_datas([ - "baskets" => $baskets, - "stories" => $stories, - ]); - - return $result; - } - - /** - * Get an API_V1_result containing the record metadatas - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return API_V1_result - */ - public function get_record_metadatas(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - $result->set_datas( - [ - "record_metadatas" => $this->list_record_caption($record->get_caption()) - ] - ); - - return $result; - } - - /** - * Get an API_V1_result containing the record status - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return API_V1_result - */ - public function get_record_status(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - - $record = $this->app['phraseanet.appbox'] - ->get_databox($databox_id) - ->get_record($record_id); - - $result->set_datas( - [ - "status" => - $this->list_record_status( - $this->app['phraseanet.appbox']->get_databox($databox_id) - , $record->get_status() - ) - ] - ); - - return $result; - } - - /** - * Get an API_V1_result containing the record embed files - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return API_V1_result - */ - public function get_record_embed(Request $request, $databox_id, $record_id) - { - - $result = new API_V1_result($this->app, $request, $this); - - $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - $ret = []; - - $devices = $request->get('devices', []); - $mimes = $request->get('mimes', []); - - foreach ($record->get_embedable_medias($devices, $mimes) as $media) { - if (null !== $embed = $this->list_embedable_media($media)) { - $ret[] = $embed; - } - } - - $result->set_datas(["embed" => $ret]); - - return $result; - } - - /** - * Get an API_V1_result containing the story embed files - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * - * @return API_V1_result - */ - public function get_story_embed(Request $request, $databox_id, $record_id) - { - - $result = new API_V1_result($this->app, $request, $this); - - $record = $this->app['phraseanet.appbox'] - ->get_databox($databox_id) - ->get_record($record_id); - - $ret = []; - - $devices = $request->get('devices', []); - $mimes = $request->get('mimes', []); - - foreach ($record->get_embedable_medias($devices, $mimes) as $media) { - if (null !== $embed = $this->list_embedable_media($media)) { - $ret[] = $embed; - } - } - - $result->set_datas(["embed" => $ret]); - - return $result; - } - - public function set_record_metadatas(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - $record = $this->app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); - - try { - $metadatas = $request->get('metadatas'); - - if (!is_array($metadatas)) { - throw new Exception('Metadatas should be an array'); - } - - foreach ($metadatas as $metadata) { - if (!is_array($metadata)) { - throw new Exception('Each Metadata value should be an array'); - } - } - - $record->set_metadatas($metadatas); - $result->set_datas(["record_metadatas" => $this->list_record_caption($record->get_caption())]); - } catch (\Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('An error occured')); - } - - return $result; - } - - public function set_record_status(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - $databox = $this->app['phraseanet.appbox']->get_databox($databox_id); - $record = $databox->get_record($record_id); - $status_bits = $databox->get_statusbits(); - - try { - $status = $request->get('status'); - - $datas = strrev($record->get_status()); - - if (!is_array($status)) { - throw new API_V1_exception_badrequest(); - } - foreach ($status as $n => $value) { - if ($n > 31 || $n < 4) { - throw new API_V1_exception_badrequest(); - } - if (!in_array($value, ['0', '1'])) { - throw new API_V1_exception_badrequest(); - } - if (!isset($status_bits[$n])) { - throw new API_V1_exception_badrequest (); - } - - $datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 2)); - } - $datas = strrev($datas); - - $record->set_binary_status($datas); - - $this->app['phraseanet.SE']->updateRecord($record); - - $result->set_datas([ - "status" => - $this->list_record_status($databox, $record->get_status()) - ] - ); - } catch (\Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $this->app->trans('An error occured')); - } - - return $result; - } - - /** - * Move a record to another collection - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * @return API_V1_result - */ - public function set_record_collection(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - $databox = $this->app['phraseanet.appbox']->get_databox($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->app['phraseanet.appbox']); - $result->set_datas(["record" => $this->list_record($record)]); - } catch (\Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $e->getMessage()); - } - - return $result; - } - - /** - * Return detailed informations about one record - * - * @param Request $request - * @param int $databox_id - * @param int $record_id - * @return API_V1_result - */ - public function get_record(Request $request, $databox_id, $record_id) - { - $result = new API_V1_result($this->app, $request, $this); - $databox = $this->app['phraseanet.appbox']->get_databox($databox_id); - try { - $record = $databox->get_record($record_id); - $result->set_datas(['record' => $this->list_record($record)]); - } catch (NotFoundHttpException $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $this->app->trans('Record Not Found')); - } catch (\Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $this->app->trans('An error occured')); - } - - return $result; - } - - /** - * Return detailed informations about one story - * - * @param Request $request - * @param int $databox_id - * @param int $story_id - * @return API_V1_result - */ - public function get_story(Request $request, $databox_id, $story_id) - { - $result = new API_V1_result($this->app, $request, $this); - $databox = $this->app['phraseanet.appbox']->get_databox($databox_id); - try { - $story = $databox->get_record($story_id); - $result->set_datas(['story' => $this->list_story($story)]); - } catch (NotFoundHttpException $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $this->app->trans('Story Not Found')); - } catch (\Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, $this->app->trans('An error occured')); - } - - return $result; - } - - /** - * Return the baskets list of the authenticated user - * - * @param Request $request - * @return API_V1_result - */ - public function search_baskets(Request $request) - { - $result = new API_V1_result($this->app, $request, $this); - - $usr_id = $this->app['authentication']->getUser()->getId(); - - $result->set_datas(['baskets' => $this->list_baskets($usr_id)]); - - return $result; - } - - /** - * Return a baskets list - * - * @param int $usr_id - * @return array - */ - protected function list_baskets($usr_id) - { - $repo = $this->app['EM']->getRepository('Phraseanet:Basket'); - /* @var $repo Alchemy\Phrasea\Model\Repositories\BasketRepository */ - - $baskets = $repo->findActiveByUser($this->app['authentication']->getUser()); - - $ret = []; - foreach ($baskets as $basket) { - $ret[] = $this->list_basket($basket); - } - - return $ret; - } - - /** - * Create a new basket - * - * @param Request $request - * @return API_V1_result - */ - public function create_basket(Request $request) - { - $result = new API_V1_result($this->app, $request, $this); - - $name = $request->get('name'); - - if (trim(strip_tags($name)) === '') { - throw new API_V1_exception_badrequest('Missing basket name parameter'); - } - - $Basket = new Basket(); - $Basket->setUser($this->app['authentication']->getUser()); - $Basket->setName($name); - - $this->app['EM']->persist($Basket); - $this->app['EM']->flush(); - - $result->set_datas(["basket" => $this->list_basket($Basket)]); - - return $result; - } - - /** - * Delete a basket - * - * @param Request $request - * @param Basket $basket - * @return array - */ - public function delete_basket(Request $request, Basket $basket) - { - $this->app['EM']->remove($basket); - $this->app['EM']->flush(); - - return $this->search_baskets($request); - } - - /** - * Retrieve a basket - * - * @param Request $request - * @param Basket $basket - * @return API_V1_result - */ - public function get_basket(Request $request, Basket $basket) - { - $result = new API_V1_result($this->app, $request, $this); - - $result->set_datas( - [ - "basket" => $this->list_basket($basket), - "basket_elements" => $this->list_basket_content($basket) - ] - ); - - return $result; - } - - /** - * Retrieve elements of one basket - * - * @param Basket $Basket - * @return type - */ - protected function list_basket_content(Basket $Basket) - { - $ret = []; - - foreach ($Basket->getElements() as $basket_element) { - $ret[] = $this->list_basket_element($basket_element); - } - - return $ret; - } - - /** - * Retrieve detailled informations about a basket element - * - * @param BasketElement $basket_element - * @return type - */ - protected function list_basket_element(BasketElement $basket_element) - { - $ret = [ - 'basket_element_id' => $basket_element->getId(), - 'order' => $basket_element->getOrd(), - 'record' => $this->list_record($basket_element->getRecord($this->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() != $this->app['authentication']->getUser()->getId(), - ], - 'agreement' => $validation_datas->getAgreement(), - 'updated_on' => $validation_datas->getUpdated()->format(DATE_ATOM), - 'note' => null === $validation_datas->getNote() ? '' : $validation_datas->getNote(), - ]; - - if ($user->getId() == $this->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 API_V1_result - */ - public function set_basket_title(Request $request, Basket $basket) - { - $result = new API_V1_result($this->app, $request, $this); - - $basket->setName($request->get('name')); - - $this->app['EM']->persist($basket); - $this->app['EM']->flush(); - - $result->set_datas(["basket" => $this->list_basket($basket)]); - - return $result; - } - - /** - * Change the description of one basket - * - * @param Request $request - * @param Basket $basket - * @return API_V1_result - */ - public function set_basket_description(Request $request, Basket $basket) - { - $result = new API_V1_result($this->app, $request, $this); - - $basket->setDescription($request->get('description')); - - $this->app['EM']->persist($basket); - $this->app['EM']->flush(); - - $result->set_datas(["basket" => $this->list_basket($basket)]); - - return $result; - } - - /** - * List all avalaible feeds - * - * @param Request $request - * @param User $user - * @return API_V1_result - */ - public function search_publications(Request $request, User $user) - { - $result = new API_V1_result($this->app, $request, $this); - - $coll = $this->app['EM']->getRepository('Phraseanet:Feed')->getAllForUser($this->app['acl']->get($user)); - - $datas = []; - foreach ($coll as $feed) { - $datas[] = $this->list_publication($feed, $user); - } - - $result->set_datas(["feeds" => $datas]); - - return $result; - } - - /** - * @param Request $request - * @param int $publication_id - */ - public function remove_publications(Request $request, $publication_id) - { - - } - - /** - * Retrieve one feed - * - * @param Request $request - * @param int $publication_id - * @param User $user - * @return API_V1_result - */ - public function get_publication(Request $request, $publication_id, User $user) - { - $result = new API_V1_result($this->app, $request, $this); - - $feed = $this->app['EM']->getRepository('Phraseanet:Feed')->find($publication_id); - if (!$feed->isAccessible($user, $this->app)) { - return $result->set_datas([]); - } - $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 : 5; - - $datas = [ - 'feed' => $this->list_publication($feed, $user), - 'offset_start' => $offset_start, - 'per_page' => $per_page, - 'entries' => $this->list_publications_entries($feed, $offset_start, $per_page), - ]; - - $result->set_datas($datas); - - return $result; - } - - public function get_publications(Request $request, User $user) - { - $result = new API_V1_result($this->app, $request, $this); - - $feed = Aggregate::createFromUser($this->app, $user); - - $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 : 5; - - $datas = [ - 'total_entries' => $feed->getCountTotalEntries(), - 'offset_start' => $offset_start, - 'per_page' => $per_page, - 'entries' => $this->list_publications_entries($feed, $offset_start, $per_page), - ]; - - $result->set_datas($datas); - - return $result; - } - - public function get_feed_entry(Request $request, $entry_id, User $user) - { - $result = new API_V1_result($this->app, $request, $this); - - $entry = $this->app['EM']->getRepository('Phraseanet:FeedEntry')->find($entry_id); - - $collection = $entry->getFeed()->getCollection($this->app); - - if (null !== $collection && !$this->app['acl']->get($user)->has_access_to_base($collection->get_base_id())) { - throw new \API_V1_exception_forbidden('You have not access to the parent feed'); - } - - $datas = [ - 'entry' => $this->list_publication_entry($entry), - ]; - - $result->set_datas($datas); - - return $result; - } - - /** - * Retrieve detailled informations about one feed - * - * @param Feed $feed - * @param type $user - * @return array - */ - protected 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 - */ - protected function list_publications_entries(FeedInterface $feed, $offset_start = 0, $how_many = 5) - { - - $entries = $feed->getEntries($offset_start, $how_many); - - $out = []; - foreach ($entries as $entry) { - $out[] = $this->list_publication_entry($entry); - } - - return $out; - } - - /** - * Retrieve detailled information about one feed entry - * - * @param FeedEntry $entry - * @return array - */ - protected function list_publication_entry(FeedEntry $entry) - { - $items = []; - foreach ($entry->getItems() as $item) { - $items[] = $this->list_publication_entry_item($item); - } - - 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_url' => '/feeds/' . $entry->getFeed()->getId() . '/content/', - 'url' => '/feeds/entry/' . $entry->getId() . '/', - ]; - } - - /** - * Retrieve detailled informations about one feed entry item - * - * @param FeedItem $item - * @return array - */ - protected function list_publication_entry_item(FeedItem $item) - { - $datas = [ - 'item_id' => $item->getId() - , 'record' => $this->list_record($item->getRecord($this->app)) - ]; - - return $datas; - } - - /** - * @todo - * @param Request $request - */ - public function search_users(Request $request) - { - - } - - /** - * @param Request $request - * @param int $usr_id - */ - public function get_user_acces(Request $request, $usr_id) - { - - } - - /** - * @todo - * @param Request $request - */ - public function add_user(Request $request) - { - - } - - /** - * @retrieve detailled informations about one suddef - * - * @param media_subdef $media - * @return array - */ - protected function list_embedable_media(media_subdef $media) - { - if (!$media->is_physically_present()) { - 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(), - ]; - } - - /** - * Retrieve detailled information about one permalink - * - * @param media_Permalink_Adapter $permalink - * - * @return type - */ - protected function list_permalink(media_Permalink_Adapter $permalink) - { - 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' => $permalink->get_url() . '&download', - 'url' => $permalink->get_url() - ]; - } - - /** - * Retrieve detailled information about one status - * - * @param databox $databox - * @param string $status - * @return array - */ - protected function list_record_status(databox $databox, $status) - { - $status = strrev($status); - $ret = []; - foreach ($databox->get_statusbits() as $bit => $status_datas) { - $ret[] = ['bit' => $bit, 'state' => !!substr($status, ($bit - 1), 1)]; - } - - return $ret; - } - - /** - * List all field about a specified caption - * - * @param caption_record $caption - * @return array - */ - protected 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 - */ - protected 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(), - ]; - } - - /** - * Retirve information about one basket - * - * @param Basket $basket - * @return array - */ - public function list_basket(Basket $basket) - { - $ret = [ - 'basket_id' => $basket->getId(), - 'created_on' => $basket->getCreated()->format(DATE_ATOM), - 'description' => (string) $basket->getDescription(), - 'name' => $basket->getName(), - 'pusher_usr_id' => $basket->getPusher() ? $basket->getPusher()->getId() : null, - 'updated_on' => $basket->getUpdated()->format(DATE_ATOM), - 'unread' => !$basket->getIsRead(), - 'validation_basket' => !!$basket->getValidation() - ]; - - if ($basket->getValidation()) { - $users = []; - - foreach ($basket->getValidation()->getParticipants() as $participant) { - /* @var $participant ValidationParticipant */ - $user = $participant->getUser(); - - $users[] = [ - 'usr_id' => $user->getId(), - 'usr_name' => $user->getDisplayName(), - 'confirmed' => $participant->getIsConfirmed(), - 'can_agree' => $participant->getCanAgree(), - 'can_see_others' => $participant->getCanSeeOthers(), - 'readonly' => $user->getId() != $this->app['authentication']->getUser()->getId(), - ]; - } - - $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->app['authentication']->getUser()), - 'validation_confirmed' => $basket->getValidation()->getParticipant($this->app['authentication']->getUser())->getIsConfirmed(), - 'validation_initiator' => $basket->getValidation()->isInitiator($this->app['authentication']->getUser()), - ], $ret - ); - } - - return $ret; - } - - /** - * Retrieve detailled informations about one record - * - * @param record_adapter $record - * @return array - */ - public function list_record(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->list_embedable_media($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(record_adapter $story) - { - if (!$story->is_grouping()) { - throw new \API_V1_exception_notfound('Story not found'); - } - - $that = $this; - $records = array_map(function (\record_adapter $record) use ($that) { - return $that->list_record($record); - }, array_values($story->get_children()->get_elements())); - - $caption = $story->get_caption(); - - $format = function (caption_record $caption, $dcField) { - - $field = $caption->get_dc_field($dcField); - - if (!$field) { - return null; - } - - return $field->get_serialized_values(); - }; - - return [ - '@entity@' => self::OBJECT_TYPE_STORY, - 'databox_id' => $story->get_sbas_id(), - 'story_id' => $story->get_record_id(), - 'updated_on' => $story->get_modification_date()->format(DATE_ATOM), - 'created_on' => $story->get_creation_date()->format(DATE_ATOM), - 'collection_id' => phrasea::collFromBas($this->app, $story->get_base_id()), - 'thumbnail' => $this->list_embedable_media($story->get_thumbnail()), - '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 - */ - protected function list_databoxes() - { - $ret = []; - foreach ($this->app['phraseanet.appbox']->get_databoxes() as $databox) { - $ret[] = $this->list_databox($databox); - } - - return $ret; - } - - /** - * Retrieve CGU's for the specified databox - * - * @param databox $databox - * @return array - */ - protected 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 - */ - protected function list_databox(databox $databox) - { - $ret = []; - - $ret['databox_id'] = $databox->get_sbas_id(); - $ret['name'] = $databox->get_dbname(); - $ret['viewname'] = $databox->get_viewname(); - $ret['labels'] = [ - 'en' => $databox->get_label('en'), - 'de' => $databox->get_label('de'), - 'fr' => $databox->get_label('fr'), - 'nl' => $databox->get_label('nl'), - ]; - $ret['version'] = $databox->get_version(); - - return $ret; - } - - /** - * List all available collections for a specified databox - * - * @param databox $databox - * @return array - */ - protected function list_databox_collections(databox $databox) - { - $ret = []; - - foreach ($databox->get_collections() as $collection) { - $ret[] = $this->list_collection($collection); - } - - return $ret; - } - - /** - * Retrieve detailled informations about one collection - * - * @param collection $collection - * @return array - */ - protected function list_collection(collection $collection) - { - $ret = [ - '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(), - ]; - - return $ret; - } - - /** - * Retrieve informations for a list of status - * - * @param array $status - * @return array - */ - protected function list_databox_status(array $status) - { - $ret = []; - foreach ($status as $n => $datas) { - $ret[] = [ - 'bit' => $n, - 'label_on' => $datas['labelon'], - 'label_off' => $datas['labeloff'], - 'labels' => [ - 'en' => $datas['labels_on_i18n']['en'], - 'fr' => $datas['labels_on_i18n']['fr'], - 'de' => $datas['labels_on_i18n']['de'], - 'nl' => $datas['labels_on_i18n']['nl'], - ], - 'img_on' => $datas['img_on'], - 'img_off' => $datas['img_off'], - 'searchable' => !!$datas['searchable'], - 'printable' => !!$datas['printable'], - ]; - } - - return $ret; - } - - /** - * List all metadatas field using a databox meta structure - * - * @param databox_descriptionStructure $meta_struct - * @return array - */ - protected function list_databox_metadatas_fields(databox_descriptionStructure $meta_struct) - { - $ret = []; - foreach ($meta_struct as $meta) { - $ret[] = $this->list_databox_metadata_field_properties($meta); - } - - return $ret; - } - - /** - * Retirve informations about one databox metadata field - * - * @param databox_field $databox_field - * @return array - */ - protected function list_databox_metadata_field_properties(databox_field $databox_field) - { - $ret = [ - '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(), - ]; - - return $ret; - } - -} diff --git a/lib/classes/API/V1/exception/abstract.php b/lib/classes/API/V1/exception/abstract.php deleted file mode 100644 index 81626c4e7a..0000000000 --- a/lib/classes/API/V1/exception/abstract.php +++ /dev/null @@ -1,20 +0,0 @@ -app = $app; - $this->request = $request; - $this->api_version = $api->get_version(); - $this->response_time = $date->format(DATE_ATOM); - $this->response = new stdClass(); - - $this->parse_response_type(); - - return $this; - } - - protected function parse_response_type() - { - if (trim($this->request->get('callback')) !== '') { - return $this->response_type = self::FORMAT_JSONP; - } - - $accept = $this->request->getAcceptableContentTypes(); - $response_types = []; - - foreach ($accept as $key => $app_type) { - $response_types[strtolower($app_type)] = true; - } - - if (array_key_exists('application/json', $response_types)) { - return $this->response_type = self::FORMAT_JSON; - } - if (array_key_exists('application/yaml', $response_types)) { - return $this->response_type = self::FORMAT_YAML; - } - if (array_key_exists('text/yaml', $response_types)) { - return $this->response_type = self::FORMAT_YAML; - } - - return $this->response_type = self::FORMAT_JSON; - } - - /** - * Set datas to the response - * If no datas provided (aka empty array), a stdClass if set, - * so the serialized datas will be objects - * - * @param array $datas - * @return API_V1_result - */ - public function set_datas(array $datas) - { - if (count($datas) === 0) - $datas = new stdClass (); - $this->response = $datas; - - return $this; - } - - /** - * Return response data - * - * @return array - */ - public function get_datas() - { - return (array) $this->response; - } - - /** - * Format the data and return serialized string - * - * @return string - */ - public function format() - { - $request_uri = sprintf('%s %s' - , $this->request->getMethod() - , $this->request->getBasePath() - . $this->request->getPathInfo() - ); - - $ret = [ - 'meta' => [ - 'api_version' => $this->api_version - , 'request' => $request_uri - , 'response_time' => $this->response_time - , 'http_code' => $this->http_code - , 'error_type' => $this->error_type - , 'error_message' => $this->error_message - , 'error_details' => $this->error_details - , 'charset' => 'UTF-8' - ] - , 'response' => $this->response - ]; - - $this->app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new ApiResultEvent()); - - if ($this->app['conf']->get(['main', 'api-timers'], false)) { - $ret['timers'] = $this->app['api.timers']->toArray(); - } - - switch ($this->response_type) { - case self::FORMAT_JSON: - default: - $return_value = p4string::jsonencode($ret); - break; - case self::FORMAT_YAML: - if ($ret['response'] instanceof stdClass) - $ret['response'] = []; - - $dumper = new Symfony\Component\Yaml\Dumper(); - $return_value = $dumper->dump($ret, 8); - break; - case self::FORMAT_JSONP: - $callback = trim($this->request->get('callback')); - $return_value = $callback . '(' . p4string::jsonencode($ret) . ')'; - break; - } - - return $return_value; - } - - /** - * Return serailized datas content type - * - * @return string - */ - public function get_content_type() - { - switch ($this->response_type) { - - case self::FORMAT_JSON: - default: - $return_value = 'application/json'; - break; - case self::FORMAT_YAML: - $return_value = 'application/yaml'; - break; - case self::FORMAT_JSONP: - $return_value = 'text/javascript'; - break; - } - - return $return_value; - } - - /** - * Set the API_V1_result http_code, error_type, error_message and error_details - * with the appropriate datas - * - * @param string $const - * @param string $message - * - * @return API_V1_result - */ - public function set_error_message($const, $message) - { - $this->error_details = $message; - - switch ($const) { - case self::ERROR_BAD_REQUEST: - $this->http_code = 400; - $this->error_type = $const; - $this->error_message = API_V1_exception_badrequest::get_details(); - break; - case self::ERROR_UNAUTHORIZED: - $this->http_code = 401; - $this->error_type = $const; - $this->error_message = API_V1_exception_unauthorized::get_details(); - break; - case self::ERROR_FORBIDDEN: - $this->http_code = 403; - $this->error_type = $const; - $this->error_message = API_V1_exception_forbidden::get_details(); - break; - case self::ERROR_NOTFOUND: - $this->http_code = 404; - $this->error_type = $const; - $this->error_message = API_V1_exception_notfound::get_details(); - break; - case self::ERROR_METHODNOTALLOWED: - $this->http_code = 405; - $this->error_type = $const; - $this->error_message = API_V1_exception_methodnotallowed::get_details(); - break; - case self::ERROR_INTERNALSERVERERROR: - $this->http_code = 500; - $this->error_type = $const; - $this->error_message = API_V1_exception_internalservererror::get_details(); - break; - case self::ERROR_MAINTENANCE: - $this->http_code = 503; - $this->error_type = $const; - $this->error_message = API_V1_exception_maintenance::get_details(); - break; - case OAUTH2_ERROR_INVALID_REQUEST: - $this->error_type = $const; - break; - } - - return $this; - } - - /** - * Set the API_V1_result http_code, error_message and error_details - * with the appropriate datas - * - * @param integer $code - * - * @return API_V1_result - */ - public function set_error_code($code) - { - switch ($code = (int) $code) { - case 400: - $this->http_code = $code; - $this->error_type = self::ERROR_BAD_REQUEST; - $this->error_message = API_V1_exception_badrequest::get_details(); - break; - case 401: - $this->http_code = $code; - $this->error_type = self::ERROR_UNAUTHORIZED; - $this->error_message = API_V1_exception_unauthorized::get_details(); - break; - case 403: - $this->http_code = $code; - $this->error_type = self::ERROR_FORBIDDEN; - $this->error_message = API_V1_exception_forbidden::get_details(); - break; - case 404: - $this->http_code = $code; - $this->error_type = self::ERROR_NOTFOUND; - $this->error_message = API_V1_exception_notfound::get_details(); - break; - case 405: - $this->http_code = $code; - $this->error_type = self::ERROR_METHODNOTALLOWED; - $this->error_message = API_V1_exception_methodnotallowed::get_details(); - break; - case 500: - $this->http_code = $code; - $this->error_type = self::ERROR_INTERNALSERVERERROR; - $this->error_message = API_V1_exception_internalservererror::get_details(); - break; - } - - return $this; - } - - /** - * Returns the correct http code depending on the errors - * - * @return int - */ - public function get_http_code() - { - if ($this->response_type == self::FORMAT_JSONP && $this->http_code != 500) { - return 200; - } else { - return $this->http_code; - } - } - - /** - * - * @param int $code - */ - public function set_http_code($code) - { - $this->http_code = (int) $code; - } - - /** - * Return a Symfony Response - * - * @return \Symfony\Component\HttpFoundation\Response - */ - public function get_response() - { - $response = new Response( - $this->format(), - $this->get_http_code(), - ['Content-Type' => $this->get_content_type()] - ); - $response->setCharset('UTF-8'); - - return $response; - } -} diff --git a/lib/classes/patch/390alpha14a.php b/lib/classes/patch/390alpha14a.php new file mode 100644 index 0000000000..958fe50228 --- /dev/null +++ b/lib/classes/patch/390alpha14a.php @@ -0,0 +1,68 @@ +release; + } + + /** + * {@inheritdoc} + */ + public function require_all_upgrades() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function concern() + { + return $this->concern; + } + + /** + * {@inheritdoc} + */ + public function getDoctrineMigrations() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply(base $appbox, Application $app) + { + $app['conf']->remove(['main', 'api-timers']); + + if ($this->tableHasField($appbox, 'api_logs', 'api_log_ressource')) { + $sql = 'UPDATE api_logs SET api_log_resource = api_log_ressource'; + $app['phraseanet.appbox']->get_connection()->executeUpdate($sql); + } + + return true; + } +} diff --git a/lib/classes/patchAbstract.php b/lib/classes/patchAbstract.php index ec094e4f10..32db2ab1de 100644 --- a/lib/classes/patchAbstract.php +++ b/lib/classes/patchAbstract.php @@ -9,6 +9,7 @@ * file that was distributed with this source code. */ +use Alchemy\Phrasea\Application; use Doctrine\ORM\NoResultException; use Doctrine\ORM\EntityManager; @@ -25,4 +26,25 @@ abstract class patchAbstract implements patchInterface } } + + protected function tableExists(base $base, $tableName) + { + return $base + ->get_connection() + ->getSchemaManager() + ->tablesExist([$tableName]); + } + + protected function tableHasField(base $base, $tableName, $fieldName) + { + if (!$this->tableExists($base, $tableName)) { + return false; + } + + return $base + ->get_connection() + ->getSchemaManager() + ->listTableDetails($tableName) + ->hasColumn($fieldName); + } } diff --git a/lib/conf.d/bases_structure.xml b/lib/conf.d/bases_structure.xml index 3515f8b18b..c8986bd03a 100644 --- a/lib/conf.d/bases_structure.xml +++ b/lib/conf.d/bases_structure.xml @@ -383,7 +383,7 @@ - api_log_ressource + api_log_resource varchar(64) YES diff --git a/lib/conf.d/configuration.yml b/lib/conf.d/configuration.yml index 56273b61a5..104c4837e4 100644 --- a/lib/conf.d/configuration.yml +++ b/lib/conf.d/configuration.yml @@ -16,7 +16,6 @@ main: driver: pdo_sqlite path: '/tmp/db.sqlite' charset: UTF8 - api-timers: false cache: type: MemcacheCache options: diff --git a/tests/Alchemy/Tests/Phrasea/Application/ApiJSONPTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiJSONPTest.php similarity index 97% rename from tests/Alchemy/Tests/Phrasea/Application/ApiJSONPTest.php rename to tests/Alchemy/Tests/Phrasea/Controller/Api/ApiJSONPTest.php index e6e4d80ee4..f1eb12df31 100644 --- a/tests/Alchemy/Tests/Phrasea/Application/ApiJSONPTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiJSONPTest.php @@ -1,6 +1,6 @@ evaluateMetaNotFound($content); } - /** - * @covers \API_V1_adapter::get_databoxes - * @covers \API_V1_adapter::list_databoxes - * @covers \API_V1_adapter::list_databox - */ public function testDataboxListRoute() { $this->setToken(self::$token); @@ -231,8 +227,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase /** * Route GET /API/V1/monitor/task - * @covers API_V1_adapter::get_task_list - * @covers API_V1_adapter::list_task */ public function testGetMonitorTasks() { @@ -261,7 +255,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase /** * Route GET /API/V1/monitor/scheduler - * @covers API_V1_adapter::get_scheduler */ public function testGetScheduler() { @@ -340,11 +333,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * Route GET /API/V1/monitor/task{idTask} - * @covers API_V1_adapter::get_task - * @covers API_V1_adapter::list_task - */ public function testGetMonitorTaskById() { $tasks = self::$DI['app']['manipulator.task']->getRepository()->findAll(); @@ -372,10 +360,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateGoodTask($content['response']['task']); } - /** - * Route POST /API/V1/monitor/task{idTask} - * @covers API_V1_adapter::set_task_property - */ public function testPostMonitorTaskById() { $tasks = self::$DI['app']['manipulator.task']->getRepository()->findAll(); @@ -406,10 +390,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals($title, $content['response']['task']['title']); } - /** - * Route GET /API/V1/monitor/task/{idTask}/ - * @covers API_V1_adapter::get_task - */ public function testUnknowGetMonitorTaskById() { if (null === self::$adminToken) { @@ -422,10 +402,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMetaNotFound($content); } - /** - * Route POST /API/V1/monitor/task/{idTask}/start - * @covers API_V1_adapter::start_task - */ public function testPostMonitorStartTask() { if (null === self::$adminToken) { @@ -456,10 +432,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals(Task::STATUS_STARTED, $task->getStatus()); } - /** - * Route POST /API/V1/monitor/task/{idTask}/stop - * @covers API_V1_adapter::stop_task - */ public function testPostMonitorStopTask() { $tasks = self::$DI['app']['manipulator.task']->getRepository()->findAll(); @@ -490,13 +462,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals(Task::STATUS_STOPPED, $task->getStatus()); } - /** - * Route GET /API/V1/monitor/phraseanet - * @covers API_V1_adapter::get_phraseanet_monitor - * @covers API_V1_adapter::get_config_info - * @covers API_V1_adapter::get_cache_info - * @covers API_V1_adapter::get_gv_info - */ public function testgetMonitorPhraseanet() { if (null === self::$adminToken) { @@ -519,10 +484,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertInternalType('array', $content['response']['phraseanet']); } - /** - * @covers \API_V1_adapter::get_record - * @covers \API_V1_adapter::list_record - */ public function testRecordRoute() { $this->setToken(self::$token); @@ -545,10 +506,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_story - * @covers \API_V1_adapter::list_story - */ public function testStoryRoute() { $this->setToken(self::$token); @@ -580,11 +537,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase self::$DI['record_story_1']->removeChild(self::$DI['record_1']); } - /** - * @covers \API_V1_adapter::get_databox_collections - * @covers \API_V1_adapter::list_databox_collections - * @covers \API_V1_adapter::list_collection - */ public function testDataboxCollectionRoute() { $this->setToken(self::$token); @@ -625,10 +577,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_databox_status - * @covers \API_V1_adapter::list_databox_status - */ public function testDataboxStatusRoute() { $this->setToken(self::$token); @@ -678,11 +626,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_databox_metadatas - * @covers \API_V1_adapter::list_databox_metadatas_fields - * @covers \API_V1_adapter::list_databox_metadata_field_properties - */ public function testDataboxMetadatasRoute() { $this->setToken(self::$token); @@ -766,11 +709,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_databox_terms - * @covers \API_V1_adapter::list_databox_terms - * - */ public function testDataboxTermsOfUseRoute() { $this->setToken(self::$token); @@ -799,11 +737,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::search - * @covers \API_V1_adapter::list_record - * @covers \API_V1_adapter::list_story - */ public function testSearchRoute() { $this->setToken(self::$token); @@ -833,11 +766,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::search - * @covers \API_V1_adapter::list_record - * @covers \API_V1_adapter::list_story - */ public function testSearchRouteWithStories() { $this->setToken(self::$token); @@ -870,10 +798,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::search_records - * @covers \API_V1_adapter::list_record - */ public function testRecordsSearchRoute() { $this->setToken(self::$token); @@ -925,9 +849,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase return [['POST'], ['GET']]; } - /** - * @covers \API_V1_adapter::caption_records - */ public function testRecordsCaptionRoute() { $this->setToken(self::$token); @@ -953,10 +874,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_record_metadatas - * @covers \API_V1_adapter::list_record_caption - */ public function testRecordsMetadatasRoute() { $this->setToken(self::$token); @@ -980,9 +897,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_record_status - */ public function testRecordsStatusRoute() { $this->setToken(self::$token); @@ -1006,11 +920,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_record_embed - * @covers \API_V1_adapter::list_embedable_media - * @covers \API_V1_adapter::list_permalink - */ public function testRecordsEmbedRoute() { $this->setToken(self::$token); @@ -1037,11 +946,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_record_embed - * @covers \API_V1_adapter::list_embedable_media - * @covers \API_V1_adapter::list_permalink - */ public function testStoriesEmbedRoute() { $this->setToken(self::$token); @@ -1069,9 +973,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::get_record_embed - */ public function testRecordsEmbedRouteMimeType() { $this->setToken(self::$token); @@ -1086,9 +987,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals(0, count($content['response']['embed'])); } - /** - * @covers \API_V1_adapter::get_record_related - */ public function testRecordsEmbedRouteDevices() { $this->setToken(self::$token); @@ -1101,9 +999,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals(0, count($content['response']['embed'])); } - /** - * @covers \API_V1_adapter::get_record_related - */ public function testRecordsRelatedRoute() { $this->setToken(self::$token); @@ -1130,11 +1025,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMethodNotAllowedRoute($route, ['POST', 'PUT', 'DELETE']); } - /** - * @covers \API_V1_adapter::set_record_metadatas - * @covers \API_V1_adapter::list_record_caption - * @covers \API_V1_adapter::list_record_caption_field - */ public function testRecordsSetMetadatas() { $this->setToken(self::$token); @@ -1192,10 +1082,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::set_record_status - * @covers \API_V1_adapter::list_record_status - */ public function testRecordsSetStatus() { $this->setToken(self::$token); @@ -1254,12 +1140,9 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase self::$DI['record_1']->set_binary_status(str_repeat('0', 32)); } - /** - * @covers \API_V1_adapter::set_record_collection - */ public function testMoveRecordToCollection() { - $file = new File(self::$DI['app'], self::$DI['app']['mediavorus']->guess(__DIR__ . '/../../../../files/test001.jpg'), self::$DI['collection']); + $file = new File(self::$DI['app'], self::$DI['app']['mediavorus']->guess(__DIR__ . '/../../../../../files/test001.jpg'), self::$DI['collection']); $record = \record_adapter::createFromFile($file, self::$DI['app']); $this->setToken(self::$token); @@ -1288,11 +1171,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $record->delete(); } - /** - * @covers \API_V1_adapter::search_baskets - * @covers \API_V1_adapter::list_baskets - * @covers \API_V1_adapter::list_basket - */ public function testSearchBaskets() { self::$DI['client'] = new Client(self::$DI['app'], []); @@ -1313,10 +1191,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::create_basket - * @covers \API_V1_adapter::list_basket - */ public function testAddBasket() { $this->setToken(self::$token); @@ -1337,11 +1211,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals('un Joli Nom', $content['response']['basket']['name']); } - /** - * @covers \API_V1_adapter::get_basket - * @covers \API_V1_adapter::list_basket_content - * @covers \API_V1_adapter::list_basket_element - */ public function testBasketContent() { $this->setToken(self::$adminToken); @@ -1377,11 +1246,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::set_basket_title - * @covers \API_V1_adapter::list_basket_content - * @covers \API_V1_adapter::list_basket_element - */ public function testSetBasketTitle() { $this->setToken(self::$adminToken); @@ -1430,11 +1294,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals($content['response']['basket']['name'], 'aéaa'); } - /** - * @covers \API_V1_adapter::set_basket_description - * @covers \API_V1_adapter::list_basket_content - * @covers \API_V1_adapter::list_basket_element - */ public function testSetBasketDescription() { $this->setToken(self::$adminToken); @@ -1458,9 +1317,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals($content['response']['basket']['description'], 'une belle desc'); } - /** - * @covers \API_V1_adapter::delete_basket - */ public function testDeleteBasket() { $this->setToken(self::$adminToken); @@ -1486,10 +1342,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::add_record - * @covers \API_V1_adapter::list_record - */ public function testAddRecord() { $this->setToken(self::$token); @@ -1509,10 +1361,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertArrayHasKey('url', $datas); } - /** - * @covers \API_V1_adapter::add_record - * @covers \API_V1_adapter::list_record - */ public function testAddRecordForceRecord() { $this->setToken(self::$token); @@ -1538,10 +1386,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals('0', $datas['entity']); } - /** - * @covers \API_V1_adapter::add_record - * @covers \API_V1_adapter::list_quarantine_item - */ public function testAddRecordForceLazaret() { $this->setToken(self::$token); @@ -1566,9 +1410,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertEquals('1', $datas['entity']); } - /** - * @covers \API_V1_adapter::add_record - */ public function testAddRecordWrongBehavior() { $this->setToken(self::$token); @@ -1584,9 +1425,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMetaBadRequest($content); } - /** - * @covers \API_V1_adapter::add_record - */ public function testAddRecordWrongBaseId() { $this->setToken(self::$adminToken); @@ -1602,9 +1440,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMetaForbidden($content); } - /** - * @covers \API_V1_adapter::add_record - */ public function testAddRecordNoBaseId() { $this->setToken(self::$token); @@ -1620,9 +1455,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMetaBadRequest($content); } - /** - * @covers \API_V1_adapter::add_record - */ public function testAddRecordMultipleFiles() { $this->setToken(self::$token); @@ -1652,10 +1484,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMetaBadRequest($content); } - /** - * @covers \API_V1_adapter::search_publications - * @covers \API_V1_adapter::list_publication - */ public function testFeedList() { $created_feed = self::$DI['app']['EM']->find('Phraseanet:Feed', 1); @@ -1690,13 +1518,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::get_publications - * @covers \API_V1_adapter::list_publications_entries - * @covers \API_V1_adapter::list_publication_entry - * @covers \API_V1_adapter::list_publication_entry_item - * @covers \API_V1_adapter::list_record - */ public function testFeedsContent() { self::$DI['app']['notification.deliverer'] = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer') @@ -1754,10 +1575,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers \API_V1_adapter::get_feed_entry - * @covers \API_V1_adapter::list_publication_entry - */ public function testFeedEntry() { self::$DI['app']['notification.deliverer'] = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer') @@ -1785,10 +1602,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } - /** - * @covers \API_V1_adapter::get_feed_entry - * @covers \API_V1_adapter::list_publication_entry - */ public function testFeedEntryNoAccess() { self::$DI['app']['notification.deliverer'] = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer') @@ -1812,13 +1625,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->evaluateMetaForbidden($content); } - /** - * @covers \API_V1_adapter::get_publication - * @covers \API_V1_adapter::list_publications_entries - * @covers \API_V1_adapter::list_publication_entry - * @covers \API_V1_adapter::list_publication_entry_item - * @covers \API_V1_adapter::list_record - */ public function testFeedContent() { self::$DI['app']['notification.deliverer'] = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer') @@ -1869,10 +1675,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers list_quarantine - * @covers list_quarantine_item - */ public function testQuarantineList() { $this->setToken(self::$token); @@ -1904,9 +1706,6 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } } - /** - * @covers list_quarantine_item - */ public function testQuarantineContent() { $this->setToken(self::$token); @@ -1936,7 +1735,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase }; $tmpname = tempnam(sys_get_temp_dir(), 'test_quarantine'); - copy(__DIR__ . '/../../../../files/iphone_pic.jpg', $tmpname); + copy(__DIR__ . '/../../../../../files/iphone_pic.jpg', $tmpname); $file = File::buildFromPathfile($tmpname, self::$DI['collection'], self::$DI['app']); self::$DI['app']['border-manager']->process($lazaretSession, $file, $callback, Manager::FORCE_LAZARET); @@ -2030,7 +1829,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase protected function getAddRecordFile() { $file = tempnam(sys_get_temp_dir(), 'upload'); - copy(__DIR__ . '/../../../../files/iphone_pic.jpg', $file); + copy(__DIR__ . '/../../../../../files/iphone_pic.jpg', $file); return [ 'file' => new \Symfony\Component\HttpFoundation\File\UploadedFile($file, 'upload.jpg') @@ -2430,7 +2229,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase $this->assertArrayHasKey('thumbnail', $story); $this->assertArrayHasKey('uuid', $story); $this->assertArrayHasKey('@entity@', $story); - $this->assertEquals(\API_V1_adapter::OBJECT_TYPE_STORY, $story['@entity@']); + $this->assertEquals(V1::OBJECT_TYPE_STORY, $story['@entity@']); $this->assertTrue(\uuid::is_valid($story['uuid'])); if ( ! is_null($story['thumbnail'])) { @@ -2463,7 +2262,7 @@ abstract class ApiTestCase extends \PhraseanetWebTestCase } $this->assertArrayHasKey('@entity@', $story['metadatas']); - $this->assertEquals(\API_V1_adapter::OBJECT_TYPE_STORY_METADATA_BAG, $story['metadatas']['@entity@']); + $this->assertEquals(V1::OBJECT_TYPE_STORY_METADATA_BAG, $story['metadatas']['@entity@']); foreach ($story['records'] as $record) { $this->evaluateGoodRecord($record); diff --git a/tests/Alchemy/Tests/Phrasea/Application/ApiYamlTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiYamlTest.php similarity index 88% rename from tests/Alchemy/Tests/Phrasea/Application/ApiYamlTest.php rename to tests/Alchemy/Tests/Phrasea/Controller/Api/ApiYamlTest.php index 0ec269048f..d9bfd48eb5 100644 --- a/tests/Alchemy/Tests/Phrasea/Application/ApiYamlTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Api/ApiYamlTest.php @@ -1,6 +1,6 @@ 'application/json', + 'REQUEST_METHOD' => 'GET', + 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename', + 'REQUEST_URI' => 'my/base/path/my/request/uri', + 'PHP_SELF' => 'my/base/path', + ]; + $request = new Request(["callback" => ""], [], [], [], [], $server); + + $apiResult = new Result($request); + $return = $apiResult->createResponse()->getContent(); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $return); + $response = json_decode($return); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response); + $this->assertObjectHasAttribute("meta", $response); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response->meta); + $this->assertObjectHasAttribute("response", $response); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response->response); + $this->assertEquals(0, sizeof(get_object_vars($response->response))); + $this->assertEquals(0, sizeof(get_class_methods($response->response))); + $this->checkResponseFieldMeta($response, "api_version", V1::VERSION, \PHPUnit_Framework_Constraint_IsType::TYPE_STRING); + $this->checkResponseFieldMeta($response, "request", "GET my/base/path/my/request/uri", \PHPUnit_Framework_Constraint_IsType::TYPE_STRING); + + $date = new \DateTime(); + $now = $date->format('U'); + + $dateQuery = \DateTime::createFromFormat(DATE_ATOM, $response->meta->response_time); + $nowQuery = $dateQuery->format('U'); + + $this->assertLessThan(1, $nowQuery - $now); + + $this->assertDateAtom($response->meta->response_time); + $date = new \DateTime(); + $nowU = $date->format('U'); + $dateResp = \DateTime::createFromFormat(DATE_ATOM, $response->meta->response_time); + $respU = $dateResp->format('U'); + + $this->assertLessThan(3, abs($respU - $nowU), 'No more than 3sec between now and the query'); + + $this->checkResponseFieldMeta($response, "http_code", 200, \PHPUnit_Framework_Constraint_IsType::TYPE_INT); + $this->checkResponseFieldMeta($response, "charset", "UTF-8", \PHPUnit_Framework_Constraint_IsType::TYPE_STRING); + $this->assertObjectHasAttribute("error_message", $response->meta); + $this->assertNull($response->meta->error_message); + $this->assertObjectHasAttribute("error_details", $response->meta); + $this->assertNull($response->meta->error_details); + } + + public function testFormatYaml() + { + $server = [ + 'HTTP_ACCEPT' => 'application/yaml', + 'REQUEST_METHOD' => 'GET', + 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename', + 'REQUEST_URI' => 'my/base/path/my/request/uri', + 'PHP_SELF' => 'my/base/path', + ]; + $request = new Request(["callback" => ""], [], [], [], [], $server); + + $apiResult = new Result($request); + $response = (new Parser())->parse($apiResult->createResponse()->getContent()); + + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response); + $this->assertArrayHasKey("meta", $response); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response["meta"]); + $this->assertArrayHasKey("response", $response); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response["response"]); + $this->assertEquals(0, count($response["response"])); + $this->assertArrayHasKey("api_version", $response["meta"]); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["api_version"]); + $this->assertEquals(V1::VERSION, $response["meta"]["api_version"]); + $this->assertArrayHasKey("request", $response["meta"]); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["request"]); + $this->assertEquals("GET my/base/path/my/request/uri", $response["meta"]["request"]); + $this->assertArrayHasKey("response_time", $response["meta"]); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["response_time"]); + + $this->assertDateAtom($response["meta"]["response_time"]); + $dateObj1 = \DateTime::createFromFormat(DATE_ATOM, $response["meta"]["response_time"]); + $dateObj2 = new \DateTime(); + $this->assertLessThan(3, abs($dateObj1->format('U') - $dateObj2->format('U')), 'No more than 3sec between now and the query'); + + $this->assertArrayHasKey("http_code", $response["meta"]); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_INT, $response["meta"]["http_code"]); + $this->assertEquals(200, $response["meta"]["http_code"]); + $this->assertArrayHasKey("error_message", $response["meta"]); + $this->assertNull($response["meta"]["error_message"]); + $this->assertArrayHasKey("error_details", $response["meta"]); + $this->assertNull($response["meta"]["error_details"]); + $this->assertArrayHasKey("charset", $response["meta"]); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["charset"]); + $this->assertEquals("UTF-8", $response["meta"]["charset"]); + } + + public function testFormatJsonP() + { + $request = new Request(["callback" => "my_callback_function"], [], [], [], [], ["HTTP_ACCEPT" => "application/yaml"]); + $apiResult = new Result($request); + $return = $apiResult->createResponse()->getContent(); + $this->assertInternalType(\PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $return); + $this->assertRegexp("/my_callback_function\\(\\{.+\\}\\)/", $return); + $response = json_decode(substr($return, 21, strlen($return) - 22), true); + $this->assertSame([], $response['response']); + } + + public function testData() + { + $apiResult = new Result(new Request(), ["pirouette" => "cacahuete", "black" => true, "bob" => ["bob"]]); + $response = json_decode($apiResult->createResponse()->getContent()); + $this->checkResponseFieldResponse($response, "pirouette", "cacahuete", \PHPUnit_Framework_Constraint_IsType::TYPE_STRING); + $this->checkResponseFieldResponse($response, "black", true, \PHPUnit_Framework_Constraint_IsType::TYPE_BOOL); + $this->checkResponseFieldResponse($response, "bob", ["bob"], \PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY); + } + + public function testEmptyData() + { + $apiResult = new Result(new Request(), []); + $content = json_decode($apiResult->createResponse()->getContent(), true); + + $this->assertSame(array(), $content['response']); + } + + public function testContentType() + { + $server = ["HTTP_ACCEPT" => "application/json"]; + $request = new Request(["callback" => ""], [], [], [], [], $server); + $apiResult = new Result($request); + $this->assertEquals("application/json", $apiResult->createResponse()->headers->get('content-type')); + + $server = ["HTTP_ACCEPT" => "application/yaml"]; + $request = new Request(["callback" => ""], [], [], [], [], $server); + $apiResult = new Result($request); + $this->assertEquals('application/yaml', $apiResult->createResponse()->headers->get('content-type')); + + $server = ["HTTP_ACCEPT" => "text/yaml"]; + $request = new Request(["callback" => ""], [], [], [], [], $server); + $apiResult = new Result($request); + $this->assertEquals('application/yaml', $apiResult->createResponse()->headers->get('content-type')); + + $server = ["HTTP_ACCEPT" => ""]; + $request = new Request(["callback" => "hello"], [], [], [], [], $server); + $apiResult = new Result($request); + $this->assertEquals('text/javascript', $apiResult->createResponse()->headers->get('content-type')); + + $server = ["HTTP_ACCEPT" => "unknow"]; + $request = new Request(["callback" => ""], [], [], [], [], $server); + $apiResult = new Result($request); + $this->assertEquals("application/json", $apiResult->createResponse()->headers->get('content-type')); + } + + public function testConstructor() + { + $apiResult = new Result(new Request(), [], 400, 'type', Result::ERROR_BAD_REQUEST, 'details'); + $this->assertErrorMessage($apiResult, 400, 'type', Result::ERROR_BAD_REQUEST, 'details'); + + $apiResult = new Result(new Request(), [], 401, 'type', Result::ERROR_UNAUTHORIZED, 'details'); + $this->assertErrorMessage($apiResult, 401, 'type', Result::ERROR_UNAUTHORIZED, 'details'); + + $apiResult = new Result(new Request(), [], 403, 'type', Result::ERROR_FORBIDDEN, 'details'); + $this->assertErrorMessage($apiResult, 403, 'type', Result::ERROR_FORBIDDEN, 'details'); + + $apiResult = new Result(new Request(), [], 404, 'type', Result::ERROR_NOTFOUND, 'details'); + $this->assertErrorMessage($apiResult, 404, 'type', Result::ERROR_NOTFOUND, 'details'); + + $apiResult = new Result(new Request(), [], 405, 'type', Result::ERROR_METHODNOTALLOWED, 'details'); + $this->assertErrorMessage($apiResult, 405, 'type', Result::ERROR_METHODNOTALLOWED, 'details'); + + $apiResult = new Result(new Request(), [], 500, 'type', Result::ERROR_INTERNALSERVERERROR, 'details'); + $this->assertErrorMessage($apiResult, 500, 'type', Result::ERROR_INTERNALSERVERERROR, 'details'); + } + + public function testCreateError() + { + $apiResult = Result::createError(new Request(), 400, 'detaillage'); + $this->assertErrorMessage($apiResult, 400, Result::ERROR_BAD_REQUEST, 'Parameter is invalid or missing', 'detaillage'); + + $apiResult = Result::createError(new Request(), 401, 'detaillage'); + $this->assertErrorMessage($apiResult, 401, Result::ERROR_UNAUTHORIZED, 'The OAuth token was provided but was invalid.', 'detaillage'); + + $apiResult = Result::createError(new Request(), 403, 'detaillage'); + $this->assertErrorMessage($apiResult, 403, Result::ERROR_FORBIDDEN, 'Access to the requested resource is forbidden', 'detaillage'); + + $apiResult = Result::createError(new Request(), 404, 'detaillage'); + $this->assertErrorMessage($apiResult, 404, Result::ERROR_NOTFOUND, 'Requested resource is not found', 'detaillage'); + + $apiResult = Result::createError(new Request(), 405, 'detaillage'); + $this->assertErrorMessage($apiResult, 405, Result::ERROR_METHODNOTALLOWED, 'Attempting to use POST with a GET-only endpoint, or vice-versa', 'detaillage'); + + $apiResult = Result::createError(new Request(), 500, 'detaillage'); + $this->assertErrorMessage($apiResult, 500, Result::ERROR_INTERNALSERVERERROR, 'Internal Server Error', 'detaillage'); + } + + private function checkResponseFieldMeta(\stdClass $response, $field, $expectedValue, $type) + { + $this->assertObjectHasAttribute($field, $response->meta); + $this->assertInternalType($type, $response->meta->$field); + $this->assertEquals($expectedValue, $response->meta->$field); + } + + private function checkResponseFieldResponse(\stdClass $response, $field, $expectedValue, $type) + { + $this->assertObjectHasAttribute($field, $response->response); + $this->assertInternalType($type, $response->response->$field); + $this->assertEquals($expectedValue, $response->response->$field); + } + + private function assertErrorMessage(Result $apiResult, $code, $type, $message, $detail) + { + $response = json_decode($apiResult->createResponse()->getContent()); + $this->checkResponseFieldMeta($response, 'http_code', $code, \PHPUnit_Framework_Constraint_IsType::TYPE_INT); + + if (is_null($type)) { + $this->assertObjectHasAttribute('error_type', $response->meta); + $this->assertNull($response->meta->error_type); + } else { + $this->checkResponseFieldMeta($response, 'error_type', $type, \PHPUnit_Framework_Constraint_IsType::TYPE_STRING); + } + + if (is_null($message)) { + $this->assertObjectHasAttribute('error_message', $response->meta); + $this->assertNull($response->meta->error_message); + } else { + $this->checkResponseFieldMeta($response, 'error_message', $message, \PHPUnit_Framework_Constraint_IsType::TYPE_STRING); + } + + if (is_null($detail)) { + $this->assertObjectHasAttribute('error_details', $response->meta); + $this->assertNull($response->meta->error_details); + } else { + $this->checkResponseFieldMeta($response, 'error_details', $detail, \PHPUnit_Framework_Constraint_IsType::TYPE_STRING); + } + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml index 56273b61a5..104c4837e4 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml +++ b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml @@ -16,7 +16,6 @@ main: driver: pdo_sqlite path: '/tmp/db.sqlite' charset: UTF8 - api-timers: false cache: type: MemcacheCache options: diff --git a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml index 56273b61a5..104c4837e4 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml +++ b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml @@ -16,7 +16,6 @@ main: driver: pdo_sqlite path: '/tmp/db.sqlite' charset: UTF8 - api-timers: false cache: type: MemcacheCache options: diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php index c911fb6dd8..729cabd3c9 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php @@ -5,8 +5,11 @@ namespace Alchemy\Tests\Phrasea\Core\Event\Subscriber; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber; use Symfony\Component\HttpKernel\Client; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException; class ApiExceptionHandlerSubscriberTest extends \PhraseanetTestCase { @@ -16,10 +19,6 @@ class ApiExceptionHandlerSubscriberTest extends \PhraseanetTestCase public function testError($exception, $code) { $app = new Application('test'); - $app['api'] = function () use ($app) { - return new \API_V1_adapter($app); - }; - $app->register(new \API_V1_Timer()); $app['dispatcher']->addSubscriber(new ApiExceptionHandlerSubscriber($app)); $app->get('/', function () use ($exception) { throw $exception; @@ -35,13 +34,11 @@ class ApiExceptionHandlerSubscriberTest extends \PhraseanetTestCase public function provideExceptionsAndCode() { return [ - [new \API_V1_exception_methodnotallowed(), 405], [new MethodNotAllowedHttpException(['PUT', 'HEAD']), 405], - [new \API_V1_exception_badrequest(), 400], - [new \API_V1_exception_forbidden(), 403], - [new \API_V1_exception_unauthorized(), 401], - [new \API_V1_exception_internalservererror(), 500], [new NotFoundHttpException(), 404], + [new BadRequestHttpException(), 400], + [new AccessDeniedHttpException(), 403], + [new UnauthorizedHttpException('challenge'), 401], [new \Exception(), 500], ]; } diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriberTest.php index 7f8f530d99..a53e2d1b68 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriberTest.php +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriberTest.php @@ -18,10 +18,6 @@ class ApiOauth2ErrorsSubscriberTest extends \PhraseanetTestCase public function testError($exception, $code, $contentType) { $app = new Application('test'); - $app['api'] = function () use ($app) { - return new \API_V1_adapter($app); - }; - $app->register(new \API_V1_Timer()); $app['dispatcher']->addSubscriber(new ApiOauth2ErrorsSubscriber(PhraseaExceptionHandler::register(), $this->createTranslatorMock())); $app->get('/api/oauthv2', function () use ($exception) { throw $exception; @@ -41,10 +37,6 @@ class ApiOauth2ErrorsSubscriberTest extends \PhraseanetTestCase { $app = new Application('test'); unset($app['exception_handler']); - $app['api'] = function () use ($app) { - return new \API_V1_adapter($app); - }; - $app->register(new \API_V1_Timer()); $app['dispatcher']->addSubscriber(new ApiOauth2ErrorsSubscriber(PhraseaExceptionHandler::register(), $this->createTranslatorMock())); $app->get('/', function () use ($exception) { throw $exception; diff --git a/tests/classes/Session/LoggerTest.php b/tests/classes/Session/LoggerTest.php index f1d39a22b3..863bf51a59 100644 --- a/tests/classes/Session/LoggerTest.php +++ b/tests/classes/Session/LoggerTest.php @@ -1,6 +1,6 @@ loadApp(); - $dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface'); - $dispatcher->expects($this->exactly(9)) - ->method('addListener'); - $app['dispatcher'] = $dispatcher; - $app->register(new API_V1_Timer()); - - $this->assertInstanceOf('Doctrine\Common\Collections\ArrayCollection', $app['api.timers']); - $this->assertGreaterThan($start, $app['api.timers.start']); - } - - public function testTriggerEvent() - { - $app = $this->loadApp(); - $app->register(new API_V1_Timer()); - - $app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new Event()); - - $timers = $app['api.timers']->toArray(); - - $this->assertCount(1, $timers); - - $timer = array_pop($timers); - - $this->assertArrayHasKey('name', $timer); - $this->assertArrayHasKey('memory', $timer); - $this->assertArrayHasKey('time', $timer); - - $this->assertEquals(PhraseaEvents::API_RESULT, $timer['name']); - $this->assertGreaterThan(0, $timer['time']); - $this->assertGreaterThan(400000, $timer['memory']); - } -} diff --git a/tests/classes/api/v1/adapterTest.php b/tests/classes/api/v1/adapterTest.php deleted file mode 100644 index b839f7c0b9..0000000000 --- a/tests/classes/api/v1/adapterTest.php +++ /dev/null @@ -1,656 +0,0 @@ -register(new \API_V1_Timer()); - $this->object = new API_V1_adapter(self::$DI['app']); - } - - public function testGet_error_code() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_error_code($request, 400); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(400, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_code($request, 403); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(403, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_code($request, 500); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(500, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_code($request, 405); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(405, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_code($request, 404); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(404, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_code($request, 401); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(401, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - } - - public function testGet_error_message() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_error_message($request, API_V1_result::ERROR_BAD_REQUEST, 'detaillage'); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(400, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_message($request, API_V1_result::ERROR_FORBIDDEN, 'detaillage'); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(403, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_message($request, API_V1_result::ERROR_INTERNALSERVERERROR, 'detaillage'); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(500, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_message($request, API_V1_result::ERROR_METHODNOTALLOWED, 'detaillage'); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(405, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_message($request, API_V1_result::ERROR_NOTFOUND, 'detaillage'); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(404, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - - $result = $this->object->get_error_message($request, API_V1_result::ERROR_UNAUTHORIZED, 'detaillage'); - $this->assertTrue(is_array(json_decode($result->format(), true))); - $this->assertEquals(401, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - } - - public function testGet_version() - { - $this->assertEquals('1.3', $this->object->get_version()); - } - - public function testGet_databoxes() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_databoxes($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - - public function testGet_databox_collections() - { - $request = new Request(); - foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { - $result = $this->object->get_databox_collections($request, $databox->get_sbas_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - } - - public function testGet_record() - { - - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_record($request, self::$DI['record_1']->get_sbas_id(), "-40"); - $this->assertEquals(400, $result->get_http_code()); - - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_record($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - - public function testGet_databox_status() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { - $result = $this->object->get_databox_status($request, $databox->get_sbas_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - } - - public function testGet_databox_metadatas() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { - $result = $this->object->get_databox_metadatas($request, $databox->get_sbas_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - } - - public function testGet_databox_terms() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - foreach (self::$DI['app']['phraseanet.appbox']->get_databoxes() as $databox) { - $result = $this->object->get_databox_terms($request, $databox->get_sbas_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - } - - public function testSearch_recordsWithRecords() - { - $this->authenticate(self::$DI['app']); - - $record = \record_adapter::createFromFile(BorderFile::buildFromPathfile(__DIR__ . '/../../../files/cestlafete.jpg', self::$DI['collection'], self::$DI['app']), self::$DI['app']); - - $request = new Request(['record_type' => "image", 'search_type' => 0], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->search_records($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $data = json_decode($result->format(), true); - - $found = false; - foreach ($data['response']['results'] as $retRecord) { - if ($retRecord['record_id'] == $record->get_record_id() && $retRecord['databox_id'] == $record->get_sbas_id()) { - $found = true; - break; - } - } - - if (!$found) { - $this->fail('unable to find the record back'); - } - } - - public function testSearch_withOffset() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->search_records($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $data = json_decode($result->format(), true); - - if ($data['response']['total_results'] < 2) { - $this->markTestSkipped('Not enough data to test'); - } - - $total = $data['response']['total_results']; - - $request = new Request([ - 'offset_start' => 0, - 'per_page' => 1, - ], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $resultData1 = $this->object->search_records($request); - - $data = json_decode($resultData1->format(), true); - - $this->assertCount(1, $data['response']['results']); - $result1 = array_pop($data['response']['results']); - - $request = new Request([ - 'offset_start' => 1, - 'per_page' => 1, - ], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $resultData2 = $this->object->search_records($request); - - $data = json_decode($resultData2->format(), true); - - $this->assertCount(1, $data['response']['results']); - $result2 = array_pop($data['response']['results']); - - // item at offset #0 is different than offset at item #1 - $this->assertNotEquals($result1['record_id'], $result2['record_id']); - - // last item is last item - $request = new Request([ - 'offset_start' => $total - 1, - 'per_page' => 10, - ], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $resultData = $this->object->search_records($request); - - $data = json_decode($resultData->format(), true); - - $this->assertCount(1, $data['response']['results']); - } - - public function testSearch_recordsWithStories() - { - $this->authenticate(self::$DI['app']); - - $story = \record_adapter::createStory(self::$DI['app'], self::$DI['collection']); - - if (!$story->hasChild(self::$DI['record_1'])) { - $story->appendChild(self::$DI['record_1']); - } - - $request = new Request(['search_type' => 1], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->search_records($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $data = json_decode($result->format(), true); - - $found = false; - - foreach ($data['response']['results'] as $retStory) { - if ($retStory['record_id'] == $story->get_record_id() && $retStory['databox_id'] == $story->get_sbas_id()) { - $found = true; - break; - } - } - - if (!$found) { - $this->fail('unable to find the story back'); - } - } - - public function testSearchWithStories() - { - $this->authenticate(self::$DI['app']); - - $story = \record_adapter::createStory(self::$DI['app'], self::$DI['collection']); - - if (!$story->hasChild(self::$DI['record_1'])) { - $story->appendChild(self::$DI['record_1']); - } - - $request = new Request(['search_type' => 1], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->search($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $data = json_decode($result->format(), true); - - $this->assertArrayHasKey('records', $data['response']['results']); - $this->assertArrayHasKey('stories', $data['response']['results']); - - $found = false; - - foreach ($data['response']['results']['stories'] as $retStory) { - if ($retStory['story_id'] == $story->get_record_id() && $retStory['databox_id'] == $story->get_sbas_id()) { - $found = true; - break; - } - } - - if (!$found) { - $this->fail('unable to find the story back'); - } - } - - public function testSearchWithRecords() - { - $this->authenticate(self::$DI['app']); - - $record = \record_adapter::createFromFile(BorderFile::buildFromPathfile(__DIR__ . '/../../../files/cestlafete.jpg', self::$DI['collection'], self::$DI['app']), self::$DI['app']); - - $request = new Request(['search_type' => 0], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->search($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $data = json_decode($result->format(), true); - - $this->assertArrayHasKey('records', $data['response']['results']); - $this->assertArrayHasKey('stories', $data['response']['results']); - - $found = false; - - foreach ($data['response']['results']['records'] as $retRecord) { - if ($retRecord['record_id'] == $record->get_record_id() && $retRecord['databox_id'] == $record->get_sbas_id()) { - $found = true; - break; - } - } - - if (!$found) { - $this->fail('unable to find the record back'); - } - } - - public function testGet_record_related() - { - $basketElement = self::$DI['app']['EM']->find('Phraseanet:BasketElement', 1); - $story = self::$DI['record_story_1']; - if (false === $story->hasChild(self::$DI['record_1'])) { - $story->appendChild(self::$DI['record_1']); - } - - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_record_related($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $data = json_decode($result->format(), true); - - $this->assertArrayHasKey('baskets', $data['response']); - $this->assertArrayHasKey('stories', $data['response']); - - $found = false; - foreach ($data['response']['baskets'] as $bask) { - if ($bask['basket_id'] == $basketElement->getBasket()->getId()) { - $found = true; - break; - } - } - - if (!$found) { - $this->fail('unable to find the basket back'); - } - - $found = false; - foreach ($data['response']['stories'] as $retStory) { - if ($retStory['story_id'] == $story->get_record_id() && $retStory['databox_id'] == $story->get_sbas_id()) { - $found = true; - break; - } - } - - if (!$found) { - $this->fail('unable to find the story back'); - } - } - - public function testGet_record_metadatas() - { - - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_record_metadatas($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - - public function testGet_record_status() - { - - $request = new Request(); - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_record_status($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - - public function testGet_record_embed() - { - - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_record_embed($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - - public function testSet_record_metadatas() - { - $databox = self::$DI['record_1']->get_databox(); - $request = new Request(["salut" => "salut c'est la fete"], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->set_record_metadatas($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(400, $result->get_http_code()); - - $request = new Request(["metadatas" => "salut c'est la fete"], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $this->object->set_record_metadatas($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(400, $result->get_http_code()); - - if (sizeof(self::$DI['record_1']->get_caption()->get_fields()) == 0) { - $caption_field_value = caption_Field_Value::create(self::$DI['app'], databox_field::get_instance(self::$DI['app'], $databox, 1), self::$DI['record_1'], 'my value'); - } - - $metadatas = []; - - foreach (self::$DI['record_1']->get_databox()->get_meta_structure()->get_elements() as $field) { - try { - $values = self::$DI['record_1']->get_caption()->get_field($field->get_name())->get_values(); - $value = array_pop($values); - $meta_id = $value->getId(); - } catch (\Exception $e) { - $meta_id = null; - } - - $metadatas[] = [ - 'meta_id' => $meta_id - , 'meta_struct_id' => $field->get_id() - , 'value' => 'poOM POOM TCHOK ' . $field->get_id() - ]; - } - - $request = new Request(["metadatas" => $metadatas], [], [], [], [], ['HTTP_Accept' => 'application/json']); - - $result = $this->object->set_record_metadatas($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - - $response = json_decode($result->format(), true); - - $this->assertEquals($response['meta']['http_code'], 200); - - $this->checkResponseField($result, "record_metadatas", 'array'); - } - - public function testSet_record_status() - { - $app = self::$DI['app']; - $stub = $this->getMock("API_V1_adapter", ["list_record_status"], [$app]); - $databox = self::$DI['record_1']->get_databox(); - - $statusbit = null; - foreach ($databox->get_statusbits() as $key => $value) { - $statusbit = $key; - break; - } - - if (null === $statusbit) { - $this->markTestSkipped('No status bit defined in databox'); - } - - $request = new Request(["salut" => "salut c'est la fete"], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $stub->set_record_status($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(400, $result->get_http_code()); - - $request = new Request(["status" => "salut c'est la fete"], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $stub->set_record_status($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(400, $result->get_http_code()); - - $status = [$statusbit => '1']; - - $request = new Request(["status" => $status], [], [], [], [], ['HTTP_Accept' => 'application/json']); - //check method use record->get_caption - $stub->expects($this->once()) - ->method("list_record_status") - ->will($this->returnValue(new stdClass())); - //check for metadas fiels in response - $result = $stub->set_record_status($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->checkResponseField($result, "status", 'array'); - } - - public function testSet_record_collection() - { - $app = self::$DI['app']; - $stub = $this->getMock("API_V1_adapter", ["list_record"], [$app]); - $databox = self::$DI['record_1']->get_databox(); - - $request = new Request(["salut" => "salut c'est la fete"], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $stub->set_record_collection($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->assertEquals(400, $result->get_http_code()); - - foreach ($app['phraseanet.appbox']->get_databoxes() as $databox) { - $collections = $databox->get_collections(); - break; - } - - $collection = array_shift($collections); - - $request = new Request(["base_id" => $collection->get_base_id()], [], [], [], [], ['HTTP_Accept' => 'application/json']); - //check method use record->get_caption - $stub->expects($this->once()) - ->method("list_record") - ->will($this->returnValue(new stdClass())); - //check for metadas fiels in response - $result = $stub->set_record_collection($request, self::$DI['record_1']->get_sbas_id(), self::$DI['record_1']->get_record_id()); - $this->checkResponseField($result, "record", 'array'); - } - - /** - * @todo Implement testAdd_record_tobasket(). - */ - public function testAdd_record_tobasket() - { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); - } - - public function testSearch_baskets() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->search_baskets($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - - public function testCreate_basket() - { - $request = new Request([], [], ['name' => 'BIG BASKET'], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->create_basket($request); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $n = 0; - $response = json_decode($result->format(), true); - $this->assertArrayHasKey('basket', $response['response']); - - $basket = self::$DI['app']['converter.basket']->convert($response['response']['basket']['basket_id']); - self::$DI['app']['acl.basket']->isOwner($basket, self::$DI['app']['authentication']->getUser()); - } - - public function testDelete_basket() - { - $Basket = self::$DI['app']['EM']->find('Phraseanet:Basket', 1); - - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->delete_basket($request, $Basket); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $this->setExpectedException('Symfony\Component\HttpKernel\Exception\NotFoundHttpException'); - self::$DI['app']['converter.basket']->convert($Basket->getId()); - } - - public function testGet_basket() - { - $basket = self::$DI['app']['EM']->find('Phraseanet:Basket', 1); - - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->get_basket($request, $basket); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - } - - public function testSet_basket_title() - { - $basket = self::$DI['app']['EM']->find('Phraseanet:Basket', 1); - - $request = new Request([], [], ['name' => 'PROUTO'], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->set_basket_title($request, $basket); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $repository = self::$DI['app']['EM']->getRepository('Phraseanet:Basket'); - - $ret_bask = $repository->find($basket->getId()); - - $this->assertEquals('PROUTO', $ret_bask->getName()); - } - - public function testSet_basket_description() - { - $basket = self::$DI['app']['EM']->find('Phraseanet:Basket', 1); - - $request = new Request([], [], ['description' => 'une belle description'], [], [], ['HTTP_Accept' => 'application/json']); - $result = $this->object->set_basket_description($request, $basket); - $this->assertEquals(200, $result->get_http_code()); - $this->assertEquals('application/json', $result->get_content_type()); - $this->assertTrue(is_array(json_decode($result->format(), true))); - - $repository = self::$DI['app']['EM']->getRepository('Phraseanet:Basket'); - - $ret_bask = $repository->find($basket->getId()); - - $this->assertEquals('une belle description', $ret_bask->getDescription()); - } - - public function testSearch_publications() - { - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - $feed = self::$DI['app']['EM']->find('Phraseanet:Feed', 1); - $result = $this->object->search_publications($request, self::$DI['user']); - $this->checkResponseField($result, "feeds", 'array'); - } - - public function testRemove_publications() - { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); - } - - public function testGet_publication() - { - self::$DI['app']['notification.deliverer'] = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer') - ->disableOriginalConstructor() - ->getMock(); - - $date = new DateTime(); - $request = new Request([], [], [], [], [], ['HTTP_Accept' => 'application/json']); - - $feeds = self::$DI['app']['EM']->getRepository('Phraseanet:Feed')->getAllForUser(self::$DI['app']['acl']->get(self::$DI['user'])); - foreach ($feeds as $feed) { - $result = $this->object->get_publication($request, $feed->getId(), self::$DI['user']); - $this->checkResponseField($result, "feed", 'array'); - $this->checkResponseField($result, "entries", 'array'); - $this->checkResponseField($result, "offset_start", 'integer'); - $this->checkResponseField($result, "per_page", 'integer'); - } - } - - private function checkResponseField(API_V1_result $result, $field, $type) - { - $response = json_decode($result->format(), true); - $this->assertArrayHasKey($field, $response['response']); - $this->assertInternalType($type, $response['response'][$field]); - } -} diff --git a/tests/classes/api/v1/resultTest.php b/tests/classes/api/v1/resultTest.php deleted file mode 100644 index 168327f126..0000000000 --- a/tests/classes/api/v1/resultTest.php +++ /dev/null @@ -1,428 +0,0 @@ -register(new \API_V1_Timer()); - self::$DI['app']['conf']->set(['main', 'api-timers'], true); - - $this->api = $this->getMock("API_V1_adapter", ["get_version"], [], "", false); - $this->api->expects($this->any())->method("get_version")->will($this->returnValue("my_super_version1.0")); - } - - private function assertIsTimer($timer) - { - $this->assertObjectHasAttribute('name', $timer); - $this->assertObjectHasAttribute('memory', $timer); - $this->assertObjectHasAttribute('time', $timer); - } - - public function testFormatJson() - { - $server = [ - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $return = $api_result->format(); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $return); - $response = json_decode($return); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response); - $this->assertObjectHasAttribute("meta", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response->meta); - $this->assertObjectHasAttribute("response", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_OBJECT, $response->response); - $this->assertEquals(0, sizeof(get_object_vars($response->response))); - $this->assertEquals(0, sizeof(get_class_methods($response->response))); - $this->checkResponseFieldMeta($response, "api_version", "my_super_version1.0", PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - $this->checkResponseFieldMeta($response, "request", "GET my/base/path/my/request/uri", PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - - $this->assertObjectHasAttribute("timers", $response); - $this->assertCount(1, $response->timers); - - foreach ($response->timers as $timer) { - $this->assertIsTimer($timer); - } - - $date = new \DateTime(); - $now = $date->format('U'); - - $date_query = \DateTime::createFromFormat(DATE_ATOM, $response->meta->response_time); - $now_query = $date_query->format('U'); - - $this->assertLessThan(1, $now_query - $now); - - $this->assertDateAtom($response->meta->response_time); - $date = new DateTime(); - $now_U = $date->format('U'); - $date_resp = DateTime::createFromFormat(DATE_ATOM, $response->meta->response_time); - $resp_U = $date_resp->format('U'); - - $this->assertLessThan(3, abs($resp_U - $now_U), 'No more than 3sec between now and the query'); - - $this->checkResponseFieldMeta($response, "http_code", 200, PHPUnit_Framework_Constraint_IsType::TYPE_INT); - $this->checkResponseFieldMeta($response, "charset", "UTF-8", PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - $this->assertObjectHasAttribute("error_message", $response->meta); - $this->assertNull($response->meta->error_message); - $this->assertObjectHasAttribute("error_details", $response->meta); - $this->assertNull($response->meta->error_details); - - $this->assertObjectHasAttribute("timers", $response); - $this->assertCount(1, $response->timers); - - foreach ($response->timers as $timer) { - $this->assertIsTimer($timer); - } - } - - public function testFormatYaml() - { - $server = [ - "HTTP_ACCEPT" => "application/yaml" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $return = $api_result->format(); - $sfYaml = new Symfony\Component\Yaml\Parser(); - $response = $sfYaml->parse($return); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response); - $this->assertArrayHasKey("meta", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response["meta"]); - $this->assertArrayHasKey("response", $response); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY, $response["response"]); - $this->assertEquals(0, count($response["response"])); - $this->assertArrayHasKey("api_version", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["api_version"]); - $this->assertEquals("my_super_version1.0", $response["meta"]["api_version"]); - $this->assertArrayHasKey("request", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["request"]); - $this->assertEquals("GET my/base/path/my/request/uri", $response["meta"]["request"]); - $this->assertArrayHasKey("response_time", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["response_time"]); - - $this->assertDateAtom($response["meta"]["response_time"]); - $date_obj1 = DateTime::createFromFormat(DATE_ATOM, $response["meta"]["response_time"]); - $date_obj2 = new DateTime(); - $this->assertLessThan(3, abs($date_obj1->format('U') - $date_obj2->format('U')), 'No more than 3sec between now and the query'); - - $this->assertArrayHasKey("http_code", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_INT, $response["meta"]["http_code"]); - $this->assertEquals(200, $response["meta"]["http_code"]); - $this->assertArrayHasKey("error_message", $response["meta"]); - $this->assertNull($response["meta"]["error_message"]); - $this->assertArrayHasKey("error_details", $response["meta"]); - $this->assertNull($response["meta"]["error_details"]); - $this->assertArrayHasKey("charset", $response["meta"]); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $response["meta"]["charset"]); - $this->assertEquals("UTF-8", $response["meta"]["charset"]); - - $this->assertArrayHasKey("timers", $response); - $this->assertCount(1, $response['timers']); - } - - public function testFormatJsonP() - { - $server = [ - "HTTP_ACCEPT" => "application/yaml" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ]; - $request = new Request(["callback" => "my_callback_function"], [], [], [], [], $server); - - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $return = $api_result->format(); - $this->assertInternalType(PHPUnit_Framework_Constraint_IsType::TYPE_STRING, $return); - $this->assertRegexp("/my_callback_function\(\{.+\}\)/", $return); - $response = json_decode(substr($return, 21, strlen($return) - 22)); - - $this->assertObjectHasAttribute("timers", $response); - $this->assertCount(1, $response->timers); - - foreach ($response->timers as $timer) { - $this->assertIsTimer($timer); - } - } - - /** - * @depends testFormatJson - */ - public function testSet_datas() - { - $server = [ - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $api_result->set_datas(["pirouette" => "cacahuete", "black" => true, "bob" => ["bob"]]); - $response = json_decode($api_result->format()); - $this->checkResponseFieldResponse($response, "pirouette", "cacahuete", PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - $this->checkResponseFieldResponse($response, "black", true, PHPUnit_Framework_Constraint_IsType::TYPE_BOOL); - $this->checkResponseFieldResponse($response, "bob", ["bob"], PHPUnit_Framework_Constraint_IsType::TYPE_ARRAY); - } - - public function testGet_datas() - { - $server = [ - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - - $data = ["pirouette" => "cacahuete", "black" => true, "bob" => ["bob"]]; - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $api_result->set_datas($data); - - $this->assertEquals($data, $api_result->get_datas()); - } - - public function testGet_Emptydatas() - { - $server = [ - "HTTP_ACCEPT" => "application/json" - , 'REQUEST_METHOD' => 'GET' - , 'SCRIPT_FILENAME' => 'my/base/path/my/request/uri/filename' - , "REQUEST_URI" => "my/base/path/my/request/uri" - , 'PHP_SELF' => 'my/base/path' - ]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - - $data = []; - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $api_result->set_datas($data); - - $this->assertEquals($data, $api_result->get_datas()); - } - - private function checkResponseFieldMeta(stdClass $response, $field, $expected_value, $type) - { - $this->assertObjectHasAttribute($field, $response->meta); - $this->assertInternalType($type, $response->meta->$field); - $this->assertEquals($expected_value, $response->meta->$field); - } - - private function checkResponseFieldResponse(stdClass $response, $field, $expected_value, $type) - { - $this->assertObjectHasAttribute($field, $response->response); - $this->assertInternalType($type, $response->response->$field); - $this->assertEquals($expected_value, $response->response->$field); - } - - public function testGet_content_type() - { - $server = ["HTTP_ACCEPT" => "application/json"]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals("application/json", $api_result->get_content_type()); - - $server = ["HTTP_ACCEPT" => "application/yaml"]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals('application/yaml', $api_result->get_content_type()); - - $server = ["HTTP_ACCEPT" => "text/yaml"]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals('application/yaml', $api_result->get_content_type()); - - $server = ["HTTP_ACCEPT" => ""]; - $request = new Request(["callback" => "hello"], [], [], [], [], $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals('text/javascript', $api_result->get_content_type()); - - $server = ["HTTP_ACCEPT" => "unknow"]; - $request = new Request(["callback" => ""], [], [], [], [], $server); - $api_result = new API_V1_result(self::$DI['app'], $request, $this->api); - $this->assertEquals("application/json", $api_result->get_content_type()); - } - - /** - * @depends testFormatJson - */ - public function testSet_error_message() - { - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, 'detaillage'); - $this->assertErrorMessage($api_result, 400, API_V1_result::ERROR_BAD_REQUEST, API_V1_exception_badrequest::get_details(), 'detaillage'); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_message(API_V1_result::ERROR_UNAUTHORIZED, 'detaillage'); - $this->assertErrorMessage($api_result, 401, API_V1_result::ERROR_UNAUTHORIZED, API_V1_exception_unauthorized::get_details(), 'detaillage'); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_message(API_V1_result::ERROR_FORBIDDEN, 'detaillage'); - $this->assertErrorMessage($api_result, 403, API_V1_result::ERROR_FORBIDDEN, API_V1_exception_forbidden::get_details(), 'detaillage'); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_message(API_V1_result::ERROR_NOTFOUND, 'detaillage'); - $this->assertErrorMessage($api_result, 404, API_V1_result::ERROR_NOTFOUND, API_V1_exception_notfound::get_details(), 'detaillage'); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_message(API_V1_result::ERROR_METHODNOTALLOWED, 'detaillage'); - $this->assertErrorMessage($api_result, 405, API_V1_result::ERROR_METHODNOTALLOWED, API_V1_exception_methodnotallowed::get_details(), 'detaillage'); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_message(API_V1_result::ERROR_INTERNALSERVERERROR, 'detaillage'); - $this->assertErrorMessage($api_result, 500, API_V1_result::ERROR_INTERNALSERVERERROR, API_V1_exception_internalservererror::get_details(), 'detaillage'); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_message(OAUTH2_ERROR_INVALID_REQUEST, 'detaillage'); - $this->assertErrorMessage($api_result, 200, OAUTH2_ERROR_INVALID_REQUEST, NULL, 'detaillage'); - } - - private function assertErrorMessage(API_V1_result $api_result, $code, $type, $message, $detail) - { - $response = json_decode($api_result->format()); - $this->checkResponseFieldMeta($response, 'http_code', $code, PHPUnit_Framework_Constraint_IsType::TYPE_INT); - - if (is_null($type)) { - $this->assertObjectHasAttribute('error_type', $response->meta); - $this->assertNull($response->meta->error_type); - } else { - $this->checkResponseFieldMeta($response, 'error_type', $type, PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - } - - if (is_null($message)) { - $this->assertObjectHasAttribute('error_message', $response->meta); - $this->assertNull($response->meta->error_message); - } else { - $this->checkResponseFieldMeta($response, 'error_message', $message, PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - } - - if (is_null($detail)) { - $this->assertObjectHasAttribute('error_details', $response->meta); - $this->assertNull($response->meta->error_details); - } else { - $this->checkResponseFieldMeta($response, 'error_details', $detail, PHPUnit_Framework_Constraint_IsType::TYPE_STRING); - } - } - - /** - * @depends testFormatJson - */ - public function testSet_error_code() - { - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(400); - $this->assertErrorMessage($api_result, 400, API_V1_result::ERROR_BAD_REQUEST, API_V1_exception_badrequest::get_details(), null); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(401); - $this->assertErrorMessage($api_result, 401, API_V1_result::ERROR_UNAUTHORIZED, API_V1_exception_unauthorized::get_details(), null); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(403); - $this->assertErrorMessage($api_result, 403, API_V1_result::ERROR_FORBIDDEN, API_V1_exception_forbidden::get_details(), null); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(404); - $this->assertErrorMessage($api_result, 404, API_V1_result::ERROR_NOTFOUND, API_V1_exception_notfound::get_details(), null); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(405); - $this->assertErrorMessage($api_result, 405, API_V1_result::ERROR_METHODNOTALLOWED, API_V1_exception_methodnotallowed::get_details(), null); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(500); - $this->assertErrorMessage($api_result, 500, API_V1_result::ERROR_INTERNALSERVERERROR, API_V1_exception_internalservererror::get_details(), null); - } - - public function testGet_http_code() - { - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(400); - $this->assertEquals(400, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(401); - $this->assertEquals(401, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(403); - $this->assertEquals(403, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(404); - $this->assertEquals(404, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(405); - $this->assertEquals(405, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_error_code(500); - $this->assertEquals(500, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(["callback" => "my_callback"]), $this->api); - $api_result->set_error_code(400); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(["callback" => "my_callback"]), $this->api); - $api_result->set_error_code(500); - $this->assertEquals(500, $api_result->get_http_code()); - } - - public function testSet_http_code() - { - $api_result = new API_V1_result(self::$DI['app'], new Request(), $this->api); - $api_result->set_http_code(500); - $this->assertEquals(500, $api_result->get_http_code()); - - $api_result->set_http_code(400); - $this->assertEquals(400, $api_result->get_http_code()); - $api_result->set_http_code(401); - $this->assertEquals(401, $api_result->get_http_code()); - $api_result->set_http_code(403); - $this->assertEquals(403, $api_result->get_http_code()); - - $api_result = new API_V1_result(self::$DI['app'], new Request(["callback" => "my_callback"]), $this->api); - $api_result->set_http_code(500); - $this->assertEquals(500, $api_result->get_http_code()); - - $api_result->set_http_code(400); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(401); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(403); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(404); - $this->assertEquals(200, $api_result->get_http_code()); - - $api_result->set_http_code(405); - $this->assertEquals(200, $api_result->get_http_code()); - } -} diff --git a/www/api.php b/www/api.php index 733e9a37bd..9ec72b7a7c 100644 --- a/www/api.php +++ b/www/api.php @@ -16,7 +16,7 @@ require_once __DIR__ . '/../lib/autoload.php'; ErrorHandler::register(); -$environment = Application::ENV_PROD; +$environment = Application::ENV_DEV; $app = require __DIR__ . '/../lib/Alchemy/Phrasea/Application/Api.php'; $app->run();