Skip to content

Commit bf0db90

Browse files
elzodymoodyjmz
authored andcommitted
feat(overview): use dav search
DAV search finds documents that are not only in the root folder but also recursively in subdirectories. It was specified that it should be used in the feature spec anyway. Signed-off-by: Elizabeth Danzberger <elizabeth@elzody.dev>
1 parent 31e596e commit bf0db90

2 files changed

Lines changed: 55 additions & 6 deletions

File tree

cypress/e2e/overview.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,16 @@ describe('Office overview page', function() {
7070
cy.createRandomUser().then(user => {
7171
randUser = user
7272
cy.login(user)
73+
7374
CATEGORY_FILES.forEach(({ fixture, mimeType }) => {
7475
cy.uploadFile(user, fixture, mimeType, `/${fixture}`)
7576
})
77+
78+
cy.createFolder(user, 'subfolder').then(() => {
79+
CATEGORY_FILES.forEach(({ fixture, mimeType }) => {
80+
cy.uploadFile(user, fixture, mimeType, `/subfolder/${fixture}`)
81+
})
82+
})
7683
})
7784
})
7885

@@ -110,6 +117,13 @@ describe('Office overview page', function() {
110117
})
111118
})
112119

120+
it('Shows file cards for files in subdirectories', function() {
121+
CATEGORY_FILES.forEach(({ category }) => {
122+
cy.contains('.app-navigation-entry', category).click()
123+
cy.get('.file-card').should('have.length.at.least', 2)
124+
})
125+
})
126+
113127
it('Filters file cards by search query', function() {
114128
const { category, fixture } = CATEGORY_FILES[0]
115129
const stem = fixture.split('.')[0]

src/services/officeFiles.js

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: AGPL-3.0-or-later
44
*/
55

6-
import { getClient, getDefaultPropfind, getRootPath, resultToNode } from '@nextcloud/files/dav'
6+
import { getClient, getDavNameSpaces, getDavProperties, getRootPath, resultToNode } from '@nextcloud/files/dav'
77

88
export const OFFICE_MIME_FILTERS = {
99
documents: [
@@ -38,12 +38,48 @@ export const OFFICE_MIME_FILTERS = {
3838

3939
const ALL_OFFICE_MIMES = Object.values(OFFICE_MIME_FILTERS).flat()
4040

41+
// Pre-computed at module load time — ALL_OFFICE_MIMES is static so this never changes.
42+
const OFFICE_MIME_CONDITIONS = ALL_OFFICE_MIMES
43+
.map(mime => `\t\t\t\t<d:eq><d:prop><d:getcontenttype/></d:prop><d:literal>${mime}</d:literal></d:eq>`)
44+
.join('\n')
45+
46+
/**
47+
* Build a DAV SEARCH request body that matches files of any office MIME type
48+
* across all subdirectories (depth: infinity).
49+
*
50+
* @return {string} XML string for the SEARCH request body
51+
*/
52+
function getOfficeMimeSearch() {
53+
return `<?xml version="1.0" encoding="UTF-8"?>
54+
<d:searchrequest ${getDavNameSpaces()}>
55+
<d:basicsearch>
56+
<d:select>
57+
<d:prop>
58+
${getDavProperties()}
59+
</d:prop>
60+
</d:select>
61+
<d:from>
62+
<d:scope>
63+
<d:href>${getRootPath()}/</d:href>
64+
<d:depth>infinity</d:depth>
65+
</d:scope>
66+
</d:from>
67+
<d:where>
68+
<d:or>
69+
${OFFICE_MIME_CONDITIONS}
70+
</d:or>
71+
</d:where>
72+
</d:basicsearch>
73+
</d:searchrequest>`
74+
}
75+
4176
/** @type {import('@nextcloud/files').Node[]|null} */
4277
let cachedNodes = null
4378

4479
/**
4580
* Fetch all office files once and cache the result.
4681
* Subsequent calls return the cached array.
82+
* Uses DAV SEARCH to recursively find office files across all subdirectories.
4783
*
4884
* @return {Promise<import('@nextcloud/files').Node[]>}
4985
*/
@@ -53,16 +89,15 @@ export async function getAllOfficeFiles() {
5389
}
5490

5591
const client = getClient()
56-
const propfindPayload = getDefaultPropfind()
5792

58-
const response = await client.getDirectoryContents(getRootPath(), {
93+
const response = await client.search('/', {
5994
details: true,
60-
data: propfindPayload,
95+
data: getOfficeMimeSearch(),
6196
})
6297

63-
cachedNodes = response.data
98+
cachedNodes = response.data.results
6499
.map(item => resultToNode(item))
65-
.filter(node => node.type === 'file' && ALL_OFFICE_MIMES.includes(node.mime))
100+
.filter(node => node.type === 'file')
66101

67102
return cachedNodes
68103
}

0 commit comments

Comments
 (0)