diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 37b57c5b53..d556939bed 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -73,7 +73,8 @@ use Alchemy\Phrasea\Controller\Utils\ConnectionTest; use Alchemy\Phrasea\Controller\Utils\PathFileTest; use Alchemy\Phrasea\Controller\User\Notifications; use Alchemy\Phrasea\Controller\User\Preferences; -use Alchemy\Phrasea\Core\Event\Subscriber\Logout; +use Alchemy\Phrasea\Core\PhraseaExceptionHandler; +use Alchemy\Phrasea\Core\Event\Subscriber\LogoutSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaLocaleSubscriber; use Alchemy\Phrasea\Core\Provider\AuthenticationManagerServiceProvider; use Alchemy\Phrasea\Core\Provider\BrowserServiceProvider; @@ -121,7 +122,6 @@ use Silex\Provider\SwiftmailerServiceProvider; use Silex\Provider\UrlGeneratorServiceProvider; use Silex\Provider\ValidatorServiceProvider; use Silex\Provider\ServiceControllerServiceProvider; -use Silex\Provider\WebProfilerServiceProvider; use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser; use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser; use Unoconv\UnoconvServiceProvider; @@ -155,34 +155,25 @@ class Application extends SilexApplication private $environment; private $sessionCookieEnabled = true; + const ENV_DEV = 'dev'; + const ENV_PROD = 'prod'; + const ENV_TEST = 'test'; + public function getEnvironment() { return $this->environment; } - public function __construct($environment = 'prod') + public function __construct($environment = self::ENV_PROD) { parent::__construct(); + error_reporting(-1); + $this['root.path'] = realpath(__DIR__ . '/../../..'); $this->environment = $environment; - if ((int) ini_get('memory_limit') < 2048) { - ini_set('memory_limit', '2048M'); - } - - error_reporting(E_ALL | E_STRICT); - - ini_set('display_errors', 'on'); - ini_set('output_buffering', '4096'); ini_set('default_charset', 'UTF-8'); - ini_set('session.use_cookies', '1'); - ini_set('session.use_only_cookies', '1'); - ini_set('session.auto_start', '0'); - ini_set('session.hash_function', '1'); - ini_set('session.hash_bits_per_character', '6'); - ini_set('session.cache_limiter', ''); - ini_set('allow_url_fopen', 'on'); mb_internal_encoding("UTF-8"); !defined('JETON_MAKE_SUBDEF') ? define('JETON_MAKE_SUBDEF', 0x01) : ''; @@ -193,17 +184,12 @@ class Application extends SilexApplication $this['charset'] = 'UTF-8'; $this['debug'] = $this->share(function(Application $app) { - return $app->getEnvironment() !== 'prod'; + return Application::ENV_PROD !== $app->getEnvironment(); }); if ($this['debug'] === true) { - ini_set('display_errors', 'on'); - if ($this->getEnvironment() === 'dev') { - ini_set('log_errors', 'on'); - ini_set('error_log', __DIR__ . '/../../../logs/php_error.log'); - } - } else { - ini_set('display_errors', 'off'); + ini_set('log_errors', 'on'); + ini_set('error_log', $this['root.path'] . '/logs/php_error.log'); } $this->register(new AuthenticationManagerServiceProvider()); @@ -263,7 +249,7 @@ class Application extends SilexApplication $this->register(new SearchEngineServiceProvider()); $this->register(new SessionServiceProvider(), array( - 'session.test' => $this->getEnvironment() == 'test' + 'session.test' => $this->getEnvironment() === static::ENV_TEST )); $this->register(new ServiceControllerServiceProvider()); $this->register(new SwiftmailerServiceProvider()); @@ -272,7 +258,7 @@ class Application extends SilexApplication $this->register(new TokensServiceProvider()); $this->register(new TwigServiceProvider(), array( 'twig.options' => array( - 'cache' => realpath(__DIR__ . '/../../../tmp/cache_twig/'), + 'cache' => $this['root.path'] . '/tmp/cache_twig/', ), 'twig.form.templates' => array('login/common/form_div_layout.html.twig') )); @@ -285,19 +271,14 @@ class Application extends SilexApplication $this->register(new UnicodeServiceProvider()); $this->register(new ValidatorServiceProvider()); - if ('dev' === $this->environment) { - $this->register($p = new WebProfilerServiceProvider(), array( - 'profiler.cache_dir' => __DIR__ . '/../../../tmp/cache/profiler', - )); - $this->mount('/_profiler', $p); - } - $this->register(new XPDFServiceProvider()); + $this['phraseanet.exception_handler'] = $this->share(function ($app) { + return PhraseaExceptionHandler::register($app['debug']); + }); + $this['swiftmailer.transport'] = $this->share(function ($app) { - if ($app['phraseanet.registry']->get('GV_smtp')) { - $transport = new \Swift_Transport_EsmtpTransport( $app['swiftmailer.transport.buffer'], array($app['swiftmailer.transport.authhandler']), @@ -340,9 +321,6 @@ class Application extends SilexApplication return $transport; }); -// $this->register(new \Silex\Provider\HttpCacheServiceProvider()); -// $this->register(new \Silex\Provider\SecurityServiceProvider()); - $this['imagine.factory'] = $this->share(function(Application $app) { if ($app['phraseanet.registry']->get('GV_imagine_driver') != '') { return $app['phraseanet.registry']->get('GV_imagine_driver'); @@ -384,11 +362,17 @@ class Application extends SilexApplication }) ); - $this['dispatcher']->addListener(KernelEvents::REQUEST, array($this, 'initSession'), 254); - $this['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'addUTF8Charset'), -128); - $this['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'disableCookiesIfRequired'), -256); - $this['dispatcher']->addSubscriber(new Logout()); - $this['dispatcher']->addSubscriber(new PhraseaLocaleSubscriber($this)); + $this['dispatcher'] = $this->share( + $this->extend('dispatcher', function($dispatcher, Application $app){ + $dispatcher->addListener(KernelEvents::REQUEST, array($app, 'initSession'), 254); + $dispatcher->addListener(KernelEvents::RESPONSE, array($app, 'addUTF8Charset'), -128); + $dispatcher->addListener(KernelEvents::RESPONSE, array($app, 'disableCookiesIfRequired'), -256); + $dispatcher->addSubscriber(new LogoutSubscriber()); + $dispatcher->addSubscriber(new PhraseaLocaleSubscriber($app)); + + return $dispatcher; + }) + ); $this->register(new LocaleServiceProvider()); diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php index ed77685b45..7a5f9e8dfa 100644 --- a/lib/Alchemy/Phrasea/Application/Api.php +++ b/lib/Alchemy/Phrasea/Application/Api.php @@ -17,17 +17,19 @@ use Alchemy\Phrasea\Controller\Api\Oauth2; use Alchemy\Phrasea\Controller\Api\V1; use Alchemy\Phrasea\Core\Event\ApiLoadEndEvent; use Alchemy\Phrasea\Core\Event\ApiLoadStartEvent; +use Alchemy\Phrasea\Core\Event\Subscriber\ApiOauth2ErrorsSubscriber; +use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber; use Silex\Application as SilexApplication; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; -use Symfony\Component\HttpKernel\Exception\HttpException; -use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; -use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; -use Symfony\Component\HttpFoundation\Response; -return call_user_func(function($environment = 'prod') { +return call_user_func(function($environment = PhraseaApplication::ENV_PROD) { $app = new PhraseaApplication($environment); + + $app['exception_handler'] = $app->share(function ($app) { + return new ApiExceptionHandlerSubscriber($app); + }); + $app->disableCookies(); $app->register(new \API_V1_Timer()); @@ -61,72 +63,7 @@ return call_user_func(function($environment = 'prod') { $app->mount('/api/oauthv2', new Oauth2()); $app->mount('/api/v1', new V1()); - /** - * Route Errors - */ - $app->error(function (\Exception $e) use ($app) { - - $request = $app['request']; - - if (0 === strpos($request->getPathInfo(), '/api/oauthv2')) { - if ($e instanceof NotFoundHttpException || $e instanceof \Exception_NotFound) { - return new Response('The requested page could not be found.', 404, array('X-Status-Code' => 404)); - } - - $code = 500; - $msg = 'We are sorry, but something went wrong'; - $headers = array(); - - if ($e instanceof HttpExceptionInterface) { - $headers = $e->getHeaders(); - $msg = $e->getMessage(); - $code = $e->getStatusCode(); - - if (isset($headers['content-type']) && $headers['content-type'] == 'application/json') { - $msg = json_encode(array('msg' => $msg, 'code' => $code)); - } - } - - return new Response($msg, $code, $headers); - } - - $headers = array(); - - if ($e instanceof \API_V1_exception_methodnotallowed) { - $code = \API_V1_result::ERROR_METHODNOTALLOWED; - } elseif ($e instanceof MethodNotAllowedHttpException) { - $code = \API_V1_result::ERROR_METHODNOTALLOWED; - } 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; - } elseif ($e instanceof \Exception_NotFound) { - $code = \API_V1_result::ERROR_NOTFOUND; - } elseif ($e instanceof NotFoundHttpException) { - $code = \API_V1_result::ERROR_NOTFOUND; - } else { - $code = \API_V1_result::ERROR_INTERNALSERVERERROR; - } - - if ($e instanceof HttpException) { - $headers = $e->getHeaders(); - } - - $result = $app['api']->get_error_message($app['request'], $code, $e->getMessage()); - $response = $result->get_response(); - $response->headers->set('X-Status-Code', $result->get_http_code()); - - foreach ($headers as $key => $value) { - $response->headers->set($key, $value); - } - - return $response; - }); - + $app['dispatcher']->addSubscriber(new ApiOauth2ErrorsSubscriber($app['phraseanet.exception_handler'])); $app['dispatcher']->dispatch(PhraseaEvents::API_LOAD_END, new ApiLoadEndEvent()); return $app; diff --git a/lib/Alchemy/Phrasea/Application/Root.php b/lib/Alchemy/Phrasea/Application/Root.php index b8c482eff6..95103cfb27 100644 --- a/lib/Alchemy/Phrasea/Application/Root.php +++ b/lib/Alchemy/Phrasea/Application/Root.php @@ -12,15 +12,22 @@ namespace Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application as PhraseaApplication; +use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaExceptionHandlerSubscriber; +use Alchemy\Phrasea\Core\Event\Subscriber\BridgeExceptionSubscriber; +use Alchemy\Phrasea\Core\Event\Subscriber\FirewallSubscriber; +use Alchemy\Phrasea\Core\Event\Subscriber\JsonRequestSubscriber; +use Alchemy\Phrasea\Core\Event\Subscriber\DebuggerSubscriber; +use Silex\Provider\WebProfilerServiceProvider; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface; -return call_user_func(function($environment = null) { +return call_user_func(function($environment = PhraseaApplication::ENV_PROD) { $app = new PhraseaApplication($environment); + $app['exception_handler'] = $app->share(function ($app) { + return new PhraseaExceptionHandlerSubscriber($app['phraseanet.exception_handler']); + }); + $app->before(function (Request $request) use ($app) { if (0 === strpos($request->getPathInfo(), '/setup')) { if (!$app['phraseanet.configuration-tester']->isBlank()) { @@ -41,98 +48,23 @@ return call_user_func(function($environment = null) { $app->bindRoutes(); - $app->error(function(\Exception $e) use ($app) { - $request = $app['request']; + if (PhraseaApplication::ENV_DEV === $app->getEnvironment()) { + $app->register(new WebProfilerServiceProvider(), array( + 'profiler.cache_dir' => $app['root.path'] . '/tmp/cache/profiler', + 'profiler.mount_prefix' => '/_profiler', + )); + } - if ($e instanceof \Bridge_Exception) { - $params = array( - 'message' => $e->getMessage() - , 'file' => $e->getFile() - , 'line' => $e->getLine() - , 'r_method' => $request->getMethod() - , 'r_action' => $request->getRequestUri() - , 'r_parameters' => ($request->getMethod() == 'GET' ? array() : $request->request->all()) - ); + $app['dispatcher'] = $app->share( + $app->extend('dispatcher', function($dispatcher, PhraseaApplication $app){ + $dispatcher->addSubscriber(new BridgeExceptionSubscriber($app)); + $dispatcher->addSubscriber(new FirewallSubscriber()); + $dispatcher->addSubscriber(new JsonRequestSubscriber()); + $dispatcher->addSubscriber(new DebuggerSubscriber($app)); - if ($e instanceof \Bridge_Exception_ApiConnectorNotConfigured) { - $params = array_merge($params, array('account' => $app['current_account'])); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/notconfigured.html.twig', $params), 200, array('X-Status-Code' => 200)); - } elseif ($e instanceof \Bridge_Exception_ApiConnectorNotConnected) { - $params = array_merge($params, array('account' => $app['current_account'])); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); - } elseif ($e instanceof \Bridge_Exception_ApiConnectorAccessTokenFailed) { - $params = array_merge($params, array('account' => $app['current_account'])); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); - } elseif ($e instanceof \Bridge_Exception_ApiDisabled) { - $params = array_merge($params, array('api' => $e->get_api())); - - $response = new Response($app['twig']->render('/prod/actions/Bridge/deactivated.html.twig', $params), 200, array('X-Status-Code' => 200)); - } else { - $response = new Response($app['twig']->render('/prod/actions/Bridge/error.html.twig', $params), 200, array('X-Status-Code' => 200)); - } - - $response->headers->set('Phrasea-StatusCode', 200); - - return $response; - } - - if ((0 !== strpos($request->getPathInfo(), '/admin/') - || 0 === strpos($request->getPathInfo(), '/admin/collection/') - || 0 === strpos($request->getPathInfo(), '/admin/databox/')) - && $request->getRequestFormat() == 'json') { - $datas = array( - 'success' => false - , 'message' => $e->getMessage() - ); - - return $app->json($datas, 200, array('X-Status-Code' => 200)); - } - - if ($e instanceof HttpExceptionInterface) { - $headers = $e->getHeaders(); - - if (isset($headers['X-Phraseanet-Redirect'])) { - return new RedirectResponse($headers['X-Phraseanet-Redirect'], 302, array('X-Status-Code' => 302)); - } - - $message = isset(Response::$statusTexts[$e->getStatusCode()]) ? Response::$statusTexts[$e->getStatusCode()] : ''; - - if (400 === $e->getStatusCode()) { - $message .= ' : ' . $e->getMessage(); - } - - return new Response($message, $e->getStatusCode(), $e->getHeaders()); - } - - if ($e instanceof \Exception_BadRequest) { - return new Response('Bad Request', 400, array('X-Status-Code' => 400)); - } - if ($e instanceof \Exception_Forbidden) { - return new Response('Forbidden', 403, array('X-Status-Code' => 403)); - } - - if ($e instanceof \Exception_Session_NotAuthenticated) { - $code = 403; - $message = 'Forbidden'; - } elseif ($e instanceof \Exception_NotAllowed) { - $code = 403; - $message = 'Forbidden'; - } elseif ($e instanceof \Exception_NotFound) { - $code = 404; - $message = 'Not Found'; - } elseif ($e instanceof \Exception_UnauthorizedAction) { - $code = 403; - $message = 'Forbidden'; - } else { - $code = 500; - $message = 'Server Error' . ($app['debug'] ? ' : ' . $e->getMessage() : ''); - } - - return new Response($message, $code, array('X-Status-Code' => $code)); - }); + return $dispatcher; + }) + ); return $app; }, isset($environment) ? $environment : null); diff --git a/lib/Alchemy/Phrasea/Authentication/Authenticator.php b/lib/Alchemy/Phrasea/Authentication/Authenticator.php index e0031266f9..0874804dde 100644 --- a/lib/Alchemy/Phrasea/Authentication/Authenticator.php +++ b/lib/Alchemy/Phrasea/Authentication/Authenticator.php @@ -17,6 +17,7 @@ use Browser; use Doctrine\ORM\EntityManager; use Entities\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Authenticator { @@ -93,7 +94,7 @@ class Authenticator try { $user = \User_Adapter::getInstance($session->getUsrId(), $this->app); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { throw new RuntimeException('Unable to refresh the session', $e->getCode(), $e); } diff --git a/lib/Alchemy/Phrasea/Authentication/Token/TokenValidator.php b/lib/Alchemy/Phrasea/Authentication/Token/TokenValidator.php index 5eb2474eb6..f9a65836ec 100644 --- a/lib/Alchemy/Phrasea/Authentication/Token/TokenValidator.php +++ b/lib/Alchemy/Phrasea/Authentication/Token/TokenValidator.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\Authentication\Token; use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class TokenValidator { @@ -34,7 +35,7 @@ class TokenValidator $datas = $this->app['tokens']->helloToken($token); return $datas['usr_id']; - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } diff --git a/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php b/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php index f292e4a562..ee6eba475d 100644 --- a/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php +++ b/lib/Alchemy/Phrasea/Border/Attribute/MetaField.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\Border\Attribute; use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Phraseanet Border MetaField Attribute @@ -108,7 +109,7 @@ class MetaField implements AttributeInterface return new static($app['phraseanet.appbox'] ->get_databox($datas['sbas_id']) ->get_meta_structure()->get_element($datas['id']), $datas['value']); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { throw new \InvalidArgumentException('Field does not exist anymore'); } } diff --git a/lib/Alchemy/Phrasea/Border/Attribute/Story.php b/lib/Alchemy/Phrasea/Border/Attribute/Story.php index 2aa5b15819..4d0ce66b4e 100644 --- a/lib/Alchemy/Phrasea/Border/Attribute/Story.php +++ b/lib/Alchemy/Phrasea/Border/Attribute/Story.php @@ -12,6 +12,7 @@ namespace Alchemy\Phrasea\Border\Attribute; use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Phraseanet Border Story Attribute @@ -82,7 +83,7 @@ class Story implements AttributeInterface try { $story = new \record_adapter($app, $ids[0], $ids[1]); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { throw new \InvalidArgumentException('Unable to fetch a story from string'); } diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php index 2390a8ee2f..4d205f52f7 100644 --- a/lib/Alchemy/Phrasea/Border/Manager.php +++ b/lib/Alchemy/Phrasea/Border/Manager.php @@ -219,11 +219,11 @@ class Manager */ protected function bookLazaretPathfile($filename, $suffix = '') { - $output = __DIR__ . '/../../../../tmp/lazaret/lzrt_' . substr($filename, 0, 3) . '_' . $suffix . '.' . pathinfo($filename, PATHINFO_EXTENSION); + $output = $this->app['root.path'] . '/tmp/lazaret/lzrt_' . substr($filename, 0, 3) . '_' . $suffix . '.' . pathinfo($filename, PATHINFO_EXTENSION); $infos = pathinfo($output); $n = 0; - $this->app['filesystem']->mkdir(__DIR__ . '/../../../../tmp/lazaret'); + $this->app['filesystem']->mkdir($this->app['root.path'] . '/tmp/lazaret'); while (true) { $output = sprintf('%s/%s-%d%s', $infos['dirname'], $infos['filename'], ++ $n, (isset($infos['extension']) ? '.' . $infos['extension'] : '')); diff --git a/lib/Alchemy/Phrasea/Command/Compile/Configuration.php b/lib/Alchemy/Phrasea/Command/Compile/Configuration.php index 7b876944e1..a4c7a7730a 100644 --- a/lib/Alchemy/Phrasea/Command/Compile/Configuration.php +++ b/lib/Alchemy/Phrasea/Command/Compile/Configuration.php @@ -27,7 +27,7 @@ class Configuration extends Command { $this->container['phraseanet.configuration']->compileAndWrite(); $output->writeln("Confguration compiled."); - + return 0; } } diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Publications.php b/lib/Alchemy/Phrasea/Controller/Admin/Publications.php index 20e77170a4..769143246f 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/Publications.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/Publications.php @@ -15,6 +15,7 @@ use Alchemy\Phrasea\Application as PhraseaApplication; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; /** * @@ -111,23 +112,23 @@ class Publications implements ControllerProviderInterface try { if (!$request->files->get('files')) { - throw new \Exception_BadRequest('Missing file parameter'); + throw new BadRequestHttpException('Missing file parameter'); } if (count($request->files->get('files')) > 1) { - throw new \Exception_BadRequest('Upload is limited to 1 file per request'); + throw new BadRequestHttpException('Upload is limited to 1 file per request'); } $file = current($request->files->get('files')); if (!$file->isValid()) { - throw new \Exception_BadRequest('Uploaded file is invalid'); + throw new BadRequestHttpException('Uploaded file is invalid'); } $media = $app['mediavorus']->guess($file->getPathname()); if ($media->getType() !== \MediaVorus\Media\MediaInterface::TYPE_IMAGE) { - throw new \Exception_BadRequest('Bad filetype'); + throw new BadRequestHttpException('Bad filetype'); } $spec = new \MediaAlchemyst\Specification\Image(); diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Root.php b/lib/Alchemy/Phrasea/Controller/Admin/Root.php index 5a73d7531f..039d147190 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/Root.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/Root.php @@ -15,6 +15,7 @@ use Alchemy\Phrasea\Exception\SessionNotFound; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @@ -340,7 +341,7 @@ class Root implements ControllerProviderInterface if (null !== $file = $request->files->get('image_off')) { try { \databox_status::updateIcon($app, $databox_id, $bit, 'off', $file); - } catch (\Exception_Forbidden $e) { + } catch (AccessDeniedHttpException $e) { return $app->redirectPath('database_display_statusbit_form', array( 'databox_id' => $databox_id, 'bit' => $bit, @@ -386,7 +387,7 @@ class Root implements ControllerProviderInterface if (null !== $file = $request->files->get('image_on')) { try { \databox_status::updateIcon($app, $databox_id, $bit, 'on', $file); - } catch (\Exception_Forbidden $e) { + } catch (AccessDeniedHttpException $e) { return $app->redirectPath('database_display_statusbit_form', array( 'databox_id' => $databox_id, 'bit' => $bit, diff --git a/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php b/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php index e7aaf0553f..59400b8202 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/TaskManager.php @@ -165,6 +165,7 @@ class TaskManager implements ControllerProviderInterface /** * todo : add a message back */ + return $app->redirectPath('admin_tasks_list'); } })->bind('admin_tasks_task_delete'); diff --git a/lib/Alchemy/Phrasea/Controller/Datafiles.php b/lib/Alchemy/Phrasea/Controller/Datafiles.php index 3e2690224c..628b763580 100644 --- a/lib/Alchemy/Phrasea/Controller/Datafiles.php +++ b/lib/Alchemy/Phrasea/Controller/Datafiles.php @@ -15,6 +15,7 @@ use Alchemy\Phrasea\Application as PhraseaApplication; use Silex\Application; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @@ -63,7 +64,7 @@ class Datafiles extends AbstractDelivery } if (!$app['authentication']->getUser()->ACL()->has_access_to_subdef($record, $subdef)) { - throw new \Exception_UnauthorizedAction(sprintf('User has not access to subdef %s', $subdef)); + throw new AccessDeniedHttpException(sprintf('User has not access to subdef %s', $subdef)); } $stamp = false; diff --git a/lib/Alchemy/Phrasea/Controller/Lightbox.php b/lib/Alchemy/Phrasea/Controller/Lightbox.php index d7cd0d97bb..2fd0708efd 100644 --- a/lib/Alchemy/Phrasea/Controller/Lightbox.php +++ b/lib/Alchemy/Phrasea/Controller/Lightbox.php @@ -17,6 +17,7 @@ use Silex\ControllerProviderInterface; use Silex\Application as SilexApplication; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Lightbox implements ControllerProviderInterface { @@ -43,7 +44,7 @@ class Lightbox implements ControllerProviderInterface try { $datas = $app['tokens']->helloToken($request->query->get('LOG')); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { return; } switch ($datas['type']) { diff --git a/lib/Alchemy/Phrasea/Controller/Minifier.php b/lib/Alchemy/Phrasea/Controller/Minifier.php index e669337d9c..7f2ea50735 100644 --- a/lib/Alchemy/Phrasea/Controller/Minifier.php +++ b/lib/Alchemy/Phrasea/Controller/Minifier.php @@ -26,7 +26,7 @@ class Minifier implements ControllerProviderInterface $controllers->get('/', function (Application $app, Request $request) { // cache directory path - $min_cachePath = __DIR__ . '/../../../../tmp/cache_minify'; + $min_cachePath = $app['root.path'] . '/tmp/cache_minify'; /** * Cache file locking. Set to false if filesystem is NFS. On at least one diff --git a/lib/Alchemy/Phrasea/Controller/Permalink.php b/lib/Alchemy/Phrasea/Controller/Permalink.php index 8779a2d2ed..28c31a5fab 100644 --- a/lib/Alchemy/Phrasea/Controller/Permalink.php +++ b/lib/Alchemy/Phrasea/Controller/Permalink.php @@ -37,7 +37,7 @@ class Permalink extends AbstractDelivery $record = \media_Permalink_Adapter::challenge_token($app, $databox, $token, $record_id, $subdef); if (!$record instanceof \record_adapter) { - throw new \Exception_NotFound('bad luck'); + throw new NotFoundHttpException('bad luck'); } $params = array( @@ -56,7 +56,7 @@ class Permalink extends AbstractDelivery $record = \media_Permalink_Adapter::challenge_token($app, $databox, $token, $record_id, $subdef); if (!($record instanceof \record_adapter)) { - throw new \Exception_NotFound('bad luck'); + throw new NotFoundHttpException('bad luck'); } $watermark = $stamp = false; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Basket.php b/lib/Alchemy/Phrasea/Controller/Prod/Basket.php index 389c37fd1e..f70307784c 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Basket.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Basket.php @@ -18,6 +18,8 @@ use Entities\ValidationData; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -272,9 +274,9 @@ class Basket implements ControllerProviderInterface $success = true; $msg = _('Basket has been updated'); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $msg = _('The requested basket does not exist'); - } catch (\Exception_Forbidden $e) { + } catch (AccessDeniedHttpException $e) { $msg = _('You do not have access to this basket'); } catch (\Exception $e) { $msg = _('An error occurred'); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Bridge.php b/lib/Alchemy/Phrasea/Controller/Prod/Bridge.php index 86aa32c332..0b3b6d671c 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Bridge.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Bridge.php @@ -17,433 +17,456 @@ use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; -/** - * - * @license http://opensource.org/licenses/gpl-3.0 GPLv3 - * @link www.phraseanet.com - */ class Bridge implements ControllerProviderInterface { - public function connect(Application $app) { $controllers = $app['controllers_factory']; $controllers->before(function(Request $request) use ($app) { - $app['firewall'] - ->requireNotGuest() - ->requireRight('bas_chupub'); + $app['firewall']->requireRight('bas_chupub'); }); - $app['require_connection'] = $app->protect(function(\Bridge_Account $account) use ($app) { - $app['current_account'] = function() use ($account) { - return $account; - }; + $app['bridge.controller'] = $this; - if (!$account->get_api()->get_connector()->is_configured()) - throw new \Bridge_Exception_ApiConnectorNotConfigured("Bridge API Connector is not configured"); - if (!$account->get_api()->get_connector()->is_connected()) - throw new \Bridge_Exception_ApiConnectorNotConnected("Bridge API Connector is not connected"); + $controllers + ->post('/manager/', 'bridge.controller:doPostManager'); - return; - }); + $controllers + ->get('/login/{api_name}/', 'bridge.controller:doGetLogin') + ->bind('prod_bridge_login'); - $controllers->post('/manager/', function(Application $app) { - $route = new RecordHelper\Bridge($app, $app['request']); + $controllers + ->get('/callback/{api_name}/', 'bridge.controller:doGetCallback') + ->bind('prod_bridge_callback'); - $params = array( - 'user_accounts' => \Bridge_Account::get_accounts_by_user($app, $app['authentication']->getUser()) - , 'available_apis' => \Bridge_Api::get_availables($app) - , 'route' => $route - , 'current_account_id' => '' - ); - - return $app['twig']->render('prod/actions/Bridge/index.html.twig', $params); - }); - - $controllers->get('/login/{api_name}/', function(Application $app, $api_name) { - $connector = \Bridge_Api::get_connector_by_name($app, $api_name); - - return $app->redirect($connector->get_auth_url()); - })->bind('prod_bridge_login'); - - $controllers->get('/callback/{api_name}/', function(Application $app, $api_name) { - $error_message = ''; - try { - $api = \Bridge_Api::get_by_api_name($app, $api_name); - $connector = $api->get_connector(); - - $response = $connector->connect(); - - $user_id = $connector->get_user_id(); - - try { - $account = \Bridge_Account::load_account_from_distant_id($app, $api, $app['authentication']->getUser(), $user_id); - } catch (\Bridge_Exception_AccountNotFound $e) { - $account = \Bridge_Account::create($app, $api, $app['authentication']->getUser(), $user_id, $connector->get_user_name()); - } - $settings = $account->get_settings(); - - if (isset($response['auth_token'])) - $settings->set('auth_token', $response['auth_token']); - if (isset($response['refresh_token'])) - $settings->set('refresh_token', $response['refresh_token']); - - $connector->set_auth_settings($settings); - - $connector->reconnect(); - } catch (\Exception $e) { - $error_message = $e->getMessage(); - } - - $params = array('error_message' => $error_message); - - return $app['twig']->render('prod/actions/Bridge/callback.html.twig', $params); - })->bind('prod_bridge_callback'); - - $controllers->get('/adapter/{account_id}/logout/', function(Application $app, $account_id) { - $account = \Bridge_Account::load_account($app, $account_id); - $app['require_connection']($account); - $account->get_api()->get_connector()->disconnect(); - - return $app->redirectPath('bridge_load_elements', array( - 'account_id' => $account_id, - 'type' => $account->get_api()->get_connector()->get_default_element_type(), - )); - }) + $controllers + ->get('/adapter/{account_id}/logout/', 'bridge.controller:doGetAccountLogout') ->bind('prod_bridge_account_logout') ->assert('account_id', '\d+'); - $controllers->post('/adapter/{account_id}/delete/' - , function($account_id) use ($app) { - $success = false; - $message = ''; - try { - $account = \Bridge_Account::load_account($app, $account_id); + $controllers + ->post('/adapter/{account_id}/delete/', 'bridge.controller:doPostAccountDelete') + ->assert('account_id', '\d+'); - if ($account->get_user()->get_id() !== $app['authentication']->getUser()->get_id()) { - throw new HttpException(403, 'Access forbiden'); - } - - $account->delete(); - $success = true; - } catch (\Bridge_Exception_AccountNotFound $e) { - $message = _('Account is not found.'); - } catch (\Exception $e) { - $message = _('Something went wrong, please contact an administrator'); - } - - return $app->json(array('success' => $success, 'message' => $message)); - })->assert('account_id', '\d+'); - - $controllers->get('/adapter/{account_id}/load-records/', function(Application $app, $account_id) { - $page = max((int) $app['request']->query->get('page'), 0); - $quantity = 10; - $offset_start = max(($page - 1) * $quantity, 0); - $account = \Bridge_Account::load_account($app, $account_id); - $elements = \Bridge_Element::get_elements_by_account($app, $account, $offset_start, $quantity); - - $app['require_connection']($account); - - $params = array( - 'adapter_action' => 'load-records' - , 'account' => $account - , 'elements' => $elements - , 'error_message' => $app['request']->query->get('error') - , 'notice_message' => $app['request']->query->get('notice') - ); - - return $app['twig']->render('prod/actions/Bridge/records_list.html.twig', $params); - }) + $controllers + ->get('/adapter/{account_id}/load-records/', 'bridge.controller:doGetloadRecords') ->bind('prod_bridge_account_loadrecords') ->assert('account_id', '\d+'); - $controllers->get('/adapter/{account_id}/load-elements/{type}/', function($account_id, $type) use ($app) { - $page = max((int) $app['request']->query->get('page'), 0); - $quantity = 5; - $offset_start = max(($page - 1) * $quantity, 0); - $account = \Bridge_Account::load_account($app, $account_id); - - $app['require_connection']($account); - - $elements = $account->get_api()->list_elements($type, $offset_start, $quantity); - - $params = array( - 'action_type' => $type - , 'adapter_action' => 'load-elements' - , 'account' => $account - , 'elements' => $elements - , 'error_message' => $app['request']->query->get('error') - , 'notice_message' => $app['request']->query->get('notice') - ); - - return $app['twig']->render('prod/actions/Bridge/element_list.html.twig', $params); - }) + $controllers + ->get('/adapter/{account_id}/load-elements/{type}/', 'bridge.controller:doGetLoadElements') ->bind('bridge_load_elements') ->assert('account_id', '\d+'); - $controllers->get('/adapter/{account_id}/load-containers/{type}/', function(Application $app, $account_id, $type) { - - $page = max((int) $app['request']->query->get('page'), 0); - $quantity = 5; - $offset_start = max(($page - 1) * $quantity, 0); - $account = \Bridge_Account::load_account($app, $account_id); - - $app['require_connection']($account); - $elements = $account->get_api()->list_containers($type, $offset_start, $quantity); - - $params = array( - 'action_type' => $type - , 'adapter_action' => 'load-containers' - , 'account' => $account - , 'elements' => $elements - , 'error_message' => $app['request']->query->get('error') - , 'notice_message' => $app['request']->query->get('notice') - ); - - return $app['twig']->render('prod/actions/Bridge/element_list.html.twig', $params); - }) + $controllers + ->get('/adapter/{account_id}/load-containers/{type}/', 'bridge.controller:doGetLoadContainers') ->bind('prod_bridge_account_loadcontainers') ->assert('account_id', '\d+'); - $controllers->get('/action/{account_id}/{action}/{element_type}/', function(Application $app, $account_id, $action, $element_type) { - - $account = \Bridge_Account::load_account($app, $account_id); - - $app['require_connection']($account); - $request = $app['request']; - $elements = $request->query->get('elements_list', array()); - $elements = is_array($elements) ? $elements : explode(';', $elements); - - $destination = $request->query->get('destination'); - $route_params = array(); - $class = $account->get_api()->get_connector()->get_object_class_from_type($element_type); - - switch ($action) { - case 'createcontainer': - break; - - case 'modify': - if (count($elements) != 1) { - return $app->redirectPath('bridge_load_elements', array( - 'account_id' => $account_id, - 'type' => $element_type, - 'page' => '', - 'error' => _('Vous ne pouvez pas editer plusieurs elements simultanement'), - )); - } - foreach ($elements as $element_id) { - if ($class === \Bridge_Api_Interface::OBJECT_CLASS_ELEMENT) { - $route_params = array('element' => $account->get_api()->get_element_from_id($element_id, $element_type)); - } - if ($class === \Bridge_Api_Interface::OBJECT_CLASS_CONTAINER) { - $route_params = array('element' => $account->get_api()->get_container_from_id($element_id, $element_type)); - } - } - break; - - case 'moveinto': - - $route_params = array('containers' => $account->get_api()->list_containers($destination, 0, 0)); - break; - - case 'deleteelement': - - break; - - default: - throw new \Exception(_('Vous essayez de faire une action que je ne connais pas !')); - break; - } - - $params = array( - 'account' => $account - , 'destination' => $destination - , 'element_type' => $element_type - , 'action' => $action - , 'constraint_errors' => null - , 'adapter_action' => $action - , 'elements' => $elements - , 'error_message' => $app['request']->query->get('error') - , 'notice_message' => $app['request']->query->get('notice') - ); - - $params = array_merge($params, $route_params); - - $template = 'prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/' . $element_type . '_' . $action . ($destination ? '_' . $destination : '') . '.html.twig'; - - return $app['twig']->render($template, $params); - }) + $controllers + ->get('/action/{account_id}/{action}/{element_type}/', 'bridge.controller:doGetAction') ->bind('bridge_account_action') ->assert('account_id', '\d+'); - $controllers->post('/action/{account_id}/{action}/{element_type}/', function(Application $app, $account_id, $action, $element_type) { - $account = \Bridge_Account::load_account($app, $account_id); - - $app['require_connection']($account); - - $request = $app['request']; - $elements = $request->request->get('elements_list', array()); - $elements = is_array($elements) ? $elements : explode(';', $elements); - - $destination = $request->request->get('destination'); - - $class = $account->get_api()->get_connector()->get_object_class_from_type($element_type); - $html = ''; - switch ($action) { - case 'modify': - if (count($elements) != 1) { - return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?elements_list=' . implode(';', $elements) . '&error=' . _('Vous ne pouvez pas editer plusieurs elements simultanement')); - } - try { - foreach ($elements as $element_id) { - $datas = $account->get_api()->get_connector()->get_update_datas($app['request']); - $errors = $account->get_api()->get_connector()->check_update_constraints($datas); - } - - if (count($errors) > 0) { - $params = array( - 'element' => $account->get_api()->get_element_from_id($element_id, $element_type) - , 'account' => $account - , 'destination' => $destination - , 'element_type' => $element_type - , 'action' => $action - , 'elements' => $elements - , 'adapter_action' => $action - , 'error_message' => _('Request contains invalid datas') - , 'constraint_errors' => $errors - , 'notice_message' => $app['request']->request->get('notice') - ); - - $template = 'prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/' . $element_type . '_' . $action . ($destination ? '_' . $destination : '') . '.html.twig'; - - return $app['twig']->render($template, $params); - } - - foreach ($elements as $element_id) { - $datas = $account->get_api()->get_connector()->get_update_datas($app['request']); - $account->get_api()->update_element($element_type, $element_id, $datas); - } - } catch (\Exception $e) { - return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?elements_list[]=' . $element_id . '&error=' . get_class($e) . ' : ' . $e->getMessage()); - } - - return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-' . $class . 's/' . $element_type . '/?page=&update=success#anchor'); - - break; - case 'createcontainer': - try { - - $container_type = $request->request->get('f_container_type'); - - $account->get_api()->create_container($container_type, $app['request']); - } catch (\Exception $e) { - return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?error=' . get_class($e) . ' : ' . $e->getMessage()); - } - - return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-' . $class . 's/' . $element_type . '/?page=&update=success#anchor'); - - break; - case 'moveinto': - try { - $container_id = $request->request->get('container_id'); - foreach ($elements as $element_id) { - $account->get_api()->add_element_to_container($element_type, $element_id, $destination, $container_id); - } - } catch (\Exception $e) { - return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?error=' . get_class($e) . ' : ' . $e->getMessage()); - } - - return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-containers/' . $destination . '/?page=&update=success#anchor'); - - break; - - case 'deleteelement': - try { - foreach ($elements as $element_id) { - $account->get_api()->delete_object($element_type, $element_id); - } - } catch (\Exception $e) { - return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?error=' . get_class($e) . $e->getMessage()); - } - - return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-' . $class . 's/' . $element_type . '/'); - break; - default: - throw new \Exception('Unknown action'); - break; - } - - return new Response($html); - }) + $controllers + ->post('/action/{account_id}/{action}/{element_type}/', 'bridge.controller:doPostAction') ->bind('bridge_account_do_action') ->assert('account_id', '\d+'); - $controllers->get('/upload/', function(Application $app) { - $request = $app['request']; - $account = \Bridge_Account::load_account($app, $request->query->get('account_id')); - $app['require_connection']($account); + $controllers + ->get('/upload/', 'bridge.controller:doGetUpload') + ->bind('prod_bridge_upload'); - $route = new RecordHelper\Bridge($app, $app['request']); - - $route->grep_records($account->get_api()->acceptable_records()); - - $params = array( - 'route' => $route - , 'account' => $account - , 'error_message' => $app['request']->query->get('error') - , 'notice_message' => $app['request']->query->get('notice') - , 'constraint_errors' => null - , 'adapter_action' => 'upload' - ); - - return $app['twig']->render( - 'prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/upload.html.twig', $params - ); - })->bind('prod_bridge_upload'); - - $controllers->post('/upload/', function(Application $app) { - $errors = array(); - $request = $app['request']; - $account = \Bridge_Account::load_account($app, $request->request->get('account_id')); - $app['require_connection']($account); - - $route = new RecordHelper\Bridge($app, $app['request']); - $route->grep_records($account->get_api()->acceptable_records()); - $connector = $account->get_api()->get_connector(); - - /** - * check constraints - */ - foreach ($route->get_elements() as $record) { - $datas = $connector->get_upload_datas($request, $record); - $errors = array_merge($errors, $connector->check_upload_constraints($datas, $record)); - } - - if (count($errors) > 0) { - - $params = array( - 'route' => $route - , 'account' => $account - , 'error_message' => _('Request contains invalid datas') - , 'constraint_errors' => $errors - , 'notice_message' => $app['request']->request->get('notice') - , 'adapter_action' => 'upload' - ); - - return $app['twig']->render('prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/upload.html.twig', $params); - } - - foreach ($route->get_elements() as $record) { - $datas = $connector->get_upload_datas($request, $record); - $title = isset($datas["title"]) ? $datas["title"] : ''; - $default_type = $connector->get_default_element_type(); - \Bridge_Element::create($app, $account, $record, $title, \Bridge_Element::STATUS_PENDING, $default_type, $datas); - } - - return $app->redirect('/prod/bridge/adapter/' . $account->get_id() . '/load-records/?notice=' . sprintf(_('%d elements en attente'), count($route->get_elements()))); - })->bind('prod_bridge_do_upload'); + $controllers + ->post('/upload/', 'bridge.controller:doPostUpload') + ->bind('prod_bridge_do_upload'); return $controllers; } + + private function requireConnection(Application $app, \Bridge_Account $account) + { + $app['bridge.account'] = $account; + + if (!$account->get_api()->get_connector()->is_configured()) { + throw new \Bridge_Exception_ApiConnectorNotConfigured("Bridge API Connector is not configured"); + } + if (!$account->get_api()->get_connector()->is_connected()) { + throw new \Bridge_Exception_ApiConnectorNotConnected("Bridge API Connector is not connected"); + } + } + + public function doPostManager(Application $app, Request $request) + { + $route = new RecordHelper\Bridge($app, $request); + $params = array( + 'user_accounts' => \Bridge_Account::get_accounts_by_user($app, $app['authentication']->getUser()), + 'available_apis' => \Bridge_Api::get_availables($app), + 'route' => $route, + 'current_account_id' => '', + ); + + return $app['twig']->render('prod/actions/Bridge/index.html.twig', $params); + } + + public function doGetLogin(Application $app, Request $request, $api_name) + { + $connector = \Bridge_Api::get_connector_by_name($app, $api_name); + + return $app->redirect($connector->get_auth_url()); + } + + public function doGetCallback(Application $app, Request $request, $api_name) + { + $error_message = ''; + try { + $api = \Bridge_Api::get_by_api_name($app, $api_name); + $connector = $api->get_connector(); + $response = $connector->connect(); + $user_id = $connector->get_user_id(); + + try { + $account = \Bridge_Account::load_account_from_distant_id($app, $api, $app['authentication']->getUser(), $user_id); + } catch (\Bridge_Exception_AccountNotFound $e) { + $account = \Bridge_Account::create($app, $api, $app['authentication']->getUser(), $user_id, $connector->get_user_name()); + } + + $settings = $account->get_settings(); + + if (isset($response['auth_token'])) { + $settings->set('auth_token', $response['auth_token']); + } + if (isset($response['refresh_token'])) { + $settings->set('refresh_token', $response['refresh_token']); + } + + $connector->set_auth_settings($settings); + $connector->reconnect(); + } catch (\Exception $e) { + $error_message = $e->getMessage(); + } + + $params = array('error_message' => $error_message); + + return $app['twig']->render('prod/actions/Bridge/callback.html.twig', $params); + } + + public function doGetAccountLogout(Application $app, Request $request, $account_id) + { + $account = \Bridge_Account::load_account($app, $account_id); + $this->requireConnection($app, $account); + $account->get_api()->get_connector()->disconnect(); + + return $app->redirectPath('bridge_load_elements', array( + 'account_id' => $account_id, + 'type' => $account->get_api()->get_connector()->get_default_element_type(), + )); + } + + public function doPostAccountDelete(Application $app, Request $request, $account_id) + { + $success = false; + $message = ''; + try { + $account = \Bridge_Account::load_account($app, $account_id); + + if ($account->get_user()->get_id() !== $app['authentication']->getUser()->get_id()) { + throw new HttpException(403, 'Access forbiden'); + } + + $account->delete(); + $success = true; + } catch (\Bridge_Exception_AccountNotFound $e) { + $message = _('Account is not found.'); + } catch (\Exception $e) { + $message = _('Something went wrong, please contact an administrator'); + } + + return $app->json(array('success' => $success, 'message' => $message)); + } + + public function doGetloadRecords(Application $app, Request $request, $account_id) + { + $page = max((int) $request->query->get('page'), 0); + $quantity = 10; + $offset_start = max(($page - 1) * $quantity, 0); + $account = \Bridge_Account::load_account($app, $account_id); + $elements = \Bridge_Element::get_elements_by_account($app, $account, $offset_start, $quantity); + + $this->requireConnection($app, $account); + + $params = array( + 'adapter_action' => 'load-records' + , 'account' => $account + , 'elements' => $elements + , 'error_message' => $request->query->get('error') + , 'notice_message' => $request->query->get('notice') + ); + + return $app['twig']->render('prod/actions/Bridge/records_list.html.twig', $params); + } + + public function doGetLoadElements(Application $app, Request $request, $account_id, $type) + { + $page = max((int) $request->query->get('page'), 0); + $quantity = 5; + $offset_start = max(($page - 1) * $quantity, 0); + $account = \Bridge_Account::load_account($app, $account_id); + + $this->requireConnection($app, $account); + + $elements = $account->get_api()->list_elements($type, $offset_start, $quantity); + + $params = array( + 'action_type' => $type, + 'adapter_action' => 'load-elements', + 'account' => $account, + 'elements' => $elements, + 'error_message' => $request->query->get('error'), + 'notice_message' => $request->query->get('notice'), + ); + + return $app['twig']->render('prod/actions/Bridge/element_list.html.twig', $params); + } + + public function doGetLoadContainers(Application $app, Request $request, $account_id, $type) + { + $page = max((int) $request->query->get('page'), 0); + $quantity = 5; + $offset_start = max(($page - 1) * $quantity, 0); + $account = \Bridge_Account::load_account($app, $account_id); + + $this->requireConnection($app, $account); + $elements = $account->get_api()->list_containers($type, $offset_start, $quantity); + + $params = array( + 'action_type' => $type, + 'adapter_action' => 'load-containers', + 'account' => $account, + 'elements' => $elements, + 'error_message' => $request->query->get('error'), + 'notice_message' => $request->query->get('notice'), + ); + + return $app['twig']->render('prod/actions/Bridge/element_list.html.twig', $params); + } + + public function doGetAction(Application $app, Request $request, $account_id, $action, $element_type) + { + $account = \Bridge_Account::load_account($app, $account_id); + + $this->requireConnection($app, $account); + $elements = $request->query->get('elements_list', array()); + $elements = is_array($elements) ? $elements : explode(';', $elements); + + $destination = $request->query->get('destination'); + $route_params = array(); + $class = $account->get_api()->get_connector()->get_object_class_from_type($element_type); + + switch ($action) { + case 'createcontainer': + break; + + case 'modify': + if (count($elements) != 1) { + return $app->redirectPath('bridge_load_elements', array( + 'account_id' => $account_id, + 'type' => $element_type, + 'page' => '', + 'error' => _('Vous ne pouvez pas editer plusieurs elements simultanement'), + )); + } + foreach ($elements as $element_id) { + if ($class === \Bridge_Api_Interface::OBJECT_CLASS_ELEMENT) { + $route_params = array('element' => $account->get_api()->get_element_from_id($element_id, $element_type)); + } + if ($class === \Bridge_Api_Interface::OBJECT_CLASS_CONTAINER) { + $route_params = array('element' => $account->get_api()->get_container_from_id($element_id, $element_type)); + } + } + break; + + case 'moveinto': + $route_params = array('containers' => $account->get_api()->list_containers($destination, 0, 0)); + break; + + case 'deleteelement': + break; + + default: + throw new \Exception(_('Vous essayez de faire une action que je ne connais pas !')); + break; + } + + $params = array( + 'account' => $account, + 'destination' => $destination, + 'element_type' => $element_type, + 'action' => $action, + 'constraint_errors' => null, + 'adapter_action' => $action, + 'elements' => $elements, + 'error_message' => $request->query->get('error'), + 'notice_message' => $request->query->get('notice'), + ); + + $params = array_merge($params, $route_params); + $template = 'prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/' . $element_type . '_' . $action . ($destination ? '_' . $destination : '') . '.html.twig'; + + return $app['twig']->render($template, $params); + } + + public function doPostAction(Application $app, Request $request, $account_id, $action, $element_type) + { + $account = \Bridge_Account::load_account($app, $account_id); + + $this->requireConnection($app, $account); + + $elements = $request->request->get('elements_list', array()); + $elements = is_array($elements) ? $elements : explode(';', $elements); + + $destination = $request->request->get('destination'); + + $class = $account->get_api()->get_connector()->get_object_class_from_type($element_type); + $html = ''; + switch ($action) { + case 'modify': + if (count($elements) != 1) { + return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?elements_list=' . implode(';', $elements) . '&error=' . _('Vous ne pouvez pas editer plusieurs elements simultanement')); + } + try { + foreach ($elements as $element_id) { + $datas = $account->get_api()->get_connector()->get_update_datas($request); + $errors = $account->get_api()->get_connector()->check_update_constraints($datas); + } + + if (count($errors) > 0) { + $params = array( + 'element' => $account->get_api()->get_element_from_id($element_id, $element_type), + 'account' => $account, + 'destination' => $destination, + 'element_type' => $element_type, + 'action' => $action, + 'elements' => $elements, + 'adapter_action' => $action, + 'error_message' => _('Request contains invalid datas'), + 'constraint_errors' => $errors, + 'notice_message' => $request->request->get('notice'), + ); + + $template = 'prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/' . $element_type . '_' . $action . ($destination ? '_' . $destination : '') . '.html.twig'; + + return $app['twig']->render($template, $params); + } + + foreach ($elements as $element_id) { + $datas = $account->get_api()->get_connector()->get_update_datas($request); + $account->get_api()->update_element($element_type, $element_id, $datas); + } + } catch (\Exception $e) { + return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?elements_list[]=' . $element_id . '&error=' . get_class($e) . ' : ' . $e->getMessage()); + } + + return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-' . $class . 's/' . $element_type . '/?page=&update=success#anchor'); + case 'createcontainer': + try { + $container_type = $request->request->get('f_container_type'); + + $account->get_api()->create_container($container_type, $request); + } catch (\Exception $e) { + return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?error=' . get_class($e) . ' : ' . $e->getMessage()); + } + + return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-' . $class . 's/' . $element_type . '/?page=&update=success#anchor'); + case 'moveinto': + try { + $container_id = $request->request->get('container_id'); + foreach ($elements as $element_id) { + $account->get_api()->add_element_to_container($element_type, $element_id, $destination, $container_id); + } + } catch (\Exception $e) { + return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?error=' . get_class($e) . ' : ' . $e->getMessage()); + } + + return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-containers/' . $destination . '/?page=&update=success#anchor'); + case 'deleteelement': + try { + foreach ($elements as $element_id) { + $account->get_api()->delete_object($element_type, $element_id); + } + } catch (\Exception $e) { + return $app->redirect('/prod/bridge/action/' . $account_id . '/' . $action . '/' . $element_type . '/?error=' . get_class($e) . $e->getMessage()); + } + + return $app->redirect('/prod/bridge/adapter/' . $account_id . '/load-' . $class . 's/' . $element_type . '/'); + default: + throw new \Exception('Unknown action'); + break; + } + + return new Response($html); + } + + public function doGetUpload(Application $app, Request $request) + { + $account = \Bridge_Account::load_account($app, $request->query->get('account_id')); + $this->requireConnection($app, $account); + + $route = new RecordHelper\Bridge($app, $request); + + $route->grep_records($account->get_api()->acceptable_records()); + + $params = array( + 'route' => $route, + 'account' => $account, + 'error_message' => $request->query->get('error'), + 'notice_message' => $request->query->get('notice'), + 'constraint_errors' => null, + 'adapter_action' => 'upload', + ); + + return $app['twig']->render( + 'prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/upload.html.twig', $params + ); + } + + public function doPostUpload(Application $app, Request $request) + { + $errors = array(); + $account = \Bridge_Account::load_account($app, $request->request->get('account_id')); + $this->requireConnection($app, $account); + + $route = new RecordHelper\Bridge($app, $request); + $route->grep_records($account->get_api()->acceptable_records()); + $connector = $account->get_api()->get_connector(); + + // check constraints + foreach ($route->get_elements() as $record) { + $datas = $connector->get_upload_datas($request, $record); + $errors = array_merge($errors, $connector->check_upload_constraints($datas, $record)); + } + + if (count($errors) > 0) { + $params = array( + 'route' => $route, + 'account' => $account, + 'error_message' => _('Request contains invalid datas'), + 'constraint_errors' => $errors, + 'notice_message' => $request->request->get('notice'), + 'adapter_action' => 'upload', + ); + + return $app['twig']->render('prod/actions/Bridge/' . $account->get_api()->get_connector()->get_name() . '/upload.html.twig', $params); + } + + foreach ($route->get_elements() as $record) { + $datas = $connector->get_upload_datas($request, $record); + $title = isset($datas["title"]) ? $datas["title"] : ''; + $default_type = $connector->get_default_element_type(); + \Bridge_Element::create($app, $account, $record, $title, \Bridge_Element::STATUS_PENDING, $default_type, $datas); + } + + return $app->redirect('/prod/bridge/adapter/' . $account->get_id() . '/load-records/?notice=' . sprintf(_('%d elements en attente'), count($route->get_elements()))); + } } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php b/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php index 18ccc632b6..fd71ac62a6 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php @@ -15,6 +15,7 @@ use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class DoDownload implements ControllerProviderInterface { @@ -91,11 +92,7 @@ class DoDownload implements ControllerProviderInterface */ public function prepareDownload(Application $app, Request $request, $token) { - try { - $datas = $app['tokens']->helloToken($token); - } catch (\Exception_NotFound $e) { - $app->abort(404, 'Invalid token'); - } + $datas = $app['tokens']->helloToken($token); if (false === $list = @unserialize((string) $datas['datas'])) { $app->abort(500, 'Invalid datas'); @@ -140,11 +137,7 @@ class DoDownload implements ControllerProviderInterface */ public function downloadDocuments(Application $app, Request $request, $token) { - try { - $datas = $app['tokens']->helloToken($token); - } catch (\Exception_NotFound $e) { - $app->abort(404, 'Invalid token'); - } + $datas = $app['tokens']->helloToken($token); if (false === $list = @unserialize((string) $datas['datas'])) { $app->abort(500, 'Invalid datas'); @@ -160,7 +153,7 @@ class DoDownload implements ControllerProviderInterface $mime = $subdef['mime']; $list['complete'] = true; } else { - $exportFile = __DIR__ . '/../../../../../tmp/download/' . $datas['value'] . '.zip'; + $exportFile = $app['root.path'] . '/tmp/download/' . $datas['value'] . '.zip'; $mime = 'application/zip'; } @@ -202,7 +195,7 @@ class DoDownload implements ControllerProviderInterface { try { $datas = $app['tokens']->helloToken($token); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { return $app->json(array( 'success' => false, 'message' => 'Invalid token' @@ -225,7 +218,7 @@ class DoDownload implements ControllerProviderInterface $app, $token, $list, - sprintf('%s/../../../../../tmp/download/%s.zip', __DIR__, $datas['value']) // Dest file + sprintf($app['root.path'] . '/tmp/download/%s.zip', $datas['value']) // Dest file ); return $app->json(array( diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Feed.php b/lib/Alchemy/Phrasea/Controller/Prod/Feed.php index 7cce1ae8b5..36ff032d48 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Feed.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Feed.php @@ -16,6 +16,8 @@ use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -79,7 +81,7 @@ class Feed implements ControllerProviderInterface $entry = \Feed_Entry_Adapter::load_from_id($app, $id); if (!$entry->is_publisher($app['authentication']->getUser())) { - throw new \Exception_UnauthorizedAction(); + throw new AccessDeniedHttpException(); } $feeds = \Feed_Collection::load_all($app, $app['authentication']->getUser()); @@ -102,7 +104,7 @@ class Feed implements ControllerProviderInterface $entry = \Feed_Entry_Adapter::load_from_id($app, $id); if (!$entry->is_publisher($app['authentication']->getUser())) { - throw new \Exception_UnauthorizedAction(); + throw new AccessDeniedHttpException(); } $title = $request->request->get('title'); @@ -120,12 +122,12 @@ class Feed implements ControllerProviderInterface if ($current_feed_id != $new_feed_id) { try { $new_feed = \Feed_Adapter::load_with_user($app, $app['authentication']->getUser(), $new_feed_id); - } catch (\Exception_NotFound $e) { - throw new \Exception_Forbidden('You have no access to this feed'); + } catch (NotFoundHttpException $e) { + throw new AccessDeniedHttpException('You have no access to this feed'); } if (!$new_feed->is_publisher($app['authentication']->getUser())) { - throw new \Exception_Forbidden('You are not publisher of this feed'); + throw new AccessDeniedHttpException('You are not publisher of this feed'); } $entry->set_feed($new_feed); @@ -151,10 +153,10 @@ class Feed implements ControllerProviderInterface } catch (\Exception_Feed_EntryNotFound $e) { $app['phraseanet.appbox']->get_connection()->rollBack(); $datas['message'] = _('Feed entry not found'); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $app['phraseanet.appbox']->get_connection()->rollBack(); $datas['message'] = _('Feed not found'); - } catch (\Exception_Forbidden $e) { + } catch (AccessDeniedHttpException $e) { $app['phraseanet.appbox']->get_connection()->rollBack(); $datas['message'] = _('You are not authorized to access this feed'); } catch (\Exception $e) { @@ -178,7 +180,7 @@ class Feed implements ControllerProviderInterface if (!$entry->is_publisher($app['authentication']->getUser()) && $entry->get_feed()->is_owner($app['authentication']->getUser()) === false) { - throw new \Exception_UnauthorizedAction(_('Action Forbidden : You are not the publisher')); + throw new AccessDeniedHttpException(_('Action Forbidden : You are not the publisher')); } $entry->delete(); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/MustacheLoader.php b/lib/Alchemy/Phrasea/Controller/Prod/MustacheLoader.php index 80ccb8f622..ac7fb7a018 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/MustacheLoader.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/MustacheLoader.php @@ -14,6 +14,8 @@ namespace Alchemy\Phrasea\Controller\Prod; use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -31,13 +33,13 @@ class MustacheLoader implements ControllerProviderInterface $template_name = $request->query->get('template'); if (!preg_match('/^[a-zA-Z0-9-_]+$/', $template_name)) { - throw new \Exception_BadRequest('Wrong template name : ' . $template_name); + throw new BadRequestHttpException('Wrong template name : ' . $template_name); } $template_path = realpath(__DIR__ . '/../../../../../templates/web/Mustache/Prod/' . $template_name . '.Mustache.html'); if (!file_exists($template_path)) { - throw new \Exception_NotFound('Template does not exists : ' . $template_path); + throw new NotFoundHttpException('Template does not exists : ' . $template_path); } return new \Symfony\Component\HttpFoundation\Response(file_get_contents($template_path)); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Order.php b/lib/Alchemy/Phrasea/Controller/Prod/Order.php index 4771b3260e..a1943c348a 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Order.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Order.php @@ -255,11 +255,7 @@ class Order implements ControllerProviderInterface */ public function displayOneOrder(Application $app, Request $request, $order_id) { - try { - $order = new \set_order($app, $order_id); - } catch (\Exception_NotFound $e) { - $app->abort(404); - } + $order = new \set_order($app, $order_id); return $app['twig']->render('prod/orders/order_item.html.twig', array( 'order' => $order @@ -278,11 +274,7 @@ class Order implements ControllerProviderInterface { $success = false; - try { - $order = new \set_order($app, $order_id); - } catch (\Exception_NotFound $e) { - $app->abort(404); - } + $order = new \set_order($app, $order_id); try { $order->send_elements($app, $request->request->get('elements', array()), !!$request->request->get('force', false)); @@ -317,11 +309,7 @@ class Order implements ControllerProviderInterface { $success = false; - try { - $order = new \set_order($app, $order_id); - } catch (\Exception_NotFound $e) { - $app->abort(404); - } + $order = new \set_order($app, $order_id); try { $order->deny_elements($request->request->get('elements', array())); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Push.php b/lib/Alchemy/Phrasea/Controller/Prod/Push.php index 540b0d5825..df58094346 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Push.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Push.php @@ -17,6 +17,7 @@ use Alchemy\Phrasea\Helper\Record as RecordHelper; use Alchemy\Phrasea\Controller\Exception as ControllerException; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -370,7 +371,7 @@ class Push implements ControllerProviderInterface try { $Participant = $Validation->getParticipant($participant_user, $app); continue; - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Root.php b/lib/Alchemy/Phrasea/Controller/Prod/Root.php index 74027111f8..c4a278907f 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Root.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Root.php @@ -32,7 +32,6 @@ class Root implements ControllerProviderInterface $controllers = $app['controllers_factory']; $controllers->before(function(Request $request) use ($app) { - if (!$app['authentication']->isAuthenticated() && null !== $request->query->get('nolog')) { return $app->redirectPath('login_authenticate_as_guest'); } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Story.php b/lib/Alchemy/Phrasea/Controller/Prod/Story.php index be3de67a06..7661a2d360 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Story.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Story.php @@ -17,6 +17,7 @@ use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @@ -43,7 +44,7 @@ class Story implements ControllerProviderInterface $collection = \collection::get_from_base_id($app, $request->request->get('base_id')); if (!$app['authentication']->getUser()->ACL()->has_right_on_base($collection->get_base_id(), 'canaddrecord')) { - throw new \Exception_Forbidden('You can not create a story on this collection'); + throw new AccessDeniedHttpException('You can not create a story on this collection'); } $Story = \record_adapter::createStory($app, $collection); @@ -121,7 +122,7 @@ class Story implements ControllerProviderInterface $Story = new \record_adapter($app, $sbas_id, $record_id); if (!$app['authentication']->getUser()->ACL()->has_right_on_base($Story->get_base_id(), 'canmodifrecord')) - throw new \Exception_Forbidden('You can not add document to this Story'); + throw new AccessDeniedHttpException('You can not add document to this Story'); $n = 0; @@ -154,7 +155,7 @@ class Story implements ControllerProviderInterface $record = new \record_adapter($app, $child_sbas_id, $child_record_id); if (!$app['authentication']->getUser()->ACL()->has_right_on_base($Story->get_base_id(), 'canmodifrecord')) - throw new \Exception_Forbidden('You can not add document to this Story'); + throw new AccessDeniedHttpException('You can not add document to this Story'); $Story->removeChild($record); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Upload.php b/lib/Alchemy/Phrasea/Controller/Prod/Upload.php index a5bb086979..8e96e4b69c 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/Upload.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/Upload.php @@ -19,6 +19,8 @@ use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * Upload controller collection @@ -159,27 +161,27 @@ class Upload implements ControllerProviderInterface ); if (null === $request->files->get('files')) { - throw new \Exception_BadRequest('Missing file parameter'); + throw new BadRequestHttpException('Missing file parameter'); } if (count($request->files->get('files')) > 1) { - throw new \Exception_BadRequest('Upload is limited to 1 file per request'); + throw new BadRequestHttpException('Upload is limited to 1 file per request'); } $base_id = $request->request->get('base_id'); if (!$base_id) { - throw new \Exception_BadRequest('Missing base_id parameter'); + throw new BadRequestHttpException('Missing base_id parameter'); } if (!$app['authentication']->getUser()->ACL()->has_right_on_base($base_id, 'canaddrecord')) { - throw new \Exception_Forbidden('User is not allowed to add record on this collection'); + throw new AccessDeniedHttpException('User is not allowed to add record on this collection'); } $file = current($request->files->get('files')); if (!$file->isValid()) { - throw new \Exception_BadRequest('Uploaded file is invalid'); + throw new BadRequestHttpException('Uploaded file is invalid'); } try { diff --git a/lib/Alchemy/Phrasea/Controller/Prod/UsrLists.php b/lib/Alchemy/Phrasea/Controller/Prod/UsrLists.php index c543431ddd..9f47f7f9bc 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/UsrLists.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/UsrLists.php @@ -19,6 +19,7 @@ use Silex\ControllerProviderInterface; use Alchemy\Phrasea\Controller\Exception as ControllerException; use Symfony\Component\HttpFoundation\Request; use Doctrine\Common\Collections\ArrayCollection; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; /** * @@ -477,9 +478,9 @@ class UsrLists implements ControllerProviderInterface ); if (!$app['request']->request->get('role')) - throw new \Exception_BadRequest('Missing role parameter'); + throw new BadRequestHttpException('Missing role parameter'); elseif (!in_array($app['request']->request->get('role'), $availableRoles)) - throw new \Exception_BadRequest('Role is invalid'); + throw new BadRequestHttpException('Role is invalid'); try { $repository = $app['EM']->getRepository('\Entities\UsrList'); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php b/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php index 19b658cfd4..89b5ce7c6f 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/WorkZone.php @@ -16,6 +16,9 @@ use Silex\Application; use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\Request; use Alchemy\Phrasea\Helper\WorkZone as WorkzoneHelper; +use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -121,7 +124,7 @@ class WorkZone implements ControllerProviderInterface public function attachStories(Application $app, Request $request) { if (!$request->request->get('stories')) { - throw new \Exception_BadRequest(); + throw new BadRequestHttpException('Missing parameters stories'); } $StoryWZRepo = $app['EM']->getRepository('\Entities\StoryWZ'); @@ -139,7 +142,7 @@ class WorkZone implements ControllerProviderInterface } if (!$app['authentication']->getUser()->ACL()->has_access_to_base($Story->get_base_id())) { - throw new \Exception_Forbidden('You do not have access to this Story'); + throw new AccessDeniedHttpException('You do not have access to this Story'); } if ($StoryWZRepo->findUserStory($app, $app['authentication']->getUser(), $Story)) { @@ -205,7 +208,7 @@ class WorkZone implements ControllerProviderInterface $StoryWZ = $repository->findUserStory($app, $app['authentication']->getUser(), $Story); if (!$StoryWZ) { - throw new \Exception_NotFound('Story not found'); + throw new NotFoundHttpException('Story not found'); } $app['EM']->remove($StoryWZ); diff --git a/lib/Alchemy/Phrasea/Controller/RecordsRequest.php b/lib/Alchemy/Phrasea/Controller/RecordsRequest.php index 970c929190..64b8010168 100644 --- a/lib/Alchemy/Phrasea/Controller/RecordsRequest.php +++ b/lib/Alchemy/Phrasea/Controller/RecordsRequest.php @@ -15,6 +15,7 @@ use Entities\Basket; use Doctrine\Common\Collections\ArrayCollection; use Alchemy\Phrasea\Application; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class RecordsRequest extends ArrayCollection { @@ -223,7 +224,7 @@ class RecordsRequest extends ArrayCollection $record = new \record_adapter($app, (int) $basrec[0], (int) $basrec[1]); $received[$record->get_serialize_key()] = $record; unset($record); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { continue; } } diff --git a/lib/Alchemy/Phrasea/Controller/Root/Account.php b/lib/Alchemy/Phrasea/Controller/Root/Account.php index 39c47926f9..39bb3c2cf3 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Account.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Account.php @@ -22,6 +22,7 @@ use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class Account implements ControllerProviderInterface { @@ -221,7 +222,7 @@ class Account implements ControllerProviderInterface ); $account->set_revoked((bool) $request->query->get('revoke'), false); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $error = true; } diff --git a/lib/Alchemy/Phrasea/Controller/Root/Developers.php b/lib/Alchemy/Phrasea/Controller/Root/Developers.php index ae15b62746..d86c04c0b5 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Developers.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Developers.php @@ -16,6 +16,7 @@ use Silex\ControllerProviderInterface; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -189,7 +190,7 @@ class Developers implements ControllerProviderInterface try { $clientApp = new \API_OAuth2_Application($app, $id); $clientApp->delete(); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $error = true; } @@ -220,7 +221,7 @@ class Developers implements ControllerProviderInterface } else { $error = true; } - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $error = true; } @@ -283,7 +284,7 @@ class Developers implements ControllerProviderInterface try { $clientApp = new \API_OAuth2_Application($app, $id); $clientApp->set_grant_password((bool) $request->request->get('grant', false)); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $error = true; } @@ -368,7 +369,7 @@ class Developers implements ControllerProviderInterface { try { $client = new \API_OAuth2_Application($app, $id); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $app->abort(404); } diff --git a/lib/Alchemy/Phrasea/Controller/Root/Login.php b/lib/Alchemy/Phrasea/Controller/Root/Login.php index 58b47aaecd..a59081bf46 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/Login.php +++ b/lib/Alchemy/Phrasea/Controller/Root/Login.php @@ -474,7 +474,7 @@ class Login implements ControllerProviderInterface try { $datas = $app['tokens']->helloToken($code); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $app->addFlash('error', _('Invalid unlock link.')); return $app->redirectPath('homepage'); @@ -795,7 +795,7 @@ class Login implements ControllerProviderInterface try { $token = $this->app['tokens']->getValidationToken($participantId, $basketId); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { continue; } diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php new file mode 100644 index 0000000000..c7374e0b28 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriber.php @@ -0,0 +1,75 @@ +app = $app; + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::EXCEPTION => array('onSilexError', 0), + ); + } + + public function onSilexError(GetResponseForExceptionEvent $event) + { + $headers = array(); + $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; + } 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; + } elseif ($e instanceof NotFoundHttpException) { + $code = \API_V1_result::ERROR_NOTFOUND; + } else { + $code = \API_V1_result::ERROR_INTERNALSERVERERROR; + } + + if ($e instanceof HttpException) { + $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()); + + foreach ($headers as $key => $value) { + $response->headers->set($key, $value); + } + + $event->setResponse($response); + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriber.php new file mode 100644 index 0000000000..f0ea27a88e --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriber.php @@ -0,0 +1,64 @@ +handler = $handler; + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::EXCEPTION => array('onSilexError', 20), + ); + } + + public function onSilexError(GetResponseForExceptionEvent $event) + { + $request = $event->getRequest(); + + if (0 !== strpos($request->getPathInfo(), '/api/oauthv2')) { + return; + } + + $e = $event->getException(); + + $code = 500; + $msg = _('Whoops, looks like something went wrong.'); + $headers = array(); + + if ($e instanceof HttpExceptionInterface) { + $headers = $e->getHeaders(); + $msg = $e->getMessage(); + $code = $e->getStatusCode(); + } + + if (isset($headers['content-type']) && $headers['content-type'] == 'application/json') { + $msg = json_encode(array('msg' => $msg, 'code' => $code)); + $event->setResponse(new Response($msg, $code, $headers)); + } else { + $event->setResponse($this->handler->createResponseBasedOnRequest($event->getRequest(), $event->getException())); + } + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/BridgeExceptionSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/BridgeExceptionSubscriber.php new file mode 100644 index 0000000000..b0ceeb3d09 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/BridgeExceptionSubscriber.php @@ -0,0 +1,79 @@ +app = $app; + } + + public function onSilexError(GetResponseForExceptionEvent $event) + { + if (!$event->getException() instanceof \Bridge_Exception) { + return; + } + + $e = $event->getException(); + $request = $event->getRequest(); + + $params = array( + 'account' => null, + 'elements' => array(), + 'message' => $e->getMessage(), + 'error_message' => null, + 'notice_message' => null, + 'file' => $e->getFile(), + 'line' => $e->getLine(), + 'r_method' => $request->getMethod(), + 'r_action' => $request->getRequestUri(), + 'r_parameters' => ($request->getMethod() == 'GET' ? array() : $request->request->all()), + ); + + if ($e instanceof \Bridge_Exception_ApiConnectorNotConfigured) { + $params = array_replace($params, array('account' => $this->app['bridge.account'])); + $response = new Response($this->app['twig']->render('/prod/actions/Bridge/notconfigured.html.twig', $params), 200, array('X-Status-Code' => 200)); + } elseif ($e instanceof \Bridge_Exception_ApiConnectorNotConnected) { + $params = array_replace($params, array('account' => $this->app['bridge.account'])); + $response = new Response($this->app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); + } elseif ($e instanceof \Bridge_Exception_ApiConnectorAccessTokenFailed) { + $params = array_replace($params, array('account' => $this->app['bridge.account'])); + $response = new Response($this->app['twig']->render('/prod/actions/Bridge/disconnected.html.twig', $params), 200, array('X-Status-Code' => 200)); + } elseif ($e instanceof \Bridge_Exception_ApiDisabled) { + $params = array_replace($params, array('api' => $e->get_api())); + $response = new Response($this->app['twig']->render('/prod/actions/Bridge/deactivated.html.twig', $params), 200, array('X-Status-Code' => 200)); + } else { + $response = new Response($this->app['twig']->render('/prod/actions/Bridge/error.html.twig', $params), 200, array('X-Status-Code' => 200)); + } + + $response->headers->set('Phrasea-StatusCode', 200); + + $event->setResponse($response); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array(KernelEvents::EXCEPTION => array('onSilexError', 20)); + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/DebuggerSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/DebuggerSubscriber.php new file mode 100644 index 0000000000..76e11186bc --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/DebuggerSubscriber.php @@ -0,0 +1,59 @@ +app = $app; + } + + public static function getSubscribedEvents() + { + return array( + KernelEvents::REQUEST => array( + array('checkIp', 255), + ), + ); + } + + public function checkIp(GetResponseEvent $event) + { + if (Application::ENV_DEV !== $this->app->getEnvironment()) { + return; + } + + if (isset($this->app['phraseanet.configuration']['debugger']) + && isset($this->app['phraseanet.configuration']['debugger']['allowed-ips'])) { + + $allowedIps = $this->app['phraseanet.configuration']['debugger']['allowed-ips']; + $allowedIps = is_array($allowedIps) ? $allowedIps : array($allowedIps); + } else { + $allowedIps = array(); + } + + $ips = array_merge(array('127.0.0.1', 'fe80::1', '::1'), $allowedIps); + + if (!in_array($event->getRequest()->getClientIp(), $ips)) { + throw new AccessDeniedHttpException('You are not allowed to access this file. Check index_dev.php for more information.'); + } + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/FirewallSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/FirewallSubscriber.php new file mode 100644 index 0000000000..f28c2662a9 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/FirewallSubscriber.php @@ -0,0 +1,50 @@ + array('onKernelResponse', 0), + KernelEvents::EXCEPTION => array('onSilexError', 20), + ); + } + + public function onKernelResponse(FilterResponseEvent $event) + { + if ($event->getResponse()->headers->has('X-Phraseanet-Redirect')) { + $event->getResponse()->headers->remove('X-Phraseanet-Redirect'); + } + } + + public function onSilexError(GetResponseForExceptionEvent $event) + { + $e = $event->getException(); + + if ($e instanceof HttpExceptionInterface) { + $headers = $e->getHeaders(); + + if (isset($headers['X-Phraseanet-Redirect'])) { + $event->setResponse(new RedirectResponse($headers['X-Phraseanet-Redirect'], 302, array('X-Status-Code' => 302))); + } + } + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/JsonRequestSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/JsonRequestSubscriber.php new file mode 100644 index 0000000000..d21e902e69 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/JsonRequestSubscriber.php @@ -0,0 +1,46 @@ +getException(); + $request = $event->getRequest(); + + if ((0 !== strpos($request->getPathInfo(), '/admin/') + || 0 === strpos($request->getPathInfo(), '/admin/collection/') + || 0 === strpos($request->getPathInfo(), '/admin/databox/')) + && $request->getRequestFormat() == 'json') { + $datas = array( + 'success' => false, + 'message' => $exception->getMessage(), + ); + + $event->setResponse(new JsonResponse($datas, 200, array('X-Status-Code' => 200))); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array(KernelEvents::EXCEPTION => array('onSilexError', 10)); + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/Logout.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/LogoutSubscriber.php similarity index 92% rename from lib/Alchemy/Phrasea/Core/Event/Subscriber/Logout.php rename to lib/Alchemy/Phrasea/Core/Event/Subscriber/LogoutSubscriber.php index 51ab856ac5..74c4372ff0 100644 --- a/lib/Alchemy/Phrasea/Core/Event/Subscriber/Logout.php +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/LogoutSubscriber.php @@ -15,7 +15,7 @@ use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Core\Event\LogoutEvent; use Symfony\Component\EventDispatcher\EventSubscriberInterface; -class Logout implements EventSubscriberInterface +class LogoutSubscriber implements EventSubscriberInterface { public function onLogout(LogoutEvent $event) { diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/PhraseaExceptionHandlerSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/PhraseaExceptionHandlerSubscriber.php new file mode 100644 index 0000000000..24973b0a73 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/PhraseaExceptionHandlerSubscriber.php @@ -0,0 +1,51 @@ +enabled = true; + $this->handler = $handler; + } + + public function disable() + { + $this->enabled = false; + } + + public function onSilexError(GetResponseForExceptionEvent $event) + { + if (!$this->enabled) { + return; + } + + $event->setResponse($this->handler->createResponseBasedOnRequest($event->getRequest(), $event->getException())); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array(KernelEvents::EXCEPTION => array('onSilexError', 0)); + } +} diff --git a/lib/Alchemy/Phrasea/Core/PhraseaExceptionHandler.php b/lib/Alchemy/Phrasea/Core/PhraseaExceptionHandler.php new file mode 100644 index 0000000000..82764c562f --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/PhraseaExceptionHandler.php @@ -0,0 +1,143 @@ +getStatusCode(): + $title = _('Sorry, the page you are looking for could not be found.'); + break; + case 403 === $exception->getStatusCode(): + $title = _('Sorry, you do have access to the page you are looking for.'); + break; + case 500 === $exception->getStatusCode(): + $title = _('Whoops, looks like something went wrong.'); + break; + case isset(Response::$statusTexts[$exception->getStatusCode()]): + $title = $exception->getStatusCode() . ' : ' . Response::$statusTexts[$exception->getStatusCode()]; + break; + default: + $title = 'Whoops, looks like something went wrong.'; + } + + $content = parent::getContent($exception); + $start = strpos($content, ''); + + $content = '
' + . '

' . $title . '

' + . substr($content, $start); + + return $content; + } + + public function getStylesheet(FlattenException $exception) + { + $exception->getStatusCode(); + + switch ($exception->getStatusCode()) { + case 403: + $errorImg = '/skins/error-pages/403.png'; + break; + case 404: + $errorImg = '/skins/error-pages/404.png'; + break; + case 500: + $errorImg = '/skins/error-pages/500.png'; + break; + default: + $errorImg = '/skins/error-pages/error.png'; + break; + } + + return <<share(function () { return new Compiler(); diff --git a/lib/Alchemy/Phrasea/Core/Provider/JMSSerializerServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/JMSSerializerServiceProvider.php index eae25302a7..c64fc696a7 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/JMSSerializerServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/JMSSerializerServiceProvider.php @@ -21,8 +21,8 @@ class JMSSerializerServiceProvider implements ServiceProviderInterface { public function register(Application $app) { - $app['serializer.cache-directory'] = __DIR__ . '/../../../../../tmp/serializer/'; - $app['serializer.src_directory'] = __DIR__ . '/../../../../../vendor/jms/serializer/src/'; + $app['serializer.cache-directory'] = $app['root.path'] . '/tmp/serializer/'; + $app['serializer.src_directory'] = $app['root.path'] . '/vendor/jms/serializer/src/'; $app['serializer.metadata.annotation_reader'] = $app->share(function () use ($app) { AnnotationRegistry::registerAutoloadNamespace("JMS\Serializer\Annotation", $app['serializer.src_directory']); diff --git a/lib/Alchemy/Phrasea/Form/Constraint/PasswordToken.php b/lib/Alchemy/Phrasea/Form/Constraint/PasswordToken.php index d5a4eacb5c..9fddddc466 100644 --- a/lib/Alchemy/Phrasea/Form/Constraint/PasswordToken.php +++ b/lib/Alchemy/Phrasea/Form/Constraint/PasswordToken.php @@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Form\Constraint; use Alchemy\Phrasea\Application; use Symfony\Component\Validator\Constraint; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class PasswordToken extends Constraint { @@ -32,7 +33,7 @@ class PasswordToken extends Constraint { try { $data = $this->random->helloToken($token); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { return false; } diff --git a/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php b/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php index 19a052201f..2ab5728239 100644 --- a/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php +++ b/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php @@ -44,7 +44,6 @@ class PhraseaRegisterForm extends AbstractType ), )); - $builder->add('password', 'repeated', array( 'type' => 'password', 'required' => true, diff --git a/lib/Alchemy/Phrasea/Helper/User/Edit.php b/lib/Alchemy/Phrasea/Helper/User/Edit.php index 486ce8ac1e..8d22e09402 100644 --- a/lib/Alchemy/Phrasea/Helper/User/Edit.php +++ b/lib/Alchemy/Phrasea/Helper/User/Edit.php @@ -16,6 +16,7 @@ use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Notification\Mail\MailSuccessEmailUpdate; use Alchemy\Phrasea\Notification\Receiver; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @@ -644,7 +645,7 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper $template = \User_adapter::getInstance($this->request->get('template'), $this->app); if ($template->get_template_owner()->get_id() != $this->app['authentication']->getUser()->get_id()) { - throw new \Exception_Forbidden('You are not the owner of the template'); + throw new AccessDeniedHttpException('You are not the owner of the template'); } $base_ids = array_keys($this->app['authentication']->getUser()->ACL()->get_granted_base(array('canadmin'))); diff --git a/lib/Doctrine/Entities/ValidationSession.php b/lib/Doctrine/Entities/ValidationSession.php index 75c681f9b8..0282985a06 100644 --- a/lib/Doctrine/Entities/ValidationSession.php +++ b/lib/Doctrine/Entities/ValidationSession.php @@ -12,6 +12,7 @@ namespace Entities; use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * Kernel @@ -279,7 +280,7 @@ class ValidationSession } } - throw new \Exception_NotFound('Particpant not found' . $user->get_email()); + throw new NotFoundHttpException('Particpant not found' . $user->get_email()); } /** * @var integer $initiator @@ -380,7 +381,7 @@ class ValidationSession public function addParticipant(\Entities\ValidationParticipant $participants) { $this->participants[] = $participants; - + return $this; } diff --git a/lib/Doctrine/Repositories/BasketElementRepository.php b/lib/Doctrine/Repositories/BasketElementRepository.php index 11d47cfac9..304a624eae 100644 --- a/lib/Doctrine/Repositories/BasketElementRepository.php +++ b/lib/Doctrine/Repositories/BasketElementRepository.php @@ -4,6 +4,7 @@ namespace Repositories; use Doctrine\ORM\EntityRepository; use Entities; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * BasketElementRepository @@ -38,7 +39,7 @@ class BasketElementRepository extends EntityRepository /* @var $element \Entities\BasketElement */ if (null === $element) { - throw new \Exception_NotFound(_('Element is not found')); + throw new NotFoundHttpException(_('Element is not found')); } return $element; diff --git a/lib/Doctrine/Repositories/BasketRepository.php b/lib/Doctrine/Repositories/BasketRepository.php index 31a63211c6..be06758862 100644 --- a/lib/Doctrine/Repositories/BasketRepository.php +++ b/lib/Doctrine/Repositories/BasketRepository.php @@ -14,6 +14,8 @@ namespace Repositories; use Alchemy\Phrasea\Application; use Doctrine\ORM\EntityRepository; use Entities; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -120,8 +122,8 @@ class BasketRepository extends EntityRepository /** * Find a basket specified by his basket_id and his owner * - * @throws \Exception_NotFound - * @throws \Exception_Forbidden + * @throws NotFoundHttpException + * @throws AccessDeniedHttpException * @param type $basket_id * @param \User_Adapter $user * @return \Entities\Basket @@ -140,7 +142,7 @@ class BasketRepository extends EntityRepository /* @var $basket \Entities\Basket */ if (null === $basket) { - throw new \Exception_NotFound(_('Basket is not found')); + throw new NotFoundHttpException(_('Basket is not found')); } if ($basket->getOwner($app)->get_id() != $user->get_id()) { @@ -155,7 +157,7 @@ class BasketRepository extends EntityRepository } } if ( ! $participant) { - throw new \Exception_Forbidden(_('You have not access to this basket')); + throw new AccessDeniedHttpException(_('You have not access to this basket')); } } diff --git a/lib/Doctrine/Repositories/StoryWZRepository.php b/lib/Doctrine/Repositories/StoryWZRepository.php index 57462061f9..2d27656c02 100644 --- a/lib/Doctrine/Repositories/StoryWZRepository.php +++ b/lib/Doctrine/Repositories/StoryWZRepository.php @@ -4,6 +4,8 @@ namespace Repositories; use Alchemy\Phrasea\Application; use Doctrine\ORM\EntityRepository; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * StoryWZRepository @@ -30,7 +32,7 @@ class StoryWZRepository extends EntityRepository foreach ($stories as $key => $story) { try { $story->getRecord($app)->get_title(); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $this->getEntityManager()->remove($story); unset($stories[$key]); } @@ -67,16 +69,16 @@ class StoryWZRepository extends EntityRepository if ($story) { try { $story->getRecord($app)->get_title(); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $this->getEntityManager()->remove($story); - throw new \Exception_NotFound('Story not found'); + throw new NotFoundHttpException('Story not found'); } if ($story->getUser($app)->get_id() !== $user->get_id()) { - throw new \Exception_Forbidden('You have not access to ths story'); + throw new AccessDeniedHttpException('You have not access to ths story'); } } else { - throw new \Exception_NotFound('Story not found'); + throw new NotFoundHttpException('Story not found'); } return $story; @@ -95,7 +97,7 @@ class StoryWZRepository extends EntityRepository if ($story) { try { $record = $story->getRecord($app); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $this->getEntityManager()->remove($story); $this->getEntityManager()->flush(); $story = null; @@ -121,7 +123,7 @@ class StoryWZRepository extends EntityRepository foreach ($stories as $key => $story) { try { $record = $story->getRecord(); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $this->getEntityManager()->remove($story); $this->getEntityManager()->flush(); unset($stories[$key]); @@ -145,7 +147,7 @@ class StoryWZRepository extends EntityRepository foreach ($stories as $key => $story) { try { $record = $story->getRecord(); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $this->getEntityManager()->remove($story); $this->getEntityManager()->flush(); unset($stories[$key]); diff --git a/lib/Doctrine/Repositories/UsrListEntryRepository.php b/lib/Doctrine/Repositories/UsrListEntryRepository.php index 668e71e1e9..9b00ba70b5 100644 --- a/lib/Doctrine/Repositories/UsrListEntryRepository.php +++ b/lib/Doctrine/Repositories/UsrListEntryRepository.php @@ -3,6 +3,8 @@ namespace Repositories; use Doctrine\ORM\EntityRepository; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * UsrListEntryRepository @@ -40,12 +42,12 @@ class UsrListEntryRepository extends EntityRepository $entry = $this->find($entry_id); if ( ! $entry) { - throw new \Exception_NotFound('Entry not found'); + throw new NotFoundHttpException('Entry not found'); } /* @var $entry \Entities\UsrListEntry */ if ($entry->getList()->getId() != $list->getId()) { - throw new \Exception_Forbidden('Entry mismatch list'); + throw new AccessDeniedHttpException('Entry mismatch list'); } return $entry; @@ -68,7 +70,7 @@ class UsrListEntryRepository extends EntityRepository $entry = $query->getResult(); if ( ! $entry) { - throw new \Exception_NotFound('Entry not found'); + throw new NotFoundHttpException('Entry not found'); } return $query->getSingleResult(); diff --git a/lib/Doctrine/Repositories/UsrListOwnerRepository.php b/lib/Doctrine/Repositories/UsrListOwnerRepository.php index d51346bbf7..940fdd3d93 100644 --- a/lib/Doctrine/Repositories/UsrListOwnerRepository.php +++ b/lib/Doctrine/Repositories/UsrListOwnerRepository.php @@ -3,6 +3,8 @@ namespace Repositories; use Doctrine\ORM\EntityRepository; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * UsrListOwnerRepository @@ -26,11 +28,11 @@ class UsrListOwnerRepository extends EntityRepository /* @var $owner \Entities\UsrListOwner */ if (null === $owner) { - throw new \Exception_NotFound(_('Owner is not found')); + throw new NotFoundHttpException(_('Owner is not found')); } if ( ! $owner->getList()->getid() != $list->getId()) { - throw new \Exception_Forbidden(_('Owner and list mismatch')); + throw new AccessDeniedHttpException(_('Owner and list mismatch')); } return $owner; @@ -61,7 +63,7 @@ class UsrListOwnerRepository extends EntityRepository /* @var $owner \Entities\UsrListOwner */ if (null === $owner) { - throw new \Exception_NotFound(_('Owner is not found')); + throw new NotFoundHttpException(_('Owner is not found')); } return $owner; diff --git a/lib/Doctrine/Repositories/UsrListRepository.php b/lib/Doctrine/Repositories/UsrListRepository.php index ce59e35993..70e67a3bbf 100644 --- a/lib/Doctrine/Repositories/UsrListRepository.php +++ b/lib/Doctrine/Repositories/UsrListRepository.php @@ -4,6 +4,8 @@ namespace Repositories; use Alchemy\Phrasea\Application; use Doctrine\ORM\EntityRepository; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * UsrListRepository @@ -49,11 +51,11 @@ class UsrListRepository extends EntityRepository /* @var $basket \Entities\UsrList */ if (null === $list) { - throw new \Exception_NotFound(_('List is not found')); + throw new NotFoundHttpException(_('List is not found')); } if ( ! $list->hasAccess($user, $app)) { - throw new \Exception_Forbidden(_('You have not access to this list')); + throw new AccessDeniedHttpException(_('You have not access to this list')); } return $list; diff --git a/lib/classes/API/OAuth2/Account.php b/lib/classes/API/OAuth2/Account.php index 66fe695f8a..c6603eb57d 100644 --- a/lib/classes/API/OAuth2/Account.php +++ b/lib/classes/API/OAuth2/Account.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -179,7 +180,7 @@ class API_OAuth2_Account if (! $this->token) { try { $this->token = new API_OAuth2_Token($this->app['phraseanet.appbox'], $this); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $this->token = API_OAuth2_Token::create($this->app['phraseanet.appbox'], $this); } } @@ -263,7 +264,7 @@ class API_OAuth2_Account $stmt->closeCursor(); if (! $row) { - throw new Exception_NotFound(); + throw new NotFoundHttpException('Account nof found.'); } return new self($app, $row['api_account_id']); diff --git a/lib/classes/API/OAuth2/Application.php b/lib/classes/API/OAuth2/Application.php index f1dab4c24c..a213dfa7ef 100644 --- a/lib/classes/API/OAuth2/Application.php +++ b/lib/classes/API/OAuth2/Application.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -149,7 +150,7 @@ class API_OAuth2_Application $stmt->execute(array(':application_id' => $this->id)); if (0 === $stmt->rowCount()) { - throw new \Exception_NotFound(sprintf('Application with id %d not found', $this->id)); + throw new NotFoundHttpException(sprintf('Application with id %d not found', $this->id)); } $row = $stmt->fetch(PDO::FETCH_ASSOC); @@ -546,7 +547,7 @@ class API_OAuth2_Application $stmt->closeCursor(); if ( ! $row) - throw new Exception_NotFound(); + throw new NotFoundHttpException('Application not found.'); return new API_OAuth2_Account($this->app, $row['api_account_id']); } @@ -659,7 +660,7 @@ class API_OAuth2_Application $stmt->closeCursor(); if ( ! $row) - throw new Exception_NotFound(); + throw new NotFoundHttpException('Client not found.'); return new self($app, $row['application_id']); } diff --git a/lib/classes/API/OAuth2/AuthCode.php b/lib/classes/API/OAuth2/AuthCode.php index 1f2ece6450..6c380026ad 100644 --- a/lib/classes/API/OAuth2/AuthCode.php +++ b/lib/classes/API/OAuth2/AuthCode.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -44,7 +45,7 @@ class API_OAuth2_AuthCode $stmt->closeCursor(); if ( ! $row) - throw new Exception_NotFound(); + throw new NotFoundHttpException('Code not found'); $this->account_id = (int) $row['api_account_id']; $this->redirect_uri = $row['redirect_uri']; diff --git a/lib/classes/API/OAuth2/Token.php b/lib/classes/API/OAuth2/Token.php index 86454b6c24..d2f6072b8d 100644 --- a/lib/classes/API/OAuth2/Token.php +++ b/lib/classes/API/OAuth2/Token.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -78,7 +79,7 @@ class API_OAuth2_Token $row = $stmt->fetch(PDO::FETCH_ASSOC); if ( ! $row) - throw new Exception_NotFound(); + throw new NotFoundHttpException('Account not found'); $stmt->closeCursor(); @@ -286,7 +287,7 @@ class API_OAuth2_Token $stmt->closeCursor(); if ( ! $row) - throw new Exception_NotFound(); + throw new NotFoundHttpException('Account not found'); $account = new API_OAuth2_Account($app, $row['api_account_id']); diff --git a/lib/classes/API/V1/adapter.php b/lib/classes/API/V1/adapter.php index 2e55214895..5ffc4b8a3b 100644 --- a/lib/classes/API/V1/adapter.php +++ b/lib/classes/API/V1/adapter.php @@ -15,6 +15,7 @@ use Alchemy\Phrasea\Border\File; use Alchemy\Phrasea\Border\Attribute\Status; use Alchemy\Phrasea\Border\Manager as BorderManager; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -1190,7 +1191,7 @@ 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) { + } catch (NotFoundHttpException $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, _('An error occured')); @@ -1214,7 +1215,7 @@ class API_V1_adapter extends API_V1_Abstract try { $story = $databox->get_record($story_id); $result->set_datas(array('story' => $this->list_story($story))); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('Story Not Found')); } catch (Exception $e) { $result->set_error_message(API_V1_result::ERROR_BAD_REQUEST, _('An error occured')); diff --git a/lib/classes/Bridge/Exception/AccountNotFound.php b/lib/classes/Bridge/Exception/AccountNotFound.php index 259a86da1f..68d0d71c11 100644 --- a/lib/classes/Bridge/Exception/AccountNotFound.php +++ b/lib/classes/Bridge/Exception/AccountNotFound.php @@ -9,13 +9,15 @@ * file that was distributed with this source code. */ +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + /** * * @package Bridge * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class Bridge_Exception_AccountNotFound extends Exception_NotFound +class Bridge_Exception_AccountNotFound extends NotFoundHttpException { } diff --git a/lib/classes/Bridge/Exception/ActionForbidden.php b/lib/classes/Bridge/Exception/ActionForbidden.php index 55b65337c5..b531078357 100644 --- a/lib/classes/Bridge/Exception/ActionForbidden.php +++ b/lib/classes/Bridge/Exception/ActionForbidden.php @@ -9,13 +9,15 @@ * file that was distributed with this source code. */ +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; + /** * * @package Bridge * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class Bridge_Exception_ActionForbidden extends Exception_Forbidden +class Bridge_Exception_ActionForbidden extends AccessDeniedHttpException { } diff --git a/lib/classes/Bridge/Exception/ApiConnectorNotFound.php b/lib/classes/Bridge/Exception/ApiConnectorNotFound.php index 44a6d1efc7..bb9cecb016 100644 --- a/lib/classes/Bridge/Exception/ApiConnectorNotFound.php +++ b/lib/classes/Bridge/Exception/ApiConnectorNotFound.php @@ -9,13 +9,15 @@ * file that was distributed with this source code. */ +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + /** * * @package Bridge * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class Bridge_Exception_ApiConnectorNotFound extends Exception_NotFound +class Bridge_Exception_ApiConnectorNotFound extends NotFoundHttpException { } diff --git a/lib/classes/Bridge/Exception/ApiNotFound.php b/lib/classes/Bridge/Exception/ApiNotFound.php index dbff777c81..4a2d0be01e 100644 --- a/lib/classes/Bridge/Exception/ApiNotFound.php +++ b/lib/classes/Bridge/Exception/ApiNotFound.php @@ -9,13 +9,15 @@ * file that was distributed with this source code. */ +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + /** * * @package Bridge * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class Bridge_Exception_ApiNotFound extends Exception_NotFound +class Bridge_Exception_ApiNotFound extends NotFoundHttpException { } diff --git a/lib/classes/Bridge/Exception/ElementNotFound.php b/lib/classes/Bridge/Exception/ElementNotFound.php index ad543dc2d5..1359e2b2b3 100644 --- a/lib/classes/Bridge/Exception/ElementNotFound.php +++ b/lib/classes/Bridge/Exception/ElementNotFound.php @@ -9,13 +9,15 @@ * file that was distributed with this source code. */ +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + /** * * @package Bridge * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class Bridge_Exception_ElementNotFound extends Exception_NotFound +class Bridge_Exception_ElementNotFound extends NotFoundHttpException { } diff --git a/lib/classes/Bridge/Exception/TokenNotFound.php b/lib/classes/Bridge/Exception/TokenNotFound.php index ac932dd7fd..db4cd3fc42 100644 --- a/lib/classes/Bridge/Exception/TokenNotFound.php +++ b/lib/classes/Bridge/Exception/TokenNotFound.php @@ -9,13 +9,15 @@ * file that was distributed with this source code. */ +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + /** * * @package Bridge * @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @link www.phraseanet.com */ -class Bridge_Exception_TokenNotFound extends Exception_NotFound +class Bridge_Exception_TokenNotFound extends NotFoundHttpException { } diff --git a/lib/classes/Exception/BadRequest.php b/lib/classes/Exception/BadRequest.php deleted file mode 100644 index 123be391d1..0000000000 --- a/lib/classes/Exception/BadRequest.php +++ /dev/null @@ -1,20 +0,0 @@ -usr_id = $usr_id; - parent::__construct($message, $code, $previous); - } - - public function get_usr_id() - { - return $this->usr_id; - } -} diff --git a/lib/classes/Exception/Session/NotAuthenticated.php b/lib/classes/Exception/Session/NotAuthenticated.php deleted file mode 100644 index 05e38a5cf3..0000000000 --- a/lib/classes/Exception/Session/NotAuthenticated.php +++ /dev/null @@ -1,21 +0,0 @@ -closeCursor(); if (!$row) - throw new Exception_FeedNotFound (); + throw new NotFoundHttpException('Feed not found'); $this->title = $row['title']; $this->subtitle = $row['subtitle']; @@ -464,7 +465,7 @@ class Feed_Adapter extends Feed_Abstract implements Feed_Interface, cache_cachea return $feed; } - throw new Exception_FeedNotFound(); + throw new NotFoundHttpException('Feed not found'); } /** diff --git a/lib/classes/Feed/Entry/Adapter.php b/lib/classes/Feed/Entry/Adapter.php index 86331857d0..ddf4c78856 100644 --- a/lib/classes/Feed/Entry/Adapter.php +++ b/lib/classes/Feed/Entry/Adapter.php @@ -10,6 +10,8 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; /** * @@ -451,7 +453,7 @@ class Feed_Entry_Adapter implements Feed_Entry_Interface, cache_cacheableInterfa foreach ($rs as $item_id) { try { $items[] = new Feed_Entry_Item($this->app['phraseanet.appbox'], $this, $item_id); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } } @@ -514,7 +516,7 @@ class Feed_Entry_Adapter implements Feed_Entry_Interface, cache_cacheableInterfa if ( ! $feed->is_public() && $feed->get_collection() instanceof Collection) { if ( ! $publisher->get_user()->ACL()->has_access_to_base($feed->get_collection()->get_base_id())) { - throw new Exception_Unauthorized("User has no rights to publish in current feed"); + throw new AccessDeniedHttpException("User has no rights to publish in current feed"); } } diff --git a/lib/classes/Feed/Token.php b/lib/classes/Feed/Token.php index 4e76e26284..cfc44bfa94 100644 --- a/lib/classes/Feed/Token.php +++ b/lib/classes/Feed/Token.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -74,7 +75,7 @@ class Feed_Token $stmt->closeCursor(); if ( ! $row) - throw new Exception_FeedNotFound($token); + throw new NotFoundHttpException('Feed not found.'); $this->feed_id = (int) $row['feed_id']; $this->usr_id = (int) $row['usr_id']; diff --git a/lib/classes/Feed/TokenAggregate.php b/lib/classes/Feed/TokenAggregate.php index d3d5c951a8..b35f0a5944 100644 --- a/lib/classes/Feed/TokenAggregate.php +++ b/lib/classes/Feed/TokenAggregate.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -42,7 +43,7 @@ class Feed_TokenAggregate extends Feed_Token $stmt->closeCursor(); if ( ! $row) - throw new Exception_FeedNotFound($token); + throw new NotFoundHttpException('Feed not found.'); $this->usr_id = $row['usr_id']; $this->app = $app; diff --git a/lib/classes/appbox.php b/lib/classes/appbox.php index 917adbd123..6a01bd753e 100644 --- a/lib/classes/appbox.php +++ b/lib/classes/appbox.php @@ -15,6 +15,7 @@ use MediaAlchemyst\Specification\Image as ImageSpecification; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpFoundation\File\File as SymfoFile; use Symfony\Component\Finder\Finder; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -436,7 +437,7 @@ class appbox extends base foreach ($this->retrieve_sbas_ids() as $sbas_id) { try { $ret[$sbas_id] = new \databox($this->app, $sbas_id); - } catch (\Exception_DataboxNotFound $e) { + } catch (NotFoundHttpException $e) { } } @@ -476,7 +477,7 @@ class appbox extends base $databoxes = $this->get_databoxes(); if (!array_key_exists($sbas_id, $databoxes)) { - throw new Exception_DataboxNotFound('Databox `' . $sbas_id . '` not found'); + throw new NotFoundHttpException('Databox `' . $sbas_id . '` not found'); } return $databoxes[$sbas_id]; diff --git a/lib/classes/databox.php b/lib/classes/databox.php index 7fc71ef3a0..b33ff00448 100644 --- a/lib/classes/databox.php +++ b/lib/classes/databox.php @@ -12,6 +12,7 @@ use Alchemy\Phrasea\Application; use Symfony\Component\Filesystem\Filesystem; use Alchemy\Phrasea\Exception\InvalidArgumentException; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class databox extends base { @@ -115,7 +116,7 @@ class databox extends base $connection_params = phrasea::sbas_params($this->app); if ( ! isset($connection_params[$sbas_id])) { - throw new Exception_DataboxNotFound(sprintf('databox %d not found', $sbas_id)); + throw new NotFoundHttpException(sprintf('databox %d not found', $sbas_id)); } $this->host = $connection_params[$sbas_id]['host']; @@ -147,7 +148,7 @@ class databox extends base } if (!$row) { - throw new Exception_DataboxNotFound(sprintf('databox %d not found', $sbas_id)); + throw new NotFoundHttpException(sprintf('databox %d not found', $sbas_id)); } $this->ord = $row['ord']; diff --git a/lib/classes/module/console/systemClearCache.php b/lib/classes/module/console/systemClearCache.php index 24e9f8357f..36b857e481 100644 --- a/lib/classes/module/console/systemClearCache.php +++ b/lib/classes/module/console/systemClearCache.php @@ -40,8 +40,8 @@ class module_console_systemClearCache extends Command ->exclude('.git') ->exclude('.svn') ->in(array( - __DIR__ . '/../../../../tmp/cache_minify/', - __DIR__ . '/../../../../tmp/cache_twig/' + $this->container['root.path'] . '/tmp/cache_minify/', + $this->container['root.path'] . '/tmp/cache_twig/' )); $filesystem = new Filesystem(); diff --git a/lib/classes/module/console/taskState.php b/lib/classes/module/console/taskState.php index 17b808da38..c0889e91aa 100644 --- a/lib/classes/module/console/taskState.php +++ b/lib/classes/module/console/taskState.php @@ -20,6 +20,7 @@ use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class module_console_taskState extends Command { @@ -80,7 +81,7 @@ class module_console_taskState extends Command $task = $task_manager->getTask($task_id); $taskPID = $task->getPID(); $taskState = $task->getState(); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $output->writeln($input->getOption('short') ? 'unknown_id' : $e->getMessage()); return self::EXITCODE_TASK_UNKNOWN; diff --git a/lib/classes/patch/320f.php b/lib/classes/patch/320f.php index 8982f295e6..933c4519d0 100644 --- a/lib/classes/patch/320f.php +++ b/lib/classes/patch/320f.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -109,7 +110,7 @@ class patch_320f implements patchInterface try { $record = new record_adapter($app, phrasea::sbasFromBas($app, $row['base_id']), $row['record_id']); $item = Feed_Entry_Item::create($appbox, $entry, $record); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } } diff --git a/lib/classes/patch/370a3.php b/lib/classes/patch/370a3.php index 1c3ffca39f..c8f5cdac75 100644 --- a/lib/classes/patch/370a3.php +++ b/lib/classes/patch/370a3.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -57,7 +58,7 @@ class patch_370a3 implements patchInterface { try { \API_OAuth2_Application::load_from_client_id($app, \API_OAuth2_Application_Navigator::CLIENT_ID); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { $client = \API_OAuth2_Application::create($app, null, \API_OAuth2_Application_Navigator::CLIENT_NAME); $client->set_activated(false); diff --git a/lib/classes/random.php b/lib/classes/random.php index 23aa2ba7d9..38355a689e 100644 --- a/lib/classes/random.php +++ b/lib/classes/random.php @@ -10,6 +10,7 @@ */ use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class random { @@ -62,7 +63,7 @@ class random switch ($row['type']) { case 'download': case 'email': - $file = __DIR__ . '/../../tmp/download/' . $row['value'] . '.zip'; + $file = $this->app['root.path'] . '/tmp/download/' . $row['value'] . '.zip'; if (is_file($file)) unlink($file); break; @@ -225,7 +226,7 @@ class random $stmt->closeCursor(); if ( ! $row) - throw new Exception_NotFound('Token not found'); + throw new NotFoundHttpException('Token not found'); return $row; } @@ -238,7 +239,7 @@ class random * * @return string The token * - * @throws \Exception_NotFound + * @throws NotFoundHttpException */ public function getValidationToken($userId, $basketId) { @@ -260,7 +261,7 @@ class random $stmt->closeCursor(); if (! $row) { - throw new \Exception_NotFound('Token not found'); + throw new NotFoundHttpException('Token not found'); } return $row['value']; diff --git a/lib/classes/set/order.php b/lib/classes/set/order.php index 5f60cc53af..9f29106dda 100644 --- a/lib/classes/set/order.php +++ b/lib/classes/set/order.php @@ -11,6 +11,7 @@ use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Controller\RecordsRequest; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -231,7 +232,7 @@ class set_order extends set_abstract $stmt->closeCursor(); if ( ! $row) - throw new Exception_NotFound('unknown order ' . $id); + throw new NotFoundHttpException('unknown order ' . $id); $current_user = User_Adapter::getInstance($row['usr_id'], $app); diff --git a/lib/classes/task/abstract.php b/lib/classes/task/abstract.php index 52d7f2a1da..f5551f7466 100644 --- a/lib/classes/task/abstract.php +++ b/lib/classes/task/abstract.php @@ -455,7 +455,7 @@ abstract class task_abstract $stmt->execute(array(':task_id' => $this->getID())); $stmt->closeCursor(); - $lock_file = __DIR__ . '/../../../tmp/locks/task_' . $this->getID() . '.lock'; + $lock_file = $this->dependencyContainer['root.path'] . '/tmp/locks/task_' . $this->getID() . '.lock'; @unlink($lock_file); } } diff --git a/lib/classes/task/manager.php b/lib/classes/task/manager.php index d6c606a129..493d7a6d8c 100644 --- a/lib/classes/task/manager.php +++ b/lib/classes/task/manager.php @@ -12,6 +12,7 @@ use Monolog\Logger; use Alchemy\Phrasea\Application; use Symfony\Component\Process\Process; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** * @@ -117,7 +118,7 @@ class task_manager $tasks = $this->getTasks(false); if (!isset($tasks[$task_id])) { - throw new Exception_NotFound('Unknown task_id ' . $task_id); + throw new NotFoundHttpException('Unknown task_id ' . $task_id); } return $tasks[$task_id]; diff --git a/lib/conf.d/configuration.yml b/lib/conf.d/configuration.yml index 30a4dcd07e..1fefa6341a 100644 --- a/lib/conf.d/configuration.yml +++ b/lib/conf.d/configuration.yml @@ -28,6 +28,8 @@ main: task-manager: options: null trusted-proxies: [] +debugger: + allowed-ips: [] binaries: [] border-manager: enabled: true diff --git a/templates/web/prod/actions/Bridge/wrapper.html.twig b/templates/web/prod/actions/Bridge/wrapper.html.twig index 5f0403c5ec..e30b4f6d69 100644 --- a/templates/web/prod/actions/Bridge/wrapper.html.twig +++ b/templates/web/prod/actions/Bridge/wrapper.html.twig @@ -4,25 +4,29 @@ - {% for type, display_name in account.get_api().get_connector().get_element_types() %} - - {{ display_name }} - - {% if not loop.last %} - {% endif %} - {% endfor %} + {% if account is not none %} + {% for type, display_name in account.get_api().get_connector().get_element_types() %} + + {{ display_name }} + + {% if not loop.last %} - {% endif %} + {% endfor %} + {% endif %} | - {% for type, display_name in account.get_api().get_connector().get_container_types() %} - - {{ display_name }} - - {% if not loop.last %} - {% endif %} - {% endfor %} + {% if account is not none %} + {% for type, display_name in account.get_api().get_connector().get_container_types() %} + + {{ display_name }} + + {% if not loop.last %} - {% endif %} + {% endfor %} {% trans 'Fichiers envoyes' %} + {% endif %} - {% if account %} + {% if account is not none %} {% trans 'phraseanet:: deconnection' %} @@ -56,17 +60,21 @@ - {% if account.get_api().get_connector().get_terms_url() %} - - {% trans 'Terms of service' %} - + {% if account is not none %} + {% if account.get_api().get_connector().get_terms_url() %} + + {% trans 'Terms of service' %} + + {% endif %} {% endif %} - - {{ account.get_api().get_connector().get_infos() }} - - + {% if account is not none %} + + {{ account.get_api().get_connector().get_infos() }} + + + {% endif %} diff --git a/tests/Alchemy/Tests/Phrasea/Application/RootApplicationTest.php b/tests/Alchemy/Tests/Phrasea/Application/RootApplicationTest.php new file mode 100644 index 0000000000..3dbba0d8ec --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Application/RootApplicationTest.php @@ -0,0 +1,47 @@ +assertEquals($environment, $app->getEnvironment()); + } + + public function provideEnvironments() + { + return array( + array(Application::ENV_PROD), + array(Application::ENV_TEST), + array(Application::ENV_DEV), + ); + } + + public function testWebProfilerDisableInProdEnv() + { + $environment = Application::ENV_PROD; + $app = require __DIR__ . '/../../../../../lib/Alchemy/Phrasea/Application/Root.php'; + $this->assertFalse(isset($app['profiler'])); + } + + public function testWebProfilerDisableInTestEnv() + { + $environment = Application::ENV_TEST; + $app = require __DIR__ . '/../../../../../lib/Alchemy/Phrasea/Application/Root.php'; + $this->assertFalse(isset($app['profiler'])); + } + + public function testWebProfilerEnableInDevMode() + { + $environment = Application::ENV_DEV; + $app = require __DIR__ . '/../../../../../lib/Alchemy/Phrasea/Application/Root.php'; + $this->assertTrue(isset($app['profiler'])); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/ApplicationTest.php b/tests/Alchemy/Tests/Phrasea/ApplicationTest.php index b5ccf03e70..b7be6549c4 100644 --- a/tests/Alchemy/Tests/Phrasea/ApplicationTest.php +++ b/tests/Alchemy/Tests/Phrasea/ApplicationTest.php @@ -11,6 +11,9 @@ use Symfony\Component\HttpKernel\Client; use Symfony\Component\BrowserKit\CookieJar; use Symfony\Component\BrowserKit\Cookie as BrowserCookie; use Symfony\Component\Routing\Generator\UrlGenerator; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\KernelEvents; +use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent; class ApplicationTest extends \PhraseanetPHPUnitAbstract { @@ -40,6 +43,21 @@ class ApplicationTest extends \PhraseanetPHPUnitAbstract $app = new Application(); } + public function testExceptionHandlerIsNotYetInstancied() + { + $app = new Application(); + $app['exception_handler'] = new TestExceptionHandlerSubscriber(); + + $app->get('/', function () { + throw new \Exception(); + }); + + $client = new Client($app); + $client->request('GET', '/'); + + $this->assertEquals('GOT IT !', $client->getResponse()->getContent()); + } + /** * @covers Alchemy\Phrasea\Application */ @@ -147,21 +165,6 @@ class ApplicationTest extends \PhraseanetPHPUnitAbstract $this->assertEquals('123456', $sessionId); } - public function testWebProfilerDisableByDefault() - { - $app = new Application('prod'); - $this->assertFalse(isset($app['profiler'])); - - $app = new Application('test'); - $this->assertFalse(isset($app['profiler'])); - } - - public function testWebProfilerEnableInDevMode() - { - $app = new Application('dev'); - $this->assertTrue(isset($app['profiler'])); - } - public function testGeneratePath() { $generator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGenerator') @@ -348,3 +351,19 @@ class ApplicationTest extends \PhraseanetPHPUnitAbstract return new Client($app, array(), null, $cookieJar); } } + +class TestExceptionHandlerSubscriber implements EventSubscriberInterface +{ + public function onSilexError(GetResponseForExceptionEvent $event) + { + $event->setResponse(new Response('GOT IT !')); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() + { + return array(KernelEvents::EXCEPTION => array('onSilexError', 0)); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php index 3fc001ec5f..68149686f0 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/AdminCollectionTest.php @@ -163,7 +163,7 @@ class AdminCollectionTest extends \PhraseanetWebTestCaseAuthenticatedAbstract { $this->setAdmin(true); - $prefs = ' '; + $prefs = ' '; $this->XMLHTTPRequest('POST', '/admin/collection/' . self::$DI['collection']->get_base_id() . '/suggested-values/', array( 'str' => $prefs diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php index 24e6dc876c..04be2dc01c 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxTest.php @@ -4,6 +4,7 @@ namespace Alchemy\Tests\Phrasea\Controller\Admin; use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Border\File; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class DataboxTest extends \PhraseanetWebTestCaseAuthenticatedAbstract { @@ -491,7 +492,7 @@ class DataboxTest extends \PhraseanetWebTestCaseAuthenticatedAbstract try { self::$DI['app']['phraseanet.appbox']->get_databox((int) $json->sbas_id); $this->fail('Databox not deleted'); - } catch (\Exception_DataboxNotFound $e) { + } catch (NotFoundHttpException $e) { } } @@ -567,7 +568,7 @@ class DataboxTest extends \PhraseanetWebTestCaseAuthenticatedAbstract try { self::$DI['app']['phraseanet.appbox']->get_databox((int) $json->sbas_id); $this->fail('Databox not unmounted'); - } catch (\Exception_DataboxNotFound $e) { + } catch (NotFoundHttpException $e) { } diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxesTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxesTest.php index 32e41b8f1a..27134aa9ae 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxesTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Admin/DataboxesTest.php @@ -2,6 +2,8 @@ namespace Alchemy\Tests\Phrasea\Controller\Admin; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + class DataboxesTest extends \PhraseanetWebTestCaseAuthenticatedAbstract { protected $client; @@ -88,7 +90,7 @@ class DataboxesTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $databox = self::$DI['app']['phraseanet.appbox']->get_databox($databoxId); $databox->unmount_databox(); $databox->delete(); - } catch (\Exception_DataboxNotFound $e) { + } catch (NotFoundHttpException $e) { $this->fail('databox not mounted'); } diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Prod/DoDownloadTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Prod/DoDownloadTest.php index 15fd2211db..b2323ec89b 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Prod/DoDownloadTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Prod/DoDownloadTest.php @@ -65,7 +65,7 @@ class DoDownloadTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $response = self::$DI['client']->getResponse(); $this->assertEquals(500, $response->getStatusCode()); - $this->assertTrue(false !== stripos($response->getContent(), 'internal server error')); + $this->assertTrue(false !== stripos($response->getContent(), 'Whoops, looks like something went wrong')); } /** @@ -243,7 +243,7 @@ class DoDownloadTest extends \PhraseanetWebTestCaseAuthenticatedAbstract $response = self::$DI['client']->getResponse(); $this->assertEquals(500, $response->getStatusCode()); - $this->assertTrue(false !== stripos($response->getContent(), 'internal server error')); + $this->assertTrue(false !== stripos($response->getContent(), 'Whoops, looks like something went wrong')); } /** diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Root/AccountTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Root/AccountTest.php index 63a9326208..e4c800bd1f 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Root/AccountTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Root/AccountTest.php @@ -3,6 +3,7 @@ namespace Alchemy\Tests\Phrasea\Controller\Root; use Alchemy\Phrasea\Application; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract { @@ -90,7 +91,7 @@ class AccountTest extends \PhraseanetWebTestCaseAuthenticatedAbstract try { self::$DI['app']['tokens']->helloToken($token); $this->fail('Token has not been removed'); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } diff --git a/tests/Alchemy/Tests/Phrasea/Controller/Root/DevelopersTest.php b/tests/Alchemy/Tests/Phrasea/Controller/Root/DevelopersTest.php index d3fc9f01fd..1fad6aa72e 100644 --- a/tests/Alchemy/Tests/Phrasea/Controller/Root/DevelopersTest.php +++ b/tests/Alchemy/Tests/Phrasea/Controller/Root/DevelopersTest.php @@ -2,6 +2,8 @@ namespace Alchemy\Tests\Phrasea\Controller\Root; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + class DevelopersTest extends \PhraseanetWebTestCaseAuthenticatedAbstract { @@ -129,7 +131,7 @@ class DevelopersTest extends \PhraseanetWebTestCaseAuthenticatedAbstract try { new \API_OAuth2_Application(self::$DI['app'], $oauthApp->get_id()); $this->fail('Application not deleted'); - } catch (\Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } } 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 2256210b14..1fefa6341a 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml +++ b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration-setup.yml @@ -27,6 +27,9 @@ main: options: [] task-manager: options: null +trusted-proxies: [] +debugger: + allowed-ips: [] binaries: [] border-manager: enabled: true diff --git a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml index 2256210b14..1fefa6341a 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml +++ b/tests/Alchemy/Tests/Phrasea/Core/Configuration/Fixtures/configuration.yml @@ -27,6 +27,9 @@ main: options: [] task-manager: options: null +trusted-proxies: [] +debugger: + allowed-ips: [] binaries: [] border-manager: enabled: true diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php new file mode 100644 index 0000000000..667ee18000 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiExceptionHandlerSubscriberTest.php @@ -0,0 +1,48 @@ +register(new \API_V1_Timer()); + $app['dispatcher']->addSubscriber(new ApiExceptionHandlerSubscriber($app)); + $app->get('/', function () use ($exception) { + throw $exception; + }); + + $client = new Client($app); + $client->request('GET', '/'); + + $this->assertEquals($code, $client->getResponse()->getStatusCode()); + $this->assertEquals('application/json', $client->getResponse()->headers->get('content-type')); + } + + public function provideExceptionsAndCode() + { + return array( + array(new \API_V1_exception_methodnotallowed(), 405), + array(new MethodNotAllowedHttpException(array('PUT', 'HEAD')), 405), + array(new \API_V1_exception_badrequest(), 400), + array(new \API_V1_exception_forbidden(), 403), + array(new \API_V1_exception_unauthorized(), 401), + array(new \API_V1_exception_internalservererror(), 500), + array(new NotFoundHttpException(), 404), + array(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 new file mode 100644 index 0000000000..87da546fa8 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/ApiOauth2ErrorsSubscriberTest.php @@ -0,0 +1,64 @@ +register(new \API_V1_Timer()); + $app['dispatcher']->addSubscriber(new ApiOauth2ErrorsSubscriber(PhraseaExceptionHandler::register())); + $app->get('/api/oauthv2', function () use ($exception) { + throw $exception; + }); + + $client = new Client($app); + $client->request('GET', '/api/oauthv2'); + + $this->assertEquals($code, $client->getResponse()->getStatusCode()); + $this->assertEquals($contentType, $client->getResponse()->headers->get('content-type')); + } + + /** + * @dataProvider provideExceptionsAndCode + */ + public function testErrorOnOtherRoutes($exception, $code, $contentType) + { + $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())); + $app->get('/', function () use ($exception) { + throw $exception; + }); + + $client = new Client($app); + $this->setExpectedException(get_class($exception)); + $client->request('GET', '/'); + } + + public function provideExceptionsAndCode() + { + return array( + array(new HttpException(512, null, null, array('content-type' => 'application/json')), 512, 'application/json'), + array(new HttpException(512, null, null), 512, 'text/html; charset=UTF-8'), + array(new \Exception(), 500, 'text/html; charset=UTF-8'), + ); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/BridgeExceptionSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/BridgeExceptionSubscriberTest.php new file mode 100644 index 0000000000..2f8ff5ef10 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/BridgeExceptionSubscriberTest.php @@ -0,0 +1,45 @@ +getMockBuilder('Bridge_Account') + ->disableOriginalConstructor() + ->getMock(); + unset($app['exception_handler']); + $app['dispatcher']->addSubscriber(new BridgeExceptionSubscriber($app)); + $app->get('/', function () { + throw new \Bridge_Exception('Bridge exception'); + }); + + $client = new Client($app); + $client->request('GET', '/'); + + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + } + + public function testErrorOnOtherExceptions() + { + $app = new Application('test'); + $app['bridge.account'] = $this->getMockBuilder('Bridge_Account') + ->disableOriginalConstructor() + ->getMock(); + unset($app['exception_handler']); + $app['dispatcher']->addSubscriber(new BridgeExceptionSubscriber($app)); + $app->get('/', function () { + throw new \InvalidArgumentException; + }); + + $client = new Client($app); + $this->setExpectedException('\InvalidArgumentException'); + $client->request('GET', '/'); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/DebuggerSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/DebuggerSubscriberTest.php new file mode 100644 index 0000000000..84e97d7f74 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/DebuggerSubscriberTest.php @@ -0,0 +1,59 @@ + $authorized); + $app['dispatcher']->addSubscriber(new DebuggerSubscriber($app)); + $app->get('/', function () { + return 'success'; + }); + $app->boot(); + + if ($exceptionThrown) { + $this->setExpectedException('Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException'); + } + + $app->handle(new Request(array(), array(), array(), array(), array(), array('REMOTE_ADDR' => $incomingIp))); + } + + public function provideIpsAndEnvironments() + { + return array( + array(false, Application::ENV_PROD, '127.0.0.1', array()), + array(false, Application::ENV_PROD, '192.168.0.1', array()), + array(false, Application::ENV_DEV, '127.0.0.1', array()), + array(true, Application::ENV_DEV, '192.168.0.1', array()), + array(false, Application::ENV_DEV, '192.168.0.1', array('192.168.0.1')), + array(false, Application::ENV_TEST, '127.0.0.1', array()), + array(false, Application::ENV_TEST, '192.168.0.1', array()), + ); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/FirewallSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/FirewallSubscriberTest.php new file mode 100644 index 0000000000..87bb9e4401 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/FirewallSubscriberTest.php @@ -0,0 +1,41 @@ +addSubscriber(new FirewallSubscriber()); + $app->get('/', function () { + throw new HttpException(500, null, null, array('X-Phraseanet-Redirect' => '/hello-world')); + }); + + $client = new Client($app); + $client->request('GET', '/'); + + $this->assertEquals(302, $client->getResponse()->getStatusCode()); + $this->assertEquals('/hello-world', $client->getResponse()->headers->get('Location')); + } + + public function testNoHeaderNoRedirection() + { + $app = new Application(); + unset($app['exception_handler']); + $app['dispatcher']->addSubscriber(new FirewallSubscriber()); + $app->get('/', function () { + throw new HttpException(500); + }); + + $client = new Client($app); + $this->setExpectedException('Symfony\Component\HttpKernel\Exception\HttpException'); + $client->request('GET', '/'); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-debugger.yml b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-debugger.yml new file mode 100644 index 0000000000..7a2bd5cbc6 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/Fixtures/configuration-debugger.yml @@ -0,0 +1,141 @@ +main: + servername: 'http://local.phrasea/' + maintenance: false + database: + host: sql-host + port: '3306' + user: sql-user + password: sql-password + dbname: ab_phraseanet + driver: pdo_mysql + charset: UTF8 + database-test: + driver: pdo_sqlite + path: /tmp/db.sqlite + charset: UTF8 + api-timers: true + cache: + type: MemcacheCache + options: + host: localhost + port: 11211 + opcodecache: + type: ArrayCache + options: { } + search-engine: + type: Alchemy\Phrasea\SearchEngine\Phrasea\PhraseaEngine + options: { } + task-manager: + options: '' +trusted-proxies: { } +debugger: + allowed-ips: { } +binaries: { } +border-manager: + enabled: true + checkers: + - + type: Checker\Sha256 + enabled: true + - + type: Checker\UUID + enabled: true + - + type: Checker\Colorspace + enabled: false + options: + colorspaces: + - cmyk + - grayscale + - rgb + - + type: Checker\Dimension + enabled: false + options: + width: 80 + height: 160 + - + type: Checker\Extension + enabled: false + options: + extensions: + - jpg + - jpeg + - bmp + - tif + - gif + - png + - pdf + - doc + - odt + - mpg + - mpeg + - mov + - avi + - xls + - flv + - mp3 + - mp2 + - + type: Checker\Filename + enabled: false + options: + sensitive: true + - + type: Checker\MediaType + enabled: false + options: + mediatypes: + - Audio + - Document + - Flash + - Image + - Video +authentication: + auto-create: + enabled: false + templates: { } + captcha: + enabled: true + trials-before-failure: 9 + providers: + facebook: + enabled: false + options: + app-id: '' + secret: '' + twitter: + enabled: false + options: + consumer-key: '' + consumer-secret: '' + google-plus: + enabled: false + options: + client-id: '' + client-secret: '' + github: + enabled: false + options: + client-id: '' + client-secret: '' + viadeo: + enabled: false + options: + client-id: '' + client-secret: '' + linkedin: + enabled: false + options: + client-id: '' + client-secret: '' +registration-fields: + - + name: company + required: true + - + name: firstname + required: true + - + name: geonameid + required: true diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/JsonRequestSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/JsonRequestSubscriberTest.php new file mode 100644 index 0000000000..1bf8332ecb --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/JsonRequestSubscriberTest.php @@ -0,0 +1,53 @@ +addSubscriber(new JsonRequestSubscriber()); + $app->get($route, function () { + throw new \Exception('I disagree'); + }); + + $client = new Client($app); + $headers = $isJson ? array('HTTP_ACCEPT' => 'application/json') : array(); + if ($exceptionExpected) { + $this->setExpectedException('Exception'); + } + $client->request('GET', $route, array(), array(), $headers); + if (!$exceptionExpected) { + $this->assertEquals(200, $client->getResponse()->getStatusCode()); + $this->assertEquals('application/json', $client->getResponse()->headers->get('content-type')); + $data = json_decode($client->getResponse()->getContent(), true); + $this->assertArrayHasKey('success', $data); + $this->assertArrayHasKey('message', $data); + $this->assertFalse($data['success']); + } + } + + public function provideRouteParameters() + { + return array( + array('/admin/status', true, true), + array('/admin/collection/24', false, true), + array('/admin/collection/24', true, false), + array('/admin/databox/42', false, true), + array('/admin/databox/42', true, false), + array('/report', false, true), + array('/report', true, false), + array('/prod', false, true), + array('/prod', true, false), + ); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/LogoutSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/LogoutSubscriberTest.php new file mode 100644 index 0000000000..c400726f36 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/LogoutSubscriberTest.php @@ -0,0 +1,26 @@ +addSubscriber(new LogoutSubscriber()); + + $app['phraseanet.SE'] = $this->getMock('Alchemy\Phrasea\SearchEngine\SearchEngineInterface'); + + // the method is actually called two times because the event is registered two times + // in this test and in the applicaton constructor + $app['phraseanet.SE']->expects($this->exactly(2)) + ->method('clearCache'); + + $app['dispatcher']->dispatch(PhraseaEvents::LOGOUT, new LogoutEvent($app)); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/PhraseaExceptionHandlerSubscriberTest.php b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/PhraseaExceptionHandlerSubscriberTest.php new file mode 100644 index 0000000000..dd8373a738 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Core/Event/Subscriber/PhraseaExceptionHandlerSubscriberTest.php @@ -0,0 +1,54 @@ +get('/', function () { + throw new \Exception(); + }); + + $client = new Client($app); + $client->request('GET', '/'); + + $this->assertEquals(500, $client->getResponse()->getStatusCode()); + } + + public function testANotFoundResponseIsReturned() + { + $app = new Application(); + $app['exception_handler'] = new PhraseaExceptionHandlerSubscriber(PhraseaExceptionHandler::register()); + $app->get('/', function () { + throw new NotFoundHttpException(); + }); + + $client = new Client($app); + $client->request('GET', '/'); + + $this->assertEquals(404, $client->getResponse()->getStatusCode()); + } + + public function testItCanBeDisabled() + { + $app = new Application(); + $app['exception_handler'] = new PhraseaExceptionHandlerSubscriber(PhraseaExceptionHandler::register()); + $app->get('/', function () { + throw new \Exception(); + }); + $app['exception_handler']->disable(); + + $client = new Client($app); + $this->setExpectedException('\Exception'); + $client->request('GET', '/'); + } +} diff --git a/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenTest.php b/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenTest.php index 049df43bea..5d5c9ac1a3 100644 --- a/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenTest.php +++ b/tests/Alchemy/Tests/Phrasea/Form/Constraint/PasswordTokenTest.php @@ -3,6 +3,7 @@ namespace Alchemy\Tests\Phrasea\Form\Constraint; use Alchemy\Phrasea\Form\Constraint\PasswordToken; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class PasswordTokenTest extends \PhraseanetPHPUnitAbstract { @@ -20,7 +21,7 @@ class PasswordTokenTest extends \PhraseanetPHPUnitAbstract ->expects($this->once()) ->method('helloToken') ->with($token) - ->will($this->throwException(new \Exception_NotFound('Token not found'))); + ->will($this->throwException(new NotFoundHttpException('Token not found'))); $constraint = new PasswordToken(self::$DI['app'], $random); $this->assertFalse($constraint->isValid($token)); diff --git a/tests/Alchemy/Tests/Phrasea/Notification/Mail/AbstractMailTest.php b/tests/Alchemy/Tests/Phrasea/Notification/Mail/AbstractMailTest.php index f73ce44d25..9789a6cc97 100644 --- a/tests/Alchemy/Tests/Phrasea/Notification/Mail/AbstractMailTest.php +++ b/tests/Alchemy/Tests/Phrasea/Notification/Mail/AbstractMailTest.php @@ -3,10 +3,7 @@ namespace Alchemy\Tests\Phrasea\Notification\Mail; use Alchemy\Phrasea\Notification\Mail\AbstractMail; -use Symfony\Component\Routing\RouteCollection; -use Symfony\Component\Routing\Route; use Symfony\Component\Routing\Generator\UrlGenerator; -use Symfony\Component\Routing\RequestContext; /** * @covers Alchemy\Phrasea\Notification\Mail\AbstractMail diff --git a/tests/classes/PhraseanetPHPUnitAbstract.php b/tests/classes/PhraseanetPHPUnitAbstract.php index a6b342fd57..309da93884 100644 --- a/tests/classes/PhraseanetPHPUnitAbstract.php +++ b/tests/classes/PhraseanetPHPUnitAbstract.php @@ -182,7 +182,7 @@ abstract class PhraseanetPHPUnitAbstract extends WebTestCase protected function assertForbiddenResponse(Response $response) { $this->assertEquals(403, $response->getStatusCode()); - $this->assertTrue(false !== stripos($response->getContent(), 'forbidden')); + $this->assertTrue(false !== stripos($response->getContent(), 'Sorry, you do have access to the page you are looking for')); } protected function assertBadResponse(Response $response) @@ -194,7 +194,7 @@ abstract class PhraseanetPHPUnitAbstract extends WebTestCase protected function assertNotFoundResponse(Response $response) { $this->assertEquals(404, $response->getStatusCode()); - $this->assertTrue(false !== stripos($response->getContent(), 'not found')); + $this->assertTrue(false !== stripos($response->getContent(), 'Sorry, the page you are looking for could not be found')); } /** diff --git a/tests/classes/api/v1/api_v1_adapterTest.php b/tests/classes/api/v1/api_v1_adapterTest.php index 0d768693f4..2b84a0fb73 100644 --- a/tests/classes/api/v1/api_v1_adapterTest.php +++ b/tests/classes/api/v1/api_v1_adapterTest.php @@ -2,6 +2,7 @@ use Alchemy\Phrasea\Border\File as BorderFile; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract { @@ -593,7 +594,7 @@ class API_V1_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract try { $repo->findUserBasket(self::$DI['app'], $ssel_id, $user, true); $this->fail('An exception should have been raised'); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } } diff --git a/tests/classes/randomTest.php b/tests/classes/randomTest.php index 938dcdb4f3..0c18065955 100644 --- a/tests/classes/randomTest.php +++ b/tests/classes/randomTest.php @@ -1,5 +1,7 @@ random->helloToken($token); $this->fail(); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } } @@ -102,7 +104,7 @@ class randomTest extends PhraseanetPHPUnitAbstract try { $this->random->helloToken($token); $this->fail(); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } @@ -124,7 +126,7 @@ class randomTest extends PhraseanetPHPUnitAbstract try { $this->random->helloToken($token); $this->fail(); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } @@ -135,7 +137,7 @@ class randomTest extends PhraseanetPHPUnitAbstract try { $this->random->helloToken($token); $this->fail(); - } catch (Exception_NotFound $e) { + } catch (NotFoundHttpException $e) { } } diff --git a/www/api.php b/www/api.php index 2f87fc6873..ece1f8f827 100644 --- a/www/api.php +++ b/www/api.php @@ -9,13 +9,12 @@ * file that was distributed with this source code. */ -/** - * - * @license http://opensource.org/licenses/gpl-3.0 GPLv3 - * @link www.phraseanet.com - */ +use Symfony\Component\HttpKernel\Debug\ErrorHandler; + require_once __DIR__ . '/../lib/autoload.php'; +ErrorHandler::register(); + $app = require __DIR__ . '/../lib/Alchemy/Phrasea/Application/Api.php'; $app->run(); diff --git a/www/index.php b/www/index.php index e9c76071b0..22f1a537a2 100644 --- a/www/index.php +++ b/www/index.php @@ -9,13 +9,12 @@ * file that was distributed with this source code. */ -/** - * - * @license http://opensource.org/licenses/gpl-3.0 GPLv3 - * @link www.phraseanet.com - */ +use Symfony\Component\HttpKernel\Debug\ErrorHandler; + require_once __DIR__ . "/../lib/autoload.php"; +ErrorHandler::register(); + $environment = 'prod'; $app = require __DIR__ . '/../lib/Alchemy/Phrasea/Application/Root.php'; diff --git a/www/index_dev.php b/www/index_dev.php index 54a8856d07..a3119aeb90 100644 --- a/www/index_dev.php +++ b/www/index_dev.php @@ -9,13 +9,12 @@ * file that was distributed with this source code. */ -/** - * - * @license http://opensource.org/licenses/gpl-3.0 GPLv3 - * @link www.phraseanet.com - */ +use Symfony\Component\HttpKernel\Debug\ErrorHandler; + require_once __DIR__ . "/../lib/autoload.php"; +ErrorHandler::register(); + $environment = 'dev'; $app = require __DIR__ . '/../lib/Alchemy/Phrasea/Application/Root.php'; diff --git a/www/skins/error-pages/403.png b/www/skins/error-pages/403.png new file mode 100755 index 0000000000..a993f5be93 Binary files /dev/null and b/www/skins/error-pages/403.png differ diff --git a/www/skins/error-pages/404.png b/www/skins/error-pages/404.png new file mode 100755 index 0000000000..c5b9278602 Binary files /dev/null and b/www/skins/error-pages/404.png differ diff --git a/www/skins/error-pages/500.png b/www/skins/error-pages/500.png new file mode 100755 index 0000000000..d1db2859f0 Binary files /dev/null and b/www/skins/error-pages/500.png differ diff --git a/www/skins/error-pages/background.png b/www/skins/error-pages/background.png new file mode 100755 index 0000000000..7b7c65ad8f Binary files /dev/null and b/www/skins/error-pages/background.png differ diff --git a/www/skins/error-pages/error.png b/www/skins/error-pages/error.png new file mode 100755 index 0000000000..ab90f01bff Binary files /dev/null and b/www/skins/error-pages/error.png differ