From 076f0317b5388066bccb69ccb28e95f8401aa276 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Tue, 15 May 2012 16:47:12 +0200 Subject: [PATCH] Cleanup + add error_type to API response --- lib/Alchemy/Phrasea/Application/Api.php | 79 +++++---- .../Phrasea/Application/ApiVersion.php | 4 +- lib/classes/API/V1/Interface.class.php | 2 +- lib/classes/API/V1/adapter.class.php | 161 ++++++++++++++++-- lib/classes/API/V1/result.class.php | 39 +++-- 5 files changed, 225 insertions(+), 60 deletions(-) diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index a66e78a5db..2c772ef82d 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -11,13 +11,13 @@ namespace Alchemy\Phrasea\Application; +use Silex\Application; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception; /** * - * @package APIv1 * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ @@ -185,12 +185,11 @@ return call_user_func(function() { /* @var $user \User_Adapter */ $user = $app['token']->get_account()->get_user(); if ( ! $user->is_admin()) { - throw new \API_V1_exception_unauthorized(); + throw new \API_V1_exception_unauthorized('You are not authorized'); } }; /** - * ******************************************************************* * Get all tasks information * * Route : /monitor/phraseanet/ @@ -298,9 +297,10 @@ return call_user_func(function() { } )->middleware($mustBeAdmin); + /** * ******************************************************************* - * Route : /databoxes/list/FORMAT/ + * Route : /databoxes/list/ * * Method : GET * @@ -317,7 +317,7 @@ return call_user_func(function() { /** * ******************************************************************* * - * Route /databoxes/DATABOX_ID/collections/FORMAT/ + * Route /databoxes/DATABOX_ID/collections/ * * Method : GET * @@ -338,7 +338,7 @@ return call_user_func(function() { /** * ******************************************************************* - * Route /databoxes/DATABOX_ID/status/FORMAT/ + * Route /databoxes/DATABOX_ID/status/ * * Method : GET * @@ -358,7 +358,7 @@ return call_user_func(function() { $app->get('/databoxes/{any_id}/status/', $bad_request_exception); /** - * Route /databoxes/DATABOX_ID/metadatas/FORMAT/ + * Route /databoxes/DATABOX_ID/metadatas/ * * Method : GET * @@ -377,7 +377,7 @@ return call_user_func(function() { $app->get('/databoxes/{any_id}/metadatas/', $bad_request_exception); /** - * Route /databoxes/DATABOX_ID/termsOfUse/FORMAT/ + * Route /databoxes/DATABOX_ID/termsOfUse/ * * Method : GET * @@ -396,8 +396,27 @@ return call_user_func(function() { $app->get('/databoxes/{any_id}/termsOfUse/', $bad_request_exception); + /** - * Route : /records/search/FORMAT/ + * ******************************************************************* + * Route : /records/add/ + * + * Method : POST + * + * Parameters : + * + */ + $route = '/records/add/'; + $app->post( + $route, function(\Silex\Application $app, Request $request) { + return $app['api']->add_record($app, $request)->get_response(); + } + ); + + $app->match('/records/add/', $bad_request_exception); + + /** + * Route : /records/search/ * * Method : GET or POST * @@ -435,7 +454,7 @@ return call_user_func(function() { /** - * Route : /records/DATABOX_ID/RECORD_ID/metadatas/FORMAT/ + * Route : /records/DATABOX_ID/RECORD_ID/metadatas/ * * Method : GET * @@ -456,7 +475,7 @@ return call_user_func(function() { $app->get('/records/{any_id}/{anyother_id}/metadatas/', $bad_request_exception); /** - * Route : /records/DATABOX_ID/RECORD_ID/status/FORMAT/ + * Route : /records/DATABOX_ID/RECORD_ID/status/ * * Method : GET * @@ -477,7 +496,7 @@ return call_user_func(function() { $app->get('/records/{any_id}/{anyother_id}/status/', $bad_request_exception); /** - * Route : /records/DATABOX_ID/RECORD_ID/related/FORMAT/ + * Route : /records/DATABOX_ID/RECORD_ID/related/ * * Method : GET * @@ -498,7 +517,7 @@ return call_user_func(function() { $app->get('/records/{any_id}/{anyother_id}/related/', $bad_request_exception); /** - * Route : /records/DATABOX_ID/RECORD_ID/embed/FORMAT/ + * Route : /records/DATABOX_ID/RECORD_ID/embed/ * * Method : GET * @@ -519,7 +538,7 @@ return call_user_func(function() { $app->get('/records/{any_id}/{anyother_id}/embed/', $bad_request_exception); /** - * Route : /records/DATABOX_ID/RECORD_ID/setmetadatas/FORMAT/ + * Route : /records/DATABOX_ID/RECORD_ID/setmetadatas/ * * Method : POST * @@ -540,7 +559,7 @@ return call_user_func(function() { $app->post('/records/{any_id}/{anyother_id}/setmetadatas/', $bad_request_exception); /** - * Route : /records/DATABOX_ID/RECORD_ID/setstatus/FORMAT/ + * Route : /records/DATABOX_ID/RECORD_ID/setstatus/ * * Method : POST * @@ -562,7 +581,7 @@ return call_user_func(function() { /** - * Route : /records/DATABOX_ID/RECORD_ID/setcollection/FORMAT/ + * Route : /records/DATABOX_ID/RECORD_ID/setcollection/ * * Method : POST * @@ -591,7 +610,7 @@ return call_user_func(function() { $app->get('/records/{any_id}/{anyother_id}/', $bad_request_exception); /** - * Route : /baskets/list/FORMAT/ + * Route : /baskets/list/ * * Method : POST * @@ -609,7 +628,7 @@ return call_user_func(function() { /** - * Route : /baskets/add/FORMAT/ + * Route : /baskets/add/ * * Method : POST * @@ -628,7 +647,7 @@ return call_user_func(function() { /** - * Route : /baskets/BASKET_ID/content/FORMAT/ + * Route : /baskets/BASKET_ID/content/ * * Method : GET * @@ -648,7 +667,7 @@ return call_user_func(function() { /** - * Route : /baskets/BASKET_ID/settitle/FORMAT/ + * Route : /baskets/BASKET_ID/settitle/ * * Method : GET * @@ -668,7 +687,7 @@ return call_user_func(function() { /** - * Route : /baskets/BASKET_ID/setdescription/FORMAT/ + * Route : /baskets/BASKET_ID/setdescription/ * * Method : POST * @@ -687,7 +706,7 @@ return call_user_func(function() { $app->post('/baskets/{wrong_basket_id}/setdescription/', $bad_request_exception); /** - * Route : /baskets/BASKET_ID/delete/FORMAT/ + * Route : /baskets/BASKET_ID/delete/ * * Method : POST * @@ -707,7 +726,7 @@ return call_user_func(function() { /** - * Route : /feeds/list/FORMAT/ + * Route : /feeds/list/ * * Method : POST * @@ -724,7 +743,7 @@ return call_user_func(function() { ); /** - * Route : /feeds/PUBLICATION_ID/content/FORMAT/ + * Route : /feeds/PUBLICATION_ID/content/ * * Method : GET * @@ -769,13 +788,13 @@ return call_user_func(function() { else $code = \API_V1_result::ERROR_INTERNALSERVERERROR; - $result = $app['api']->get_error_message($app['request'], $code); + $result = $app['api']->get_error_message($app['request'], $code, $e->getMessage()); return $result->get_response(); }); //// //// //// /** -//// * Route : /records/DATABOX_ID/RECORD_ID/addtobasket/FORMAT/ +//// * Route : /records/DATABOX_ID/RECORD_ID/addtobasket/ //// * //// * Method : POST //// * @@ -788,7 +807,7 @@ return call_user_func(function() { //// //// //// /** -//// * Route : /feeds/PUBLICATION_ID/remove/FORMAT/ +//// * Route : /feeds/PUBLICATION_ID/remove/ //// * //// * Method : GET //// * @@ -800,7 +819,7 @@ return call_user_func(function() { //// //// //// /** -//// * Route : /users/search/FORMAT/ +//// * Route : /users/search/ //// * //// * Method : POST-GET //// * @@ -810,7 +829,7 @@ return call_user_func(function() { //// public function search_users(\Symfony\Component\HttpFoundation\Request $app['request']); //// //// /** -//// * Route : /users/USER_ID/access/FORMAT/ +//// * Route : /users/USER_ID/access/ //// * //// * Method : GET //// * @@ -821,7 +840,7 @@ return call_user_func(function() { //// public function get_user_acces(\Symfony\Component\HttpFoundation\Request $app['request'], $usr_id); //// //// /** -//// * Route : /users/add/FORMAT/ +//// * Route : /users/add/ //// * //// * Method : POST //// * diff --git a/lib/Alchemy/Phrasea/Application/ApiVersion.php b/lib/Alchemy/Phrasea/Application/ApiVersion.php index ba92e9255a..2472b388c4 100644 --- a/lib/Alchemy/Phrasea/Application/ApiVersion.php +++ b/lib/Alchemy/Phrasea/Application/ApiVersion.php @@ -27,13 +27,11 @@ return call_user_func(function() { $app["Core"] = \bootstrap::getCore(); - $app["appbox"] = \appbox::get_instance($app['Core']); - $app->get( '/', function(Request $request) use ($app) { $registry = $app["Core"]->getRegistry(); - $apiAdapter = new \API_V1_adapter(false, $app["appbox"], $app["Core"]); + $apiAdapter = new \API_V1_adapter(false, \appbox::get_instance($app['Core']), $app["Core"]); $result = new \API_V1_result($request, $apiAdapter); diff --git a/lib/classes/API/V1/Interface.class.php b/lib/classes/API/V1/Interface.class.php index ea2c398816..11bdbbaa2d 100644 --- a/lib/classes/API/V1/Interface.class.php +++ b/lib/classes/API/V1/Interface.class.php @@ -311,7 +311,7 @@ interface API_V1_Interface */ public function add_user(\Symfony\Component\HttpFoundation\Request $request); - public function get_error_message(\Symfony\Component\HttpFoundation\Request $request, $error); + public function get_error_message(\Symfony\Component\HttpFoundation\Request $request, $error, $message); public function get_error_code(\Symfony\Component\HttpFoundation\Request $request, $code); } diff --git a/lib/classes/API/V1/adapter.class.php b/lib/classes/API/V1/adapter.class.php index 9ebc52e32b..aaa64d6bed 100644 --- a/lib/classes/API/V1/adapter.class.php +++ b/lib/classes/API/V1/adapter.class.php @@ -9,15 +9,14 @@ * file that was distributed with this source code. */ +use Symfony\Component\HttpFoundation\Request; +use Silex\Application; + /** * * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ - -use Symfony\Component\HttpFoundation\Request; -use Silex\Application; - class API_V1_adapter extends API_V1_Abstract { /** @@ -62,10 +61,10 @@ class API_V1_adapter extends API_V1_Abstract * @param string $error * @return API_V1_result ` */ - public function get_error_message(Request $request, $error) + public function get_error_message(Request $request, $error, $message) { $result = new API_V1_result($request, $this); - $result->set_error_message($error); + $result->set_error_message($error, $message); return $result; } @@ -657,6 +656,144 @@ class API_V1_adapter extends API_V1_Abstract 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($request->get('base_id')); + + if ( ! $app['Core']->getAuthenticatedUser()->ACL()->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_name())); + } + + $media = \MediaVorus\MediaVorus::guess($file); + + $Package = new Alchemy\Phrasea\Border\File($media, $collection, $file->getClientOriginalName()); + + if ($request->get('status')) { + $Package->addAttribute(new \Alchemy\Phrasea\Border\Attribute\Status($request->get('status'))); + } + + $session = new Entities\LazaretSession(); + $session->setUsrId($app['Core']->getAuthenticatedUser()->get_id()); + + $app['Core']['EM']->persist($session); + $app['Core']['EM']->flush(); + + $errors = $output = null; + + $callback = function($element, $visa, $code) use(&$errors, &$output) { + if ( ! $visa->isValid()) { + $errors = array(); + + foreach ($visa->getResponses() as $response) { + $errors[] = $response->getMessage(); + } + } + + if ($code == \Alchemy\Phrasea\Border\Manager::RECORD_CREATED) { + $output = $element; + } + if ($code == \Alchemy\Phrasea\Border\Manager::LAZARET_CREATED) { + $output = $element; + } + }; + + switch ($request->get('forceBehavior')) { + case '0' : + $behavior = \Alchemy\Phrasea\Border\Manager::FORCE_RECORD; + break; + case '1' : + $behavior = \Alchemy\Phrasea\Border\Manager::FORCE_LAZARET; + break; + case null: + $behavior = null; + break; + default: + throw new API_V1_exception_badrequest('Invalid forceBehavior value'); + break; + } + + $app['Core']['border-manager']->process($session, $Package, $callback, $behavior); + + if ($output instanceof \record_adapter) { + $ret = $this->list_record($output); + } + if ($output instanceof \Entities\LazaretFile) { + $ret = array( + 'errors' => $errors, + 'lazaretFile' => $this->list_lazaret_file($output), + ); + } + + $result = new API_V1_result($request, $this); + + $result->set_datas($ret); + + return $result; + } + + protected function list_lazaret_file(\Entities\LazaretFile $file) + { + $attributes = $checks = array(); + + foreach ($file->getAttributes() as $attr) { + $attributes[] = array( + 'name' => $attr->getName(), + 'value' => $attr->asString(), + ); + } + + foreach ((array) $file->getChecks() as $checker) { + + if ( ! class_exists($checker)) { + continue; + } + + if ( ! $checker instanceof \Alchemy\Phrasea\Border\Checker\Checker) { + continue; + } + + $checks[] = $checker::getMessage(); + } + + $session = array( + 'id' => $file->getSession()->getId(), + 'usr_id' => $file->getSession()->getUsrId(), + ); + + return array( + 'id' => $file->getId(), + 'session' => $session, + 'base_id' => $file->getBaseId(), + 'original_name' => $file->getOriginalName(), + 'sha256' => $file->getSha256(), + 'uuid' => $file->getUuid(), + 'forced' => $file->getForced(), + 'attributes' => $attributes, + 'checks' => $checks, + 'created_on' => $file->getCreated()->format(DATE_ATOM), + 'updated_on' => $file->getUpdated()->format(DATE_ATOM), + ); + } + /** * Get an API_V1_result containing the results of a records search * @@ -922,7 +1059,7 @@ class API_V1_adapter extends API_V1_Abstract $record->set_metadatas($metadatas); $result->set_datas(array("metadatas" => $this->list_record_caption($record->get_caption()))); } catch (Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST); + $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('An error occured')); } return $result; @@ -965,7 +1102,7 @@ class API_V1_adapter extends API_V1_Abstract ) ); } catch (Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST); + $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('An error occured')); } return $result; @@ -991,7 +1128,7 @@ class API_V1_adapter extends API_V1_Abstract $record->move_to_collection($collection, $this->appbox); $result->set_datas(array("record" => $this->list_record($record))); } catch (Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST); + $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('An error occured')); } return $result; @@ -1012,8 +1149,10 @@ class API_V1_adapter extends API_V1_Abstract try { $record = $databox->get_record($record_id); $result->set_datas(array('record' => $this->list_record($record))); + } catch (Exception_NotFound $e) { + $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Record Not Found')); } catch (Exception $e) { - $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST); + $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('An error occured')); } return $result; @@ -1083,7 +1222,7 @@ class API_V1_adapter extends API_V1_Abstract $name = $request->get('name'); if (trim(strip_tags($name)) === '') { - throw new API_V1_exception_badrequest (); + throw new API_V1_exception_badrequest('Missing basket name parameter'); } $user = $this->core->getAuthenticatedUser(); diff --git a/lib/classes/API/V1/result.class.php b/lib/classes/API/V1/result.class.php index cc51e6db2c..4852b34d68 100644 --- a/lib/classes/API/V1/result.class.php +++ b/lib/classes/API/V1/result.class.php @@ -39,6 +39,12 @@ class API_V1_result */ protected $http_code = 200; + /** + * + * @var string + */ + protected $error_type; + /** * * @var string @@ -172,6 +178,7 @@ class API_V1_result , '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' @@ -227,47 +234,49 @@ class API_V1_result } /** - * Set the API_V1_result http_code, error_message and error_details + * Set the API_V1_result http_code, error_type, error_message and error_details * with the appropriate datas * * @param string $const * @return API_V1_result */ - public function set_error_message($const) + public function set_error_message($const, $message) { + $this->error_details = $message; + switch ($const) { case self::ERROR_BAD_REQUEST: $this->http_code = 400; - $this->error_message = $const; - $this->error_details = API_V1_exception_badrequest::get_details(); + $this->error_type = $const; + $this->error_message = API_V1_exception_badrequest::get_details(); break; case self::ERROR_UNAUTHORIZED: $this->http_code = 401; - $this->error_message = $const; - $this->error_details = API_V1_exception_unauthorized::get_details(); + $this->error_type = $const; + $this->error_message = API_V1_exception_unauthorized::get_details(); break; case self::ERROR_FORBIDDEN: $this->http_code = 403; - $this->error_message = $const; - $this->error_details = API_V1_exception_forbidden::get_details(); + $this->error_type = $const; + $this->error_message = API_V1_exception_forbidden::get_details(); break; case self::ERROR_NOTFOUND: $this->http_code = 404; - $this->error_message = $const; - $this->error_details = API_V1_exception_notfound::get_details(); + $this->error_type = $const; + $this->error_message = API_V1_exception_notfound::get_details(); break; case self::ERROR_METHODNOTALLOWED: $this->http_code = 405; - $this->error_message = $const; - $this->error_details = API_V1_exception_methodnotallowed::get_details(); + $this->error_type = $const; + $this->error_message = API_V1_exception_methodnotallowed::get_details(); break; case self::ERROR_INTERNALSERVERERROR: $this->http_code = 500; - $this->error_message = $const; - $this->error_details = API_V1_exception_internalservererror::get_details(); + $this->error_type = $const; + $this->error_message = API_V1_exception_internalservererror::get_details(); break; case OAUTH2_ERROR_INVALID_REQUEST: - $this->error_message = $const; + $this->error_type = $const; break; }