1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
/*!
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import type { INode } from '@nextcloud/files'
import type { ResponseDataDetailed, SearchResult } from 'webdav'
import { getCurrentUser } from '@nextcloud/auth'
import { defaultRootPath, getDavNameSpaces, getDavProperties, resultToNode } from '@nextcloud/files/dav'
import { getBaseUrl } from '@nextcloud/router'
import { client } from './WebdavClient.ts'
import logger from '../logger.ts'
export interface SearchNodesOptions {
dir?: string,
signal?: AbortSignal
}
/**
* Search for nodes matching the given query.
*
* @param query - Search query
* @param options - Options
* @param options.dir - The base directory to scope the search to
* @param options.signal - Abort signal for the request
*/
export async function searchNodes(query: string, { dir, signal }: SearchNodesOptions): Promise<INode[]> {
const user = getCurrentUser()
if (!user) {
// the search plugin only works for user roots
return []
}
query = query.trim()
if (query.length < 3) {
// the search plugin only works with queries of at least 3 characters
return []
}
if (dir && !dir.startsWith('/')) {
dir = `/${dir}`
}
logger.debug('Searching for nodes', { query, dir })
const { data } = await client.search('/', {
details: true,
signal,
data: `
<d:searchrequest ${getDavNameSpaces()}>
<d:basicsearch>
<d:select>
<d:prop>
${getDavProperties()}
</d:prop>
</d:select>
<d:from>
<d:scope>
<d:href>/files/${user.uid}${dir || ''}</d:href>
<d:depth>infinity</d:depth>
</d:scope>
</d:from>
<d:where>
<d:like>
<d:prop>
<d:displayname/>
</d:prop>
<d:literal>%${query.replace('%', '')}%</d:literal>
</d:like>
</d:where>
<d:orderby/>
</d:basicsearch>
</d:searchrequest>`,
}) as ResponseDataDetailed<SearchResult>
// check if the request was aborted
if (signal?.aborted) {
return []
}
// otherwise return the result mapped to Nextcloud nodes
return data.results.map((result) => resultToNode(result, defaultRootPath, getBaseUrl()))
}
|