Skip to content

Commit

Permalink
Merge pull request #30795 from owncloud/privatelink-resolve-dispatcher
Browse files Browse the repository at this point in the history
Add symfony event for resolving private links by apps
  • Loading branch information
DeepDiver1975 authored Mar 26, 2018
2 parents 9216675 + 18b20de commit 4f48737
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 91 deletions.
38 changes: 23 additions & 15 deletions apps/files/lib/Controller/ViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
use OCP\IUserSession;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use OCP\AppFramework\Http;
use Symfony\Component\EventDispatcher\GenericEvent;

/**
* Class ViewController
Expand Down Expand Up @@ -283,18 +284,20 @@ public function showFile($fileId) {
$files = $baseFolder->getById($fileId);
$params = [];

$isFilesView = true;
if (empty($files) && $this->appManager->isEnabledForUser('files_trashbin')) {
// Access files_trashbin if it exists
if ( $this->rootFolder->nodeExists($uid . '/files_trashbin/files/')) {
$baseFolder = $this->rootFolder->get($uid . '/files_trashbin/files/');
$files = $baseFolder->getById($fileId);
$params['view'] = 'trashbin';
$isFilesView = false;
}
}
if (empty($files)) {
// probe apps to see if the file is in a different state and can be accessed
// through another URL
$event = new GenericEvent(null, [
'fileid' => $fileId,
'uid' => $uid,
'resolvedWebLink' => null,
'resolvedDavLink' => null,
]);
$this->eventDispatcher->dispatch('files.resolvePrivateLink', $event);

if (!empty($files)) {
$webUrl = $event->getArgument('resolvedWebLink');
$webdavUrl = $event->getArgument('resolvedDavLink');
} else {
$file = current($files);
if ($file instanceof Folder) {
// set the full path to enter the folder
Expand All @@ -305,10 +308,15 @@ public function showFile($fileId) {
// and scroll to the entry
$params['scrollto'] = $file->getName();
}
$response = new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', $params));
if ($isFilesView) {
$webdavUrl = $this->urlGenerator->linkTo('', 'remote.php') . '/dav/files/' . rawurlencode($uid) . '/';
$webdavUrl .= \OCP\Util::encodePath(ltrim($baseFolder->getRelativePath($file->getPath()), '/'));
$webUrl = $this->urlGenerator->linkToRoute('files.view.index', $params);

$webdavUrl = $this->urlGenerator->linkTo('', 'remote.php') . '/dav/files/' . rawurlencode($uid) . '/';
$webdavUrl .= \OCP\Util::encodePath(ltrim($baseFolder->getRelativePath($file->getPath()), '/'));
}

if ($webUrl) {
$response = new RedirectResponse($webUrl);
if ($webdavUrl !== null) {
$response->addHeader('Webdav-Location', $webdavUrl);
}
return $response;
Expand Down
62 changes: 14 additions & 48 deletions apps/files/tests/Controller/ViewControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
use OCP\Template;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Test\TestCase;
use Symfony\Component\EventDispatcher\GenericEvent;

/**
* Class ViewControllerTest
Expand Down Expand Up @@ -468,63 +469,28 @@ public function testShowFileRouteWithInvalidFileIdLoggedIn() {
/**
* @dataProvider showFileMethodProvider
*/
public function testShowFileRouteWithTrashedFile($useShowFile) {
$this->appManager->expects($this->once())
->method('isEnabledForUser')
->with('files_trashbin')
->will($this->returnValue(true));

public function testShowFileRouteWithDispatcher($useShowFile) {
$baseFolder = $this->createMock('\OCP\Files\Folder');
$this->rootFolder->expects($this->once())
->method('nodeExists')
->will($this->returnValue(true));

$parentNode = $this->createMock('\OCP\Files\Folder');
$parentNode->expects($this->once())
->method('getPath')
->will($this->returnValue('test@#?%test/files_trashbin/files/test.d1462861890/sub'));

$baseFolderFiles = $this->createMock('\OCP\Files\Folder');
$baseFolderTrash = $this->createMock('\OCP\Files\Folder');

$this->rootFolder->expects($this->at(0))
->method('get')
->with('test@#?%test/files/')
->will($this->returnValue($baseFolderFiles));
//The index is pointing to 2, because nodeExists internally calls get method.
$this->rootFolder->expects($this->at(2))
->method('get')
->with('test@#?%test/files_trashbin/files/')
->will($this->returnValue($baseFolderTrash));
->will($this->returnValue($baseFolder));

$baseFolderFiles->expects($this->once())
$baseFolder->expects($this->at(0))
->method('getById')
->with(123)
->will($this->returnValue([]));

$node = $this->createMock('\OCP\Files\File');
$node->expects($this->once())
->method('getParent')
->will($this->returnValue($parentNode));
$node->expects($this->once())
->method('getName')
->will($this->returnValue('somefile.txt'));

$baseFolderTrash->expects($this->at(0))
->method('getById')
->with(123)
->will($this->returnValue([$node]));
$baseFolderTrash->expects($this->at(1))
->method('getRelativePath')
->with('test@#?%test/files_trashbin/files/test.d1462861890/sub')
->will($this->returnValue('/test.d1462861890/sub'));

$this->urlGenerator
->expects($this->once())
->method('linkToRoute')
->with('files.view.index', ['view' => 'trashbin', 'dir' => '/test.d1462861890/sub', 'scrollto' => 'somefile.txt'])
->will($this->returnValue('/owncloud/index.php/apps/files/?view=trashbin&dir=/test.d1462861890/sub&scrollto=somefile.txt'));
$this->eventDispatcher->expects($this->once())
->method('dispatch')
->with('files.resolvePrivateLink')
->will($this->returnCallback(function ($eventName, $event) {
$event->setArgument('resolvedWebLink', '/owncloud/weblink/' . $event->getArgument('uid') . '/' . $event->getArgument('fileid'));
$event->setArgument('resolvedDavLink', '/owncloud/davlink/' . $event->getArgument('uid') . '/' . $event->getArgument('fileid'));
}));

$expected = new Http\RedirectResponse('/owncloud/index.php/apps/files/?view=trashbin&dir=/test.d1462861890/sub&scrollto=somefile.txt');
$expected = new Http\RedirectResponse('/owncloud/weblink/test@#?%test/123');
$expected->addHeader('Webdav-Location', '/owncloud/davlink/test@#?%test/123');
if ($useShowFile) {
$this->assertEquals($expected, $this->viewController->showFile(123));
} else {
Expand Down
3 changes: 3 additions & 0 deletions apps/files_trashbin/appinfo/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@
'name' => $l->t('Deleted files'),
];
});

$app = new \OCA\Files_Trashbin\AppInfo\Application();
$app->registerListeners();
}
16 changes: 16 additions & 0 deletions apps/files_trashbin/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use OCA\Files_Trashbin\Expiration;
use OCA\Files_Trashbin\Quota;
use OCP\AppFramework\App;
use OCA\Files_Trashbin\Trashbin;

class Application extends App {
public function __construct (array $urlParams = []) {
Expand Down Expand Up @@ -55,5 +56,20 @@ public function __construct (array $urlParams = []) {
$c->query('ServerContainer')->getConfig()
);
});

/*
* Register trashbin service
*/
$container->registerService('Trashbin', function($c) {
return new Trashbin(
$c->getServer()->getLazyRootFolder(),
$c->getServer()->getUrlGenerator(),
$c->getServer()->getEventDispatcher()
);
});
}

public function registerListeners() {
$this->getContainer()->query('Trashbin')->registerListeners();
}
}
79 changes: 79 additions & 0 deletions apps/files_trashbin/lib/Trashbin.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,39 @@
use OCA\Files_Trashbin\Command\Expire;
use OCP\Files\NotFoundException;
use OCP\User;
use Symfony\Component\EventDispatcher\GenericEvent;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\IURLGenerator;
use Symfony\Component\EventDispatcher\EventDispatcher;

class Trashbin {

/**
* @var IURLGenerator
*/
private $urlGenerator;

/**
* @var IRootFolder
*/
private $rootFolder;

/**
* @var EventDispatcher
*/
private $eventDispatcher;

public function __construct(
IRootFolder $rootFolder,
IUrlGenerator $urlGenerator,
EventDispatcher $eventDispatcher
) {
$this->rootFolder = $rootFolder;
$this->urlGenerator = $urlGenerator;
$this->eventDispatcher = $eventDispatcher;
}

/**
* Whether versions have already be rescanned during this PHP request
*
Expand Down Expand Up @@ -974,6 +1004,25 @@ private static function getTrashbinSize($user) {
return isset($fileInfo['size']) ? $fileInfo['size'] : 0;
}

/**
* Register listeners
*/
public function registerListeners() {
$this->eventDispatcher->addListener(
'files.resolvePrivateLink',
function(GenericEvent $event) {
$uid = $event->getArgument('uid');
$fileId = $event->getArgument('fileid');

$link = $this->resolvePrivateLink($uid, $fileId);

if ($link !== null) {
$event->setArgument('resolvedWebLink', $link);
}
}
);
}

/**
* register hooks
*/
Expand All @@ -990,6 +1039,36 @@ public static function registerHooks() {
\OCP\Util::connectHook('OC_Filesystem', 'post_rename', 'OCA\Files_Trashbin\Storage', 'postRenameHook');
}

/**
* Resolves web URL that points to the trashbin view of the given file
*
* @param string $uid user id
* @param string $fileId file id
* @return string|null view URL or null if the file is not found or not accessible
*/
public function resolvePrivateLink($uid, $fileId) {
if ($this->rootFolder->nodeExists($uid . '/files_trashbin/files/')) {
$baseFolder = $this->rootFolder->get($uid . '/files_trashbin/files/');
$files = $baseFolder->getById($fileId);
if (!empty($files)) {
$params['view'] = 'trashbin';
$file = current($files);
if ($file instanceof Folder) {
// set the full path to enter the folder
$params['dir'] = $baseFolder->getRelativePath($file->getPath());
} else {
// set parent path as dir
$params['dir'] = $baseFolder->getRelativePath($file->getParent()->getPath());
// and scroll to the entry
$params['scrollto'] = $file->getName();
}
return $this->urlGenerator->linkToRoute('files.view.index', $params);
}
}

return null;
}

/**
* check if trash bin is empty for a given user
*
Expand Down
Loading

0 comments on commit 4f48737

Please sign in to comment.