aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/src/services/Files.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files/src/services/Files.ts')
-rw-r--r--apps/files/src/services/Files.ts139
1 files changed, 69 insertions, 70 deletions
diff --git a/apps/files/src/services/Files.ts b/apps/files/src/services/Files.ts
index a293154f625..080ce91e538 100644
--- a/apps/files/src/services/Files.ts
+++ b/apps/files/src/services/Files.ts
@@ -1,84 +1,60 @@
/**
- * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
- *
- * @author John Molakvoæ <skjnldsv@protonmail.com>
- *
- * @license AGPL-3.0-or-later
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
*/
-import type { ContentsWithRoot } from '@nextcloud/files'
-import type { FileStat, ResponseDataDetailed, DAVResultResponseProps } from 'webdav'
+import type { ContentsWithRoot, File, Folder, Node } from '@nextcloud/files'
+import type { FileStat, ResponseDataDetailed } from 'webdav'
+import { defaultRootPath, getDefaultPropfind, resultToNode as davResultToNode } from '@nextcloud/files/dav'
import { CancelablePromise } from 'cancelable-promise'
-import { File, Folder, davParsePermissions, davGetDefaultPropfind } from '@nextcloud/files'
-import { generateRemoteUrl } from '@nextcloud/router'
-import { getCurrentUser } from '@nextcloud/auth'
-
-import { getClient, rootPath } from './WebdavClient'
-import { hashCode } from '../utils/hashUtils'
-import logger from '../logger'
-
-const client = getClient()
-
-interface ResponseProps extends DAVResultResponseProps {
- permissions: string,
- fileid: number,
- size: number,
-}
-
-export const resultToNode = function(node: FileStat): File | Folder {
- const props = node.props as ResponseProps
- const permissions = davParsePermissions(props?.permissions)
- const owner = (props['owner-id'] || getCurrentUser()?.uid) as string
+import { join } from 'path'
+import { client } from './WebdavClient.ts'
+import { searchNodes } from './WebDavSearch.ts'
+import { getPinia } from '../store/index.ts'
+import { useFilesStore } from '../store/files.ts'
+import { useSearchStore } from '../store/search.ts'
+import logger from '../logger.ts'
+/**
+ * Slim wrapper over `@nextcloud/files` `davResultToNode` to allow using the function with `Array.map`
+ * @param stat The result returned by the webdav library
+ */
+export const resultToNode = (stat: FileStat): Node => davResultToNode(stat)
- const source = generateRemoteUrl('dav' + rootPath + node.filename)
- const id = props?.fileid < 0
- ? hashCode(source)
- : props?.fileid as number || 0
+/**
+ * Get contents implementation for the files view.
+ * This also allows to fetch local search results when the user is currently filtering.
+ *
+ * @param path - The path to query
+ */
+export function getContents(path = '/'): CancelablePromise<ContentsWithRoot> {
+ const controller = new AbortController()
+ const searchStore = useSearchStore(getPinia())
- const nodeData = {
- id,
- source,
- mtime: new Date(node.lastmod),
- mime: node.mime as string,
- size: props?.size as number || 0,
- permissions,
- owner,
- root: rootPath,
- attributes: {
- ...node,
- ...props,
- hasPreview: props?.['has-preview'],
- failed: props?.fileid < 0,
- },
+ if (searchStore.query.length >= 3) {
+ return new CancelablePromise((resolve, reject, cancel) => {
+ cancel(() => controller.abort())
+ getLocalSearch(path, searchStore.query, controller.signal)
+ .then(resolve)
+ .catch(reject)
+ })
+ } else {
+ return defaultGetContents(path)
}
-
- delete nodeData.attributes.props
-
- return node.type === 'file'
- ? new File(nodeData)
- : new Folder(nodeData)
}
-export const getContents = (path = '/'): Promise<ContentsWithRoot> => {
+/**
+ * Generic `getContents` implementation for the users files.
+ *
+ * @param path - The path to get the contents
+ */
+export function defaultGetContents(path: string): CancelablePromise<ContentsWithRoot> {
+ path = join(defaultRootPath, path)
const controller = new AbortController()
- const propfindPayload = davGetDefaultPropfind()
+ const propfindPayload = getDefaultPropfind()
return new CancelablePromise(async (resolve, reject, onCancel) => {
onCancel(() => controller.abort())
+
try {
const contentsResponse = await client.getDirectoryContents(path, {
details: true,
@@ -89,13 +65,14 @@ export const getContents = (path = '/'): Promise<ContentsWithRoot> => {
const root = contentsResponse.data[0]
const contents = contentsResponse.data.slice(1)
- if (root.filename !== path) {
+ if (root.filename !== path && `${root.filename}/` !== path) {
+ logger.debug(`Exepected "${path}" but got filename "${root.filename}" instead.`)
throw new Error('Root node does not match requested path')
}
resolve({
folder: resultToNode(root) as Folder,
- contents: contents.map(result => {
+ contents: contents.map((result) => {
try {
return resultToNode(result)
} catch (error) {
@@ -109,3 +86,25 @@ export const getContents = (path = '/'): Promise<ContentsWithRoot> => {
}
})
}
+
+/**
+ * Get the local search results for the current folder.
+ *
+ * @param path - The path
+ * @param query - The current search query
+ * @param signal - The aboort signal
+ */
+async function getLocalSearch(path: string, query: string, signal: AbortSignal): Promise<ContentsWithRoot> {
+ const filesStore = useFilesStore(getPinia())
+ let folder = filesStore.getDirectoryByPath('files', path)
+ if (!folder) {
+ const rootPath = join(defaultRootPath, path)
+ const stat = await client.stat(rootPath, { details: true }) as ResponseDataDetailed<FileStat>
+ folder = resultToNode(stat.data) as Folder
+ }
+ const contents = await searchNodes(query, { dir: path, signal })
+ return {
+ folder,
+ contents,
+ }
+}