aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/files/appinfo/routes.php6
-rw-r--r--apps/files/lib/Controller/ViewController.php136
-rw-r--r--apps/files/src/actions/openInFilesAction.spec.ts4
-rw-r--r--apps/files/src/actions/openInFilesAction.ts2
-rw-r--r--apps/files/src/actions/sidebarAction.ts6
-rw-r--r--apps/files/src/components/FilesListVirtual.vue12
-rw-r--r--apps/files/src/views/Sidebar.vue58
-rw-r--r--apps/files/tests/Controller/ViewControllerTest.php169
8 files changed, 159 insertions, 234 deletions
diff --git a/apps/files/appinfo/routes.php b/apps/files/appinfo/routes.php
index 05d0a37fd70..97f47facff0 100644
--- a/apps/files/appinfo/routes.php
+++ b/apps/files/appinfo/routes.php
@@ -139,16 +139,14 @@ $application->registerRoutes(
'verb' => 'GET'
],
[
- 'name' => 'view#index',
+ 'name' => 'view#indexView',
'url' => '/{view}',
'verb' => 'GET',
- 'postfix' => 'view',
],
[
- 'name' => 'view#index',
+ 'name' => 'view#indexViewFileid',
'url' => '/{view}/{fileid}',
'verb' => 'GET',
- 'postfix' => 'fileid',
],
],
'ocs' => [
diff --git a/apps/files/lib/Controller/ViewController.php b/apps/files/lib/Controller/ViewController.php
index e8621c1fa14..8fe7eea01a0 100644
--- a/apps/files/lib/Controller/ViewController.php
+++ b/apps/files/lib/Controller/ViewController.php
@@ -153,17 +153,36 @@ class ViewController extends Controller {
*
* @param string $fileid
* @return TemplateResponse|RedirectResponse
- * @throws NotFoundException
*/
- public function showFile(string $fileid = null, int $openfile = 1): Response {
+ public function showFile(string $fileid = null): Response {
+ if (!$fileid) {
+ return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index'));
+ }
+
// This is the entry point from the `/f/{fileid}` URL which is hardcoded in the server.
try {
- return $this->redirectToFile($fileid, $openfile !== 0);
+ return $this->redirectToFile((int) $fileid);
} catch (NotFoundException $e) {
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', ['fileNotFound' => true]));
}
}
+
+ /**
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ * @UseSession
+ *
+ * @param string $dir
+ * @param string $view
+ * @param string $fileid
+ * @param bool $fileNotFound
+ * @return TemplateResponse|RedirectResponse
+ */
+ public function indexView($dir = '', $view = '', $fileid = null, $fileNotFound = false) {
+ return $this->index($dir, $view, $fileid, $fileNotFound);
+ }
+
/**
* @NoCSRFRequired
* @NoAdminRequired
@@ -173,11 +192,30 @@ class ViewController extends Controller {
* @param string $view
* @param string $fileid
* @param bool $fileNotFound
- * @param string $openfile - the openfile URL parameter if it was present in the initial request
* @return TemplateResponse|RedirectResponse
- * @throws NotFoundException
*/
- public function index($dir = '', $view = '', $fileid = null, $fileNotFound = false, $openfile = null) {
+ public function indexViewFileid($dir = '', $view = '', $fileid = null, $fileNotFound = false) {
+ return $this->index($dir, $view, $fileid, $fileNotFound);
+ }
+
+ /**
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ * @UseSession
+ *
+ * @param string $dir
+ * @param string $view
+ * @param string $fileid
+ * @param bool $fileNotFound
+ * @return TemplateResponse|RedirectResponse
+ */
+ public function index($dir = '', $view = '', $fileid = null, $fileNotFound = false) {
+ if ($fileid !== null && $view !== 'trashbin') {
+ try {
+ return $this->redirectToFileIfInTrashbin((int) $fileid);
+ } catch (NotFoundException $e) {}
+ }
+
// Load the files we need
\OCP\Util::addStyle('files', 'merged');
\OCP\Util::addScript('files', 'merged-index', 'files');
@@ -192,8 +230,6 @@ class ViewController extends Controller {
$favElements['folders'] = [];
}
- $contentItems = [];
-
try {
// If view is files, we use the directory, otherwise we use the root storage
$storageInfo = $this->getStorageInfo(($view === 'files' && $dir) ? $dir : '/');
@@ -237,19 +273,19 @@ class ViewController extends Controller {
$policy->addAllowedWorkerSrcDomain('\'self\'');
$response->setContentSecurityPolicy($policy);
- $this->provideInitialState($dir, $openfile);
+ $this->provideInitialState($dir, $fileid);
return $response;
}
/**
- * Add openFileInfo in initialState if $openfile is set.
+ * Add openFileInfo in initialState.
* @param string $dir - the ?dir= URL param
- * @param string $openfile - the ?openfile= URL param
+ * @param string $fileid - the fileid URL param
* @return void
*/
- private function provideInitialState(string $dir, ?string $openfile): void {
- if ($openfile === null) {
+ private function provideInitialState(string $dir, ?string $fileid): void {
+ if ($fileid === null) {
return;
}
@@ -261,7 +297,7 @@ class ViewController extends Controller {
$uid = $user->getUID();
$userFolder = $this->rootFolder->getUserFolder($uid);
- $nodes = $userFolder->getById((int) $openfile);
+ $nodes = $userFolder->getById((int) $fileid);
$node = array_shift($nodes);
if ($node === null) {
@@ -293,44 +329,70 @@ class ViewController extends Controller {
}
/**
- * Redirects to the file list and highlight the given file id
+ * Redirects to the trashbin file list and highlight the given file id
*
- * @param string $fileId file id to show
- * @param bool $setOpenfile - whether or not to set the openfile URL parameter
+ * @param int $fileId file id to show
* @return RedirectResponse redirect response or not found response
- * @throws \OCP\Files\NotFoundException
+ * @throws NotFoundException
*/
- private function redirectToFile($fileId, bool $setOpenfile = false) {
+ private function redirectToFileIfInTrashbin($fileId): RedirectResponse {
$uid = $this->userSession->getUser()->getUID();
$baseFolder = $this->rootFolder->getUserFolder($uid);
- $files = $baseFolder->getById($fileId);
+ $nodes = $baseFolder->getById($fileId);
$params = [];
- if (empty($files) && $this->appManager->isEnabledForUser('files_trashbin')) {
+ if (empty($nodes) && $this->appManager->isEnabledForUser('files_trashbin')) {
+ /** @var Folder */
$baseFolder = $this->rootFolder->get($uid . '/files_trashbin/files/');
- $files = $baseFolder->getById($fileId);
+ $nodes = $baseFolder->getById($fileId);
$params['view'] = 'trashbin';
+
+ if (!empty($nodes)) {
+ $node = current($nodes);
+ $params['fileid'] = $fileId;
+ if ($node instanceof Folder) {
+ // set the full path to enter the folder
+ $params['dir'] = $baseFolder->getRelativePath($node->getPath());
+ } else {
+ // set parent path as dir
+ $params['dir'] = $baseFolder->getRelativePath($node->getParent()->getPath());
+ }
+ return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.indexViewFileid', $params));
+ }
}
+ throw new NotFoundException();
+ }
- if (!empty($files)) {
- $file = current($files);
- if ($file instanceof Folder) {
+ /**
+ * Redirects to the file list and highlight the given file id
+ *
+ * @param int $fileId file id to show
+ * @return RedirectResponse redirect response or not found response
+ * @throws NotFoundException
+ */
+ private function redirectToFile(int $fileId) {
+ $uid = $this->userSession->getUser()->getUID();
+ $baseFolder = $this->rootFolder->getUserFolder($uid);
+ $nodes = $baseFolder->getById($fileId);
+ $params = [];
+
+ try {
+ $this->redirectToFileIfInTrashbin($fileId);
+ } catch (NotFoundException $e) {}
+
+ if (!empty($nodes)) {
+ $node = current($nodes);
+ $params['fileid'] = $fileId;
+ if ($node instanceof Folder) {
// set the full path to enter the folder
- $params['dir'] = $baseFolder->getRelativePath($file->getPath());
+ $params['dir'] = $baseFolder->getRelativePath($node->getPath());
} else {
// set parent path as dir
- $params['dir'] = $baseFolder->getRelativePath($file->getParent()->getPath());
- // and scroll to the entry
- $params['scrollto'] = $file->getName();
-
- if ($setOpenfile) {
- // forward the openfile URL parameter.
- $params['openfile'] = $fileId;
- }
+ $params['dir'] = $baseFolder->getRelativePath($node->getParent()->getPath());
}
-
- return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', $params));
+ return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.indexViewFileid', $params));
}
- throw new \OCP\Files\NotFoundException();
+
+ throw new NotFoundException();
}
}
diff --git a/apps/files/src/actions/openInFilesAction.spec.ts b/apps/files/src/actions/openInFilesAction.spec.ts
index 302a6c45c6b..4fc402c73a8 100644
--- a/apps/files/src/actions/openInFilesAction.spec.ts
+++ b/apps/files/src/actions/openInFilesAction.spec.ts
@@ -78,7 +78,7 @@ describe('Open in files action execute tests', () => {
// Silent action
expect(exec).toBe(null)
expect(goToRouteMock).toBeCalledTimes(1)
- expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/Foo', openfile: true })
+ expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/Foo' })
})
test('Open in files with folder', async () => {
@@ -98,6 +98,6 @@ describe('Open in files action execute tests', () => {
// Silent action
expect(exec).toBe(null)
expect(goToRouteMock).toBeCalledTimes(1)
- expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/Foo/Bar', openfile: true })
+ expect(goToRouteMock).toBeCalledWith(null, { fileid: 1, view: 'files' }, { fileid: 1, dir: '/Foo/Bar' })
})
})
diff --git a/apps/files/src/actions/openInFilesAction.ts b/apps/files/src/actions/openInFilesAction.ts
index 283bfc63d50..9d3ceaf3b7b 100644
--- a/apps/files/src/actions/openInFilesAction.ts
+++ b/apps/files/src/actions/openInFilesAction.ts
@@ -44,7 +44,7 @@ export const action = new FileAction({
window.OCP.Files.Router.goToRoute(
null, // use default route
{ view: 'files', fileid: node.fileid },
- { dir, fileid: node.fileid, openfile: true },
+ { dir, fileid: node.fileid },
)
return null
},
diff --git a/apps/files/src/actions/sidebarAction.ts b/apps/files/src/actions/sidebarAction.ts
index 0073d1c8490..849cf78368d 100644
--- a/apps/files/src/actions/sidebarAction.ts
+++ b/apps/files/src/actions/sidebarAction.ts
@@ -42,6 +42,10 @@ export const action = new FileAction({
return false
}
+ if (!nodes[0]) {
+ return false
+ }
+
// Only work if the sidebar is available
if (!window?.OCA?.Files?.Sidebar) {
return false
@@ -53,7 +57,7 @@ export const action = new FileAction({
async exec(node: Node, view: Navigation) {
try {
// TODO: migrate Sidebar to use a Node instead
- window?.OCA?.Files?.Sidebar?.open?.(node.path)
+ await window.OCA.Files.Sidebar.open(node.path)
// Silently update current fileid
window.OCP.Files.Router.goToRoute(
diff --git a/apps/files/src/components/FilesListVirtual.vue b/apps/files/src/components/FilesListVirtual.vue
index c943b899897..8c7242561e9 100644
--- a/apps/files/src/components/FilesListVirtual.vue
+++ b/apps/files/src/components/FilesListVirtual.vue
@@ -69,15 +69,17 @@
<script lang="ts">
import { translate, translatePlural } from '@nextcloud/l10n'
import { getFileListHeaders, type Node } from '@nextcloud/files'
+import { showError } from '@nextcloud/dialogs'
import Vue from 'vue'
import VirtualList from './VirtualList.vue'
+import { action as sidebarAction } from '../actions/sidebarAction.ts'
import FileEntry from './FileEntry.vue'
import FilesListHeader from './FilesListHeader.vue'
import FilesListTableFooter from './FilesListTableFooter.vue'
import FilesListTableHeader from './FilesListTableHeader.vue'
import filesListWidthMixin from '../mixins/filesListWidth.ts'
-import { showError } from '@nextcloud/dialogs'
+import logger from '../logger.js'
export default Vue.extend({
name: 'FilesListVirtual',
@@ -174,10 +176,10 @@ export default Vue.extend({
if (document.documentElement.clientWidth > 1024) {
// Open the sidebar on the file if it's in the url and
// we're just loaded the app for the first time.
- const Sidebar = window?.OCA?.Files?.Sidebar
- const node = this.nodes.find(node => node.fileid === this.fileId) as Node
- if (Sidebar && node) {
- Sidebar.open(node.path)
+ const node = this.nodes.find(n => n.fileid === this.fileId) as Node
+ if (node && sidebarAction?.enabled?.([node], this.currentView)) {
+ logger.debug('Opening sidebar on file ' + node.path, { node })
+ sidebarAction.exec(node, this.currentView, this.currentFolder)
}
}
},
diff --git a/apps/files/src/views/Sidebar.vue b/apps/files/src/views/Sidebar.vue
index f3d6fe7972e..65e4c302632 100644
--- a/apps/files/src/views/Sidebar.vue
+++ b/apps/files/src/views/Sidebar.vue
@@ -451,39 +451,41 @@ export default {
* @throws {Error} loading failure
*/
async open(path) {
+ if (!path || path.trim() === '') {
+ throw new Error(`Invalid path '${path}'`)
+ }
+
// update current opened file
this.Sidebar.file = path
- if (path && path.trim() !== '') {
- // reset data, keep old fileInfo to not reload all tabs and just hide them
- this.error = null
- this.loading = true
+ // reset data, keep old fileInfo to not reload all tabs and just hide them
+ this.error = null
+ this.loading = true
- try {
- this.fileInfo = await FileInfo(this.davPath)
- // adding this as fallback because other apps expect it
- this.fileInfo.dir = this.file.split('/').slice(0, -1).join('/')
-
- // DEPRECATED legacy views
- // TODO: remove
- this.views.forEach(view => {
- view.setFileInfo(this.fileInfo)
- })
-
- this.$nextTick(() => {
- if (this.$refs.tabs) {
- this.$refs.tabs.updateTabs()
- }
- this.setActiveTab(this.Sidebar.activeTab || this.tabs[0].id)
- })
- } catch (error) {
- this.error = t('files', 'Error while loading the file data')
- console.error('Error while loading the file data', error)
+ try {
+ this.fileInfo = await FileInfo(this.davPath)
+ // adding this as fallback because other apps expect it
+ this.fileInfo.dir = this.file.split('/').slice(0, -1).join('/')
+
+ // DEPRECATED legacy views
+ // TODO: remove
+ this.views.forEach(view => {
+ view.setFileInfo(this.fileInfo)
+ })
- throw new Error(error)
- } finally {
- this.loading = false
- }
+ this.$nextTick(() => {
+ if (this.$refs.tabs) {
+ this.$refs.tabs.updateTabs()
+ }
+ this.setActiveTab(this.Sidebar.activeTab || this.tabs[0].id)
+ })
+ } catch (error) {
+ this.error = t('files', 'Error while loading the file data')
+ console.error('Error while loading the file data', error)
+
+ throw new Error(error)
+ } finally {
+ this.loading = false
}
},
diff --git a/apps/files/tests/Controller/ViewControllerTest.php b/apps/files/tests/Controller/ViewControllerTest.php
index d9ccaf47eed..b997bbcad65 100644
--- a/apps/files/tests/Controller/ViewControllerTest.php
+++ b/apps/files/tests/Controller/ViewControllerTest.php
@@ -163,74 +163,28 @@ class ViewControllerTest extends TestCase {
[$this->user->getUID(), 'files', 'crop_image_previews', true, true],
[$this->user->getUID(), 'files', 'show_grid', true],
]);
+
+ $baseFolderFiles = $this->getMockBuilder(Folder::class)->getMock();
+
+ $this->rootFolder->expects($this->any())
+ ->method('getUserFolder')
+ ->with('testuser1')
+ ->willReturn($baseFolderFiles);
$this->config
->expects($this->any())
->method('getAppValue')
->willReturnArgument(2);
- $this->shareManager->method('shareApiAllowLinks')
- ->willReturn(true);
-
- $nav = new Template('files', 'appnavigation');
- $nav->assign('navigationItems', [
- 'files' => [
- 'id' => 'files',
- 'appname' => 'files',
- 'script' => 'list.php',
- 'order' => 0,
- 'name' => \OC::$server->getL10N('files')->t('All files'),
- 'active' => false,
- 'icon' => '',
- 'type' => 'link',
- 'classes' => '',
- 'expanded' => false,
- 'unread' => 0,
- ],
- 'systemtagsfilter' => [
- 'id' => 'systemtagsfilter',
- 'appname' => 'systemtags',
- 'script' => 'list.php',
- 'order' => 25,
- 'name' => \OC::$server->getL10N('systemtags')->t('Tags'),
- 'active' => false,
- 'icon' => '',
- 'type' => 'link',
- 'classes' => '',
- 'expanded' => false,
- 'unread' => 0,
- ],
- ]);
$expected = new Http\TemplateResponse(
'files',
'index',
[
- 'usedSpacePercent' => 123,
- 'owner' => 'MyName',
- 'ownerDisplayName' => 'MyDisplayName',
- 'isPublic' => false,
- 'defaultFileSorting' => 'basename',
- 'defaultFileSortingDirection' => 'asc',
- 'showHiddenFiles' => 0,
- 'cropImagePreviews' => 1,
'fileNotFound' => 0,
- 'allowShareWithLink' => 'yes',
- 'appNavigation' => $nav,
- 'appContents' => [
- 'files' => [
- 'id' => 'files',
- 'content' => null,
- ],
- 'systemtagsfilter' => [
- 'id' => 'systemtagsfilter',
- 'content' => null,
- ],
- ],
- 'hiddenFields' => [],
- 'showgridview' => null
]
);
$policy = new Http\ContentSecurityPolicy();
+ $policy->addAllowedWorkerSrcDomain('\'self\'');
$policy->addAllowedFrameDomain('\'self\'');
$expected->setContentSecurityPolicy($policy);
@@ -249,100 +203,6 @@ class ViewControllerTest extends TestCase {
$this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView'));
}
- public function testShowFileRouteWithFolder() {
- $node = $this->getMockBuilder(Folder::class)->getMock();
- $node->expects($this->once())
- ->method('getPath')
- ->willReturn('/testuser1/files/test/sub');
-
- $baseFolder = $this->getMockBuilder(Folder::class)->getMock();
-
- $this->rootFolder->expects($this->once())
- ->method('getUserFolder')
- ->with('testuser1')
- ->willReturn($baseFolder);
-
- $baseFolder->expects($this->once())
- ->method('getById')
- ->with(123)
- ->willReturn([$node]);
- $baseFolder->expects($this->once())
- ->method('getRelativePath')
- ->with('/testuser1/files/test/sub')
- ->willReturn('/test/sub');
-
- $this->urlGenerator
- ->expects($this->once())
- ->method('linkToRoute')
- ->with('files.view.index', ['dir' => '/test/sub'])
- ->willReturn('/apps/files/?dir=/test/sub');
-
- $expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub');
- $this->assertEquals($expected, $this->viewController->index('', '', '123'));
- }
-
- public function testShowFileRouteWithFile() {
- $parentNode = $this->getMockBuilder(Folder::class)->getMock();
- $parentNode->expects($this->once())
- ->method('getPath')
- ->willReturn('testuser1/files/test');
-
- $baseFolder = $this->getMockBuilder(Folder::class)->getMock();
-
- $this->rootFolder->expects($this->once())
- ->method('getUserFolder')
- ->with('testuser1')
- ->willReturn($baseFolder);
-
- $node = $this->getMockBuilder(File::class)->getMock();
- $node->expects($this->once())
- ->method('getParent')
- ->willReturn($parentNode);
- $node->expects($this->once())
- ->method('getName')
- ->willReturn('somefile.txt');
-
- $baseFolder->expects($this->once())
- ->method('getById')
- ->with(123)
- ->willReturn([$node]);
- $baseFolder->expects($this->once())
- ->method('getRelativePath')
- ->with('testuser1/files/test')
- ->willReturn('/test');
-
- $this->urlGenerator
- ->expects($this->once())
- ->method('linkToRoute')
- ->with('files.view.index', ['dir' => '/test', 'scrollto' => 'somefile.txt'])
- ->willReturn('/apps/files/?dir=/test/sub&scrollto=somefile.txt');
-
- $expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub&scrollto=somefile.txt');
- $this->assertEquals($expected, $this->viewController->index('', '', '123'));
- }
-
- public function testShowFileRouteWithInvalidFileId() {
- $baseFolder = $this->getMockBuilder(Folder::class)->getMock();
- $this->rootFolder->expects($this->once())
- ->method('getUserFolder')
- ->with('testuser1')
- ->willReturn($baseFolder);
-
- $baseFolder->expects($this->once())
- ->method('getById')
- ->with(123)
- ->willReturn([]);
-
- $this->urlGenerator->expects($this->once())
- ->method('linkToRoute')
- ->with('files.view.index', ['fileNotFound' => true])
- ->willReturn('redirect.url');
-
- $response = $this->viewController->index('', 'MyView', '123');
- $this->assertInstanceOf('OCP\AppFramework\Http\RedirectResponse', $response);
- $this->assertEquals('redirect.url', $response->getRedirectURL());
- }
-
public function testShowFileRouteWithTrashedFile() {
$this->appManager->expects($this->once())
->method('isEnabledForUser')
@@ -357,7 +217,7 @@ class ViewControllerTest extends TestCase {
$baseFolderFiles = $this->getMockBuilder(Folder::class)->getMock();
$baseFolderTrash = $this->getMockBuilder(Folder::class)->getMock();
- $this->rootFolder->expects($this->once())
+ $this->rootFolder->expects($this->any())
->method('getUserFolder')
->with('testuser1')
->willReturn($baseFolderFiles);
@@ -366,7 +226,7 @@ class ViewControllerTest extends TestCase {
->with('testuser1/files_trashbin/files/')
->willReturn($baseFolderTrash);
- $baseFolderFiles->expects($this->once())
+ $baseFolderFiles->expects($this->any())
->method('getById')
->with(123)
->willReturn([]);
@@ -375,9 +235,6 @@ class ViewControllerTest extends TestCase {
$node->expects($this->once())
->method('getParent')
->willReturn($parentNode);
- $node->expects($this->once())
- ->method('getName')
- ->willReturn('somefile.txt');
$baseFolderTrash->expects($this->once())
->method('getById')
@@ -391,10 +248,10 @@ class ViewControllerTest extends TestCase {
$this->urlGenerator
->expects($this->once())
->method('linkToRoute')
- ->with('files.view.index', ['view' => 'trashbin', 'dir' => '/test.d1462861890/sub', 'scrollto' => 'somefile.txt'])
- ->willReturn('/apps/files/?view=trashbin&dir=/test.d1462861890/sub&scrollto=somefile.txt');
+ ->with('files.view.indexViewFileid', ['view' => 'trashbin', 'dir' => '/test.d1462861890/sub', 'fileid' => '123'])
+ ->willReturn('/apps/files/trashbin/123?dir=/test.d1462861890/sub');
- $expected = new Http\RedirectResponse('/apps/files/?view=trashbin&dir=/test.d1462861890/sub&scrollto=somefile.txt');
+ $expected = new Http\RedirectResponse('/apps/files/trashbin/123?dir=/test.d1462861890/sub');
$this->assertEquals($expected, $this->viewController->index('', '', '123'));
}
}