Merge pull request #47665 from nextcloud/fix/files-remote-shares

fix(files): Correctly parse external shares for files UI
pull/47659/head
Ferdinand Thiessen 2024-09-02 19:13:57 +07:00 committed by GitHub
commit f9a71f3da7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 69 additions and 14 deletions

@ -277,6 +277,25 @@ describe('SharingService share to Node mapping', () => {
tags: [TAG_FAVORITE],
}
const remoteFile = {
mimetype: 'text/markdown',
mtime: 1688721600,
permissions: 19,
type: 'file',
file_id: 1234,
id: 4,
share_type: ShareType.User,
parent: null,
remote: 'http://exampe.com',
remote_id: '12345',
share_token: 'share-token',
name: '/test.md',
mountpoint: '/shares/test.md',
owner: 'owner-uid',
user: 'sharee-uid',
accepted: true,
}
beforeEach(() => { vi.resetAllMocks() })
test('File', async () => {
@ -338,6 +357,35 @@ describe('SharingService share to Node mapping', () => {
expect(folder.attributes.favorite).toBe(1)
})
test('Remote file', async () => {
axios.get.mockReturnValueOnce(Promise.resolve({
data: {
ocs: {
data: [remoteFile],
},
},
}))
const shares = await getContents(false, true, false, false)
expect(axios.get).toHaveBeenCalledTimes(1)
expect(shares.contents).toHaveLength(1)
const file = shares.contents[0] as File
expect(file).toBeInstanceOf(File)
expect(file.fileid).toBe(1234)
expect(file.source).toBe('http://nextcloud.local/remote.php/dav/files/test/shares/test.md')
expect(file.owner).toBe('owner-uid')
expect(file.mime).toBe('text/markdown')
expect(file.mtime?.getTime()).toBe(remoteFile.mtime * 1000)
// not available for remote shares
expect(file.size).toBe(undefined)
expect(file.permissions).toBe(0)
expect(file.root).toBe('/files/test')
expect(file.attributes).toBeInstanceOf(Object)
expect(file.attributes.favorite).toBe(0)
})
test('Empty', async () => {
vi.spyOn(logger, 'error').mockImplementationOnce(() => {})
axios.get.mockReturnValueOnce(Promise.resolve({

@ -26,10 +26,16 @@ const ocsEntryToNode = async function(ocsEntry: any): Promise<Folder | File | nu
try {
// Federated share handling
if (ocsEntry?.remote_id !== undefined) {
const mime = (await import('mime')).default
// This won't catch files without an extension, but this is the best we can do
ocsEntry.mimetype = mime.getType(ocsEntry.name)
ocsEntry.item_type = ocsEntry.mimetype ? 'file' : 'folder'
if (!ocsEntry.mimetype) {
const mime = (await import('mime')).default
// This won't catch files without an extension, but this is the best we can do
ocsEntry.mimetype = mime.getType(ocsEntry.name)
}
ocsEntry.item_type = ocsEntry.type || (ocsEntry.mimetype ? 'file' : 'folder')
// different naming for remote shares
ocsEntry.item_mtime = ocsEntry.mtime
ocsEntry.file_target = ocsEntry.file_target || ocsEntry.mountpoint
// Need to set permissions to NONE for federated shares
ocsEntry.item_permissions = Permission.NONE
@ -46,14 +52,15 @@ const ocsEntryToNode = async function(ocsEntry: any): Promise<Folder | File | nu
// If this is an external share that is not yet accepted,
// we don't have an id. We can fallback to the row id temporarily
const fileid = ocsEntry.file_source || ocsEntry.id
// local shares (this server) use `file_source`, but remote shares (federated) use `file_id`
const fileid = ocsEntry.file_source || ocsEntry.file_id || ocsEntry.id
// Generate path and strip double slashes
const path = ocsEntry?.path || ocsEntry.file_target || ocsEntry.name
const path = ocsEntry.path || ocsEntry.file_target || ocsEntry.name
const source = generateRemoteUrl(`dav/${rootPath}/${path}`.replaceAll(/\/\//gm, '/'))
let mtime = ocsEntry.item_mtime ? new Date((ocsEntry.item_mtime) * 1000) : undefined
// Prefer share time if more recent than item mtime
let mtime = ocsEntry?.item_mtime ? new Date((ocsEntry.item_mtime) * 1000) : undefined
if (ocsEntry?.stime > (ocsEntry?.item_mtime || 0)) {
mtime = new Date((ocsEntry.stime) * 1000)
}
@ -75,7 +82,7 @@ const ocsEntryToNode = async function(ocsEntry: any): Promise<Folder | File | nu
'owner-display-name': ocsEntry?.displayname_owner,
'share-types': ocsEntry?.share_type,
'share-attributes': ocsEntry?.attributes || '[]',
favorite: ocsEntry?.tags?.includes((window.OC as Nextcloud.v28.OC & { TAG_FAVORITE: string }).TAG_FAVORITE) ? 1 : 0,
favorite: ocsEntry?.tags?.includes((window.OC as Nextcloud.v29.OC & { TAG_FAVORITE: string }).TAG_FAVORITE) ? 1 : 0,
},
})
} catch (error) {
@ -164,8 +171,8 @@ export const isFileRequest = (attributes = '[]'): boolean => {
/**
* Group an array of objects (here Nodes) by a key
* and return an array of arrays of them.
* @param nodes
* @param key
* @param nodes Nodes to group
* @param key The attribute to group by
*/
const groupBy = function(nodes: (Folder | File)[], key: string) {
return Object.values(nodes.reduce(function(acc, curr) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long