diff options
-rw-r--r-- | lib/base.php | 2 | ||||
-rw-r--r-- | lib/private/AppFramework/Routing/RouteConfig.php | 55 | ||||
-rw-r--r-- | lib/private/Route/Router.php | 12 | ||||
-rw-r--r-- | ocs/v1.php | 25 | ||||
-rw-r--r-- | tests/lib/AppFramework/Routing/RoutingTest.php | 131 |
5 files changed, 224 insertions, 1 deletions
diff --git a/lib/base.php b/lib/base.php index 62ace1bc0ef..be9de93f73f 100644 --- a/lib/base.php +++ b/lib/base.php @@ -905,7 +905,7 @@ class OC { * @param OCP\IRequest $request * @return boolean */ - private static function handleLogin(OCP\IRequest $request) { + static function handleLogin(OCP\IRequest $request) { $userSession = self::$server->getUserSession(); if (OC_User::handleApacheAuth()) { return true; diff --git a/lib/private/AppFramework/Routing/RouteConfig.php b/lib/private/AppFramework/Routing/RouteConfig.php index 64179336020..eca0051691f 100644 --- a/lib/private/AppFramework/Routing/RouteConfig.php +++ b/lib/private/AppFramework/Routing/RouteConfig.php @@ -62,6 +62,61 @@ class RouteConfig { // parse resources $this->processResources($this->routes); + + /* + * OCS routes go into a different collection + */ + $oldCollection = $this->router->getCurrentCollection(); + $this->router->useCollection($oldCollection.'.ocs'); + + // parse ocs simple routes + $this->processOCS($this->routes); + + $this->router->useCollection($oldCollection); + } + + private function processOCS(array $routes) { + $ocsRoutes = isset($routes['ocs']) ? $routes['ocs'] : []; + foreach ($ocsRoutes as $ocsRoute) { + $name = $ocsRoute['name']; + $postfix = ''; + + if (isset($ocsRoute['postfix'])) { + $postfix = $ocsRoute['postfix']; + } + + $url = $ocsRoute['url']; + $verb = isset($ocsRoute['verb']) ? strtoupper($ocsRoute['verb']) : 'GET'; + + $split = explode('#', $name, 2); + if (count($split) != 2) { + throw new \UnexpectedValueException('Invalid route name'); + } + $controller = $split[0]; + $action = $split[1]; + + $controllerName = $this->buildControllerName($controller); + $actionName = $this->buildActionName($action); + + // register the route + $handler = new RouteActionHandler($this->container, $controllerName, $actionName); + + $router = $this->router->create('ocs.'.$this->appName.'.'.$controller.'.'.$action . $postfix, $url) + ->method($verb) + ->action($handler); + + // optionally register requirements for route. This is used to + // tell the route parser how url parameters should be matched + if(array_key_exists('requirements', $ocsRoute)) { + $router->requirements($ocsRoute['requirements']); + } + + // optionally register defaults for route. This is used to + // tell the route parser how url parameters should be default valued + if(array_key_exists('defaults', $ocsRoute)) { + $router->defaults($ocsRoute['defaults']); + } + } } /** diff --git a/lib/private/Route/Router.php b/lib/private/Route/Router.php index 01262be390c..f7da827c3db 100644 --- a/lib/private/Route/Router.php +++ b/lib/private/Route/Router.php @@ -150,6 +150,11 @@ class Router implements IRouter { $collection = $this->getCollection($app); $collection->addPrefix('/apps/' . $app); $this->root->addCollection($collection); + + // Also add the OCS collection + $collection = $this->getCollection($app.'.ocs'); + $collection->addPrefix('/ocsapp/apps/' . $app); + $this->root->addCollection($collection); } } if (!isset($this->loadedApps['core'])) { @@ -241,6 +246,13 @@ class Router implements IRouter { $app = \OC_App::cleanAppId($app); \OC::$REQUESTEDAPP = $app; $this->loadRoutes($app); + } else if (substr($url, 0, 13) === '/ocsapp/apps/') { + // empty string / 'ocsapp' / 'apps' / $app / rest of the route + list(, , , $app,) = explode('/', $url, 5); + + $app = \OC_App::cleanAppId($app); + \OC::$REQUESTEDAPP = $app; + $this->loadRoutes($app); } else if (substr($url, 0, 6) === '/core/' or substr($url, 0, 10) === '/settings/') { \OC::$REQUESTEDAPP = $url; if (!\OC::$server->getConfig()->getSystemValue('maintenance', false) && !Util::needUpgrade()) { diff --git a/ocs/v1.php b/ocs/v1.php index bbc2adf39b6..e3ecefccf29 100644 --- a/ocs/v1.php +++ b/ocs/v1.php @@ -42,6 +42,10 @@ if (\OCP\Util::needUpgrade() use Symfony\Component\Routing\Exception\ResourceNotFoundException; use Symfony\Component\Routing\Exception\MethodNotAllowedException; +/* + * Try old routes first + * We first try the old routes since the appframework triggers more login stuff. + */ try { OC_App::loadApps(['session']); OC_App::loadApps(['authentication']); @@ -52,6 +56,24 @@ try { \OC::$server->getL10NFactory()->setLanguageFromRequest(); OC::$server->getRouter()->match('/ocs'.\OC::$server->getRequest()->getRawPathInfo()); + return; +} catch (ResourceNotFoundException $e) { + // Fall through the not found +} catch (MethodNotAllowedException $e) { + OC_API::setContentType(); + OC_Response::setStatus(405); +} catch (\OC\OCS\Exception $ex) { + OC_API::respond($ex->getResult(), OC_API::requestedFormat()); +} + +/* + * Try the appframework routes + */ +try { + if(!\OC::$server->getUserSession()->isLoggedIn()) { + OC::handleLogin(\OC::$server->getRequest()); + } + OC::$server->getRouter()->match('/ocsapp'.\OC::$server->getRequest()->getRawPathInfo()); } catch (ResourceNotFoundException $e) { OC_API::setContentType(); OC_OCS::notFound(); @@ -60,5 +82,8 @@ try { OC_Response::setStatus(405); } catch (\OC\OCS\Exception $ex) { OC_API::respond($ex->getResult(), OC_API::requestedFormat()); +} catch (\Exception $e) { + OC_API::setContentType(); + OC_OCS::notFound(); } diff --git a/tests/lib/AppFramework/Routing/RoutingTest.php b/tests/lib/AppFramework/Routing/RoutingTest.php index 52a5eb33ba9..6c8b0f40133 100644 --- a/tests/lib/AppFramework/Routing/RoutingTest.php +++ b/tests/lib/AppFramework/Routing/RoutingTest.php @@ -18,6 +18,15 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); } + public function testSimpleOCSRoute() { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'GET'] + ] + ]; + + $this->assertSimpleOCSRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + public function testSimpleRouteWithMissingVerb() { $routes = array('routes' => array( @@ -27,6 +36,15 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); } + public function testSimpleOCSRouteWithMissingVerb() { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/folders/{folderId}/open'] + ] + ]; + + $this->assertSimpleOCSRoute($routes, 'folders.open', 'GET', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + public function testSimpleRouteWithLowercaseVerb() { $routes = array('routes' => array( @@ -36,6 +54,15 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open'); } + public function testSimpleOCSRouteWithLowercaseVerb() { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] + ] + ]; + + $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open'); + } + public function testSimpleRouteWithRequirements() { $routes = array('routes' => array( @@ -45,6 +72,15 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open', array('something')); } + public function testSimpleOCSRouteWithRequirements() { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'requirements' => ['something']] + ] + ]; + + $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open', ['something']); + } + public function testSimpleRouteWithDefaults() { $routes = array('routes' => array( @@ -54,6 +90,16 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open', array(), array('param' => 'foobar')); } + + public function testSimpleOCSRouteWithDefaults() { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'defaults' => ['param' => 'foobar']] + ] + ]; + + $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open', [], ['param' => 'foobar']); + } + public function testSimpleRouteWithPostfix() { $routes = array('routes' => array( @@ -63,6 +109,14 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open', array(), array(), '_something'); } + public function testSimpleOCSRouteWithPostfix() { + $routes = ['ocs' => [ + ['name' => 'folders#open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete', 'postfix' => '_something'] + ] + ]; + + $this->assertSimpleOCSRoute($routes, 'folders.open', 'DELETE', '/folders/{folderId}/open', 'FoldersController', 'open', [], [], '_something'); + } /** * @expectedException \UnexpectedValueException @@ -86,6 +140,27 @@ class RoutingTest extends \Test\TestCase $config->register(); } + /** + * @expectedException \UnexpectedValueException + */ + public function testSimpleOCSRouteWithBrokenName() { + $routes = ['ocs' => [ + ['name' => 'folders_open', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] + ]]; + + // router mock + $router = $this->getMockBuilder('\OC\Route\Router') + ->setMethods(['create']) + ->setConstructorArgs([$this->getMockBuilder('\OCP\ILogger')->getMock()]) + ->getMock(); + + // load route configuration + $container = new DIContainer('app1'); + $config = new RouteConfig($container, $router, $routes); + + $config->register(); + } + public function testSimpleRouteWithUnderScoreNames() { $routes = array('routes' => array( @@ -95,6 +170,14 @@ class RoutingTest extends \Test\TestCase $this->assertSimpleRoute($routes, 'admin_folders.open_current', 'DELETE', '/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent'); } + public function testSimpleOCSRouteWithUnderScoreNames() { + $routes = ['ocs' => [ + ['name' => 'admin_folders#open_current', 'url' => '/folders/{folderId}/open', 'verb' => 'delete'] + ]]; + + $this->assertSimpleOCSRoute($routes, 'admin_folders.open_current', 'DELETE', '/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent'); + } + public function testResource() { $routes = array('resources' => array('account' => array('url' => '/accounts'))); @@ -146,6 +229,54 @@ class RoutingTest extends \Test\TestCase } /** + * @param $routes + * @param string $name + * @param string $verb + * @param string $url + * @param string $controllerName + * @param string $actionName + * @param array $requirements + * @param array $defaults + * @param string $postfix + */ + private function assertSimpleOCSRoute($routes, + $name, + $verb, + $url, + $controllerName, + $actionName, + array $requirements=array(), + array $defaults=array(), + $postfix='') + { + if ($postfix) { + $name .= $postfix; + } + + // route mocks + $container = new DIContainer('app1'); + $route = $this->mockRoute($container, $verb, $controllerName, $actionName, $requirements, $defaults); + + // router mock + $router = $this->getMockBuilder('\OC\Route\Router') + ->setMethods(['create']) + ->setConstructorArgs([$this->getMockBuilder('\OCP\ILogger')->getMock()]) + ->getMock(); + + // we expect create to be called once: + $router + ->expects($this->once()) + ->method('create') + ->with($this->equalTo('ocs.app1.' . $name), $this->equalTo($url)) + ->will($this->returnValue($route)); + + // load route configuration + $config = new RouteConfig($container, $router, $routes); + + $config->register(); + } + + /** * @param string $resourceName * @param string $url * @param string $controllerName |