diff --git a/apps/files/appinfo/application.php b/apps/files/appinfo/application.php index 2d2decf628..3dd7303787 100644 --- a/apps/files/appinfo/application.php +++ b/apps/files/appinfo/application.php @@ -26,6 +26,7 @@ use OCA\Files\Controller\ApiController; use OCP\AppFramework\App; use \OCA\Files\Service\TagService; use \OCP\IContainer; +use OCA\Files\Controller\ViewController; class Application extends App { public function __construct(array $urlParams=array()) { @@ -48,6 +49,20 @@ class Application extends App { ); }); + $container->registerService('ViewController', function (IContainer $c) use ($server) { + return new ViewController( + $c->query('AppName'), + $c->query('Request'), + $server->getURLGenerator(), + $server->getNavigationManager(), + $c->query('L10N'), + $server->getConfig(), + $server->getEventDispatcher(), + $server->getUserSession(), + $server->getUserFolder() + ); + }); + /** * Core */ diff --git a/apps/files/controller/viewcontroller.php b/apps/files/controller/viewcontroller.php index ded6fd555d..6ee924e2f0 100644 --- a/apps/files/controller/viewcontroller.php +++ b/apps/files/controller/viewcontroller.php @@ -3,6 +3,7 @@ * @author Christoph Wurst * @author Lukas Reschke * @author Thomas Müller + * @author Vincent Petry * * @copyright Copyright (c) 2016, ownCloud, Inc. * @license AGPL-3.0 @@ -26,6 +27,7 @@ namespace OCA\Files\Controller; use OC\AppFramework\Http\Request; use OCP\AppFramework\Controller; use OCP\AppFramework\Http\ContentSecurityPolicy; +use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\IConfig; @@ -35,6 +37,8 @@ use OCP\IRequest; use OCP\IURLGenerator; use OCP\IUserSession; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use OCP\AppFramework\Http\NotFoundResponse; +use OCP\Files\Folder; /** * Class ViewController @@ -58,6 +62,8 @@ class ViewController extends Controller { protected $eventDispatcher; /** @var IUserSession */ protected $userSession; + /** @var \OCP\Files\Folder */ + protected $userFolder; /** * @param string $appName @@ -68,6 +74,7 @@ class ViewController extends Controller { * @param IConfig $config * @param EventDispatcherInterface $eventDispatcherInterface * @param IUserSession $userSession + * @param Folder $userFolder */ public function __construct($appName, IRequest $request, @@ -76,7 +83,9 @@ class ViewController extends Controller { IL10N $l10n, IConfig $config, EventDispatcherInterface $eventDispatcherInterface, - IUserSession $userSession) { + IUserSession $userSession, + Folder $userFolder + ) { parent::__construct($appName, $request); $this->appName = $appName; $this->request = $request; @@ -86,6 +95,7 @@ class ViewController extends Controller { $this->config = $config; $this->eventDispatcher = $eventDispatcherInterface; $this->userSession = $userSession; + $this->userFolder = $userFolder; } /** @@ -124,10 +134,15 @@ class ViewController extends Controller { * * @param string $dir * @param string $view + * @param string $fileid * @return TemplateResponse * @throws \OCP\Files\NotFoundException */ - public function index($dir = '', $view = '') { + public function index($dir = '', $view = '', $fileid = null) { + if ($fileid !== null) { + return $this->showFile($fileid); + } + $nav = new \OCP\Template('files', 'appnavigation', ''); // Load the files we need @@ -239,4 +254,33 @@ class ViewController extends Controller { return $response; } + + /** + * Redirects to the file list and highlight the given file id + * + * @param string $fileId file id to show + * @return Response redirect response or not found response + * + * @NoCSRFRequired + * @NoAdminRequired + */ + public function showFile($fileId) { + $files = $this->userFolder->getById($fileId); + $params = []; + + if (!empty($files)) { + $file = current($files); + if ($file instanceof Folder) { + // set the full path to enter the folder + $params['dir'] = $this->userFolder->getRelativePath($file->getPath()); + } else { + // set parent path as dir + $params['dir'] = $this->userFolder->getRelativePath($file->getParent()->getPath()); + // and scroll to the entry + $params['scrollto'] = $file->getName(); + } + return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', $params)); + } + return new NotFoundResponse(); + } } diff --git a/apps/files/tests/controller/ViewControllerTest.php b/apps/files/tests/controller/ViewControllerTest.php index 420e635b4b..797702def6 100644 --- a/apps/files/tests/controller/ViewControllerTest.php +++ b/apps/files/tests/controller/ViewControllerTest.php @@ -36,6 +36,7 @@ use OCP\IL10N; use OCP\IConfig; use OCP\IUserSession; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use OCP\Files\Folder; /** * Class ViewControllerTest @@ -61,6 +62,8 @@ class ViewControllerTest extends TestCase { private $user; /** @var IUserSession */ private $userSession; + /** @var Folder */ + private $userFolder; public function setUp() { parent::setUp(); @@ -75,6 +78,7 @@ class ViewControllerTest extends TestCase { $this->userSession->expects($this->any()) ->method('getUser') ->will($this->returnValue($this->user)); + $this->userFolder = $this->getMock('\OCP\Files\Folder'); $this->viewController = $this->getMockBuilder('\OCA\Files\Controller\ViewController') ->setConstructorArgs([ 'files', @@ -84,7 +88,8 @@ class ViewControllerTest extends TestCase { $this->l10n, $this->config, $this->eventDispatcher, - $this->userSession + $this->userSession, + $this->userFolder ]) ->setMethods([ 'getStorageInfo', @@ -287,4 +292,100 @@ class ViewControllerTest extends TestCase { $expected->setContentSecurityPolicy($policy); $this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView')); } + + public function showFileMethodProvider() { + return [ + [true], + [false], + ]; + } + + /** + * @dataProvider showFileMethodProvider + */ + public function testShowFileRouteWithFolder($useShowFile) { + $node = $this->getMock('\OCP\Files\Folder'); + $node->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/user/files/test/sub')); + + $this->userFolder->expects($this->at(0)) + ->method('getById') + ->with(123) + ->will($this->returnValue([$node])); + $this->userFolder->expects($this->at(1)) + ->method('getRelativePath') + ->with('/user/files/test/sub') + ->will($this->returnValue('/test/sub')); + + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRoute') + ->with('files.view.index', ['dir' => '/test/sub']) + ->will($this->returnValue('/apps/files/?dir=/test/sub')); + + $expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub'); + if ($useShowFile) { + $this->assertEquals($expected, $this->viewController->showFile(123)); + } else { + $this->assertEquals($expected, $this->viewController->index('/whatever', '', '123')); + } + } + + /** + * @dataProvider showFileMethodProvider + */ + public function testShowFileRouteWithFile($useShowFile) { + $parentNode = $this->getMock('\OCP\Files\Folder'); + $parentNode->expects($this->once()) + ->method('getPath') + ->will($this->returnValue('/user/files/test')); + + $node = $this->getMock('\OCP\Files\File'); + $node->expects($this->once()) + ->method('getParent') + ->will($this->returnValue($parentNode)); + $node->expects($this->once()) + ->method('getName') + ->will($this->returnValue('somefile.txt')); + + $this->userFolder->expects($this->at(0)) + ->method('getById') + ->with(123) + ->will($this->returnValue([$node])); + $this->userFolder->expects($this->at(1)) + ->method('getRelativePath') + ->with('/user/files/test') + ->will($this->returnValue('/test')); + + $this->urlGenerator + ->expects($this->once()) + ->method('linkToRoute') + ->with('files.view.index', ['dir' => '/test', 'scrollto' => 'somefile.txt']) + ->will($this->returnValue('/apps/files/?dir=/test/sub&scrollto=somefile.txt')); + + $expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub&scrollto=somefile.txt'); + if ($useShowFile) { + $this->assertEquals($expected, $this->viewController->showFile(123)); + } else { + $this->assertEquals($expected, $this->viewController->index('/whatever', '', '123')); + } + } + + /** + * @dataProvider showFileMethodProvider + */ + public function testShowFileRouteWithInvalidFileId($useShowFile) { + $this->userFolder->expects($this->at(0)) + ->method('getById') + ->with(123) + ->will($this->returnValue([])); + + $expected = new Http\NotFoundResponse(); + if ($useShowFile) { + $this->assertEquals($expected, $this->viewController->showFile(123)); + } else { + $this->assertEquals($expected, $this->viewController->index('/whatever', '', '123')); + } + } } diff --git a/core/routes.php b/core/routes.php index 2b7a19f7d8..a9c800af4e 100644 --- a/core/routes.php +++ b/core/routes.php @@ -108,6 +108,12 @@ $this->create('core_ajax_preview', '/core/preview.png') $this->create('core_ajax_update', '/core/ajax/update.php') ->actionInclude('core/ajax/update.php'); +// File routes +$this->create('files.viewcontroller.showFile', '/f/{fileId}')->action(function($urlParams) { + $app = new \OCA\Files\AppInfo\Application($urlParams); + $app->dispatch('ViewController', 'showFile'); +}); + // Sharing routes $this->create('files_sharing.sharecontroller.showShare', '/s/{token}')->action(function($urlParams) { $app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);