Skip to content

Commit 3759080

Browse files
committed
fix(files): Correctly parse external shares for files UI
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
1 parent 1f394cb commit 3759080

2 files changed

Lines changed: 73 additions & 16 deletions

File tree

apps/files_sharing/src/services/SharingService.spec.ts

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
*/
2222
import type { OCSResponse } from '@nextcloud/typings/ocs'
2323
import { expect } from '@jest/globals'
24-
import { Type } from '@nextcloud/sharing'
24+
import { File, Folder } from '@nextcloud/files'
25+
import { ShareType } from '@nextcloud/sharing'
2526
import * as auth from '@nextcloud/auth'
2627
import axios from '@nextcloud/axios'
2728

2829
import { getContents } from './SharingService'
29-
import { File, Folder } from '@nextcloud/files'
3030
import logger from './logger'
3131

3232
global.window.OC = {
@@ -158,7 +158,7 @@ describe('SharingService filtering', () => {
158158
data: [
159159
{
160160
id: '62',
161-
share_type: Type.SHARE_TYPE_USER,
161+
share_type: ShareType.User,
162162
uid_owner: 'test',
163163
displayname_owner: 'test',
164164
permissions: 31,
@@ -189,7 +189,7 @@ describe('SharingService filtering', () => {
189189
})
190190

191191
test('Shared with others filtering', async () => {
192-
const shares = await getContents(false, true, false, false, [Type.SHARE_TYPE_USER])
192+
const shares = await getContents(false, true, false, false, [ShareType.User])
193193

194194
expect(axios.get).toHaveBeenCalledTimes(1)
195195
expect(shares.contents).toHaveLength(1)
@@ -198,7 +198,7 @@ describe('SharingService filtering', () => {
198198
})
199199

200200
test('Shared with others filtering empty', async () => {
201-
const shares = await getContents(false, true, false, false, [Type.SHARE_TYPE_LINK])
201+
const shares = await getContents(false, true, false, false, [ShareType.Link])
202202

203203
expect(axios.get).toHaveBeenCalledTimes(1)
204204
expect(shares.contents).toHaveLength(0)
@@ -294,6 +294,25 @@ describe('SharingService share to Node mapping', () => {
294294
tags: [window.OC.TAG_FAVORITE],
295295
}
296296

297+
const remoteFile = {
298+
mimetype: 'text/markdown',
299+
mtime: 1688721600,
300+
permissions: 19,
301+
type: 'file',
302+
file_id: 1234,
303+
id: 4,
304+
share_type: ShareType.User,
305+
parent: null,
306+
remote: 'http://exampe.com',
307+
remote_id: '12345',
308+
share_token: 'share-token',
309+
name: '/test.md',
310+
mountpoint: '/shares/test.md',
311+
owner: 'owner-uid',
312+
user: 'sharee-uid',
313+
accepted: true,
314+
}
315+
297316
test('File', async () => {
298317
jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({
299318
data: {
@@ -353,6 +372,35 @@ describe('SharingService share to Node mapping', () => {
353372
expect(folder.attributes.favorite).toBe(1)
354373
})
355374

375+
test('Remote file', async () => {
376+
jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({
377+
data: {
378+
ocs: {
379+
data: [remoteFile],
380+
},
381+
},
382+
}))
383+
384+
const shares = await getContents(false, true, false, false)
385+
386+
expect(axios.get).toHaveBeenCalledTimes(1)
387+
expect(shares.contents).toHaveLength(1)
388+
389+
const file = shares.contents[0] as File
390+
expect(file).toBeInstanceOf(File)
391+
expect(file.fileid).toBe(1234)
392+
expect(file.source).toBe('http://localhost/remote.php/dav/files/test/shares/test.md')
393+
expect(file.owner).toBe('owner-uid')
394+
expect(file.mime).toBe('text/markdown')
395+
expect(file.mtime?.getTime()).toBe(remoteFile.mtime * 1000)
396+
// not available for remote shares
397+
expect(file.size).toBe(undefined)
398+
expect(file.permissions).toBe(0)
399+
expect(file.root).toBe('/files/test')
400+
expect(file.attributes).toBeInstanceOf(Object)
401+
expect(file.attributes.favorite).toBe(0)
402+
})
403+
356404
test('Empty', async () => {
357405
jest.spyOn(logger, 'error').mockImplementationOnce(() => {})
358406
jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({

apps/files_sharing/src/services/SharingService.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@
1919
* along with this program. If not, see <http://www.gnu.org/licenses/>.
2020
*
2121
*/
22-
/* eslint-disable camelcase, n/no-extraneous-import */
23-
import type { AxiosPromise } from 'axios'
22+
import type { AxiosPromise } from '@nextcloud/axios'
2423
import type { OCSResponse } from '@nextcloud/typings/ocs'
2524

2625
import { Folder, File, type ContentsWithRoot, Permission } from '@nextcloud/files'
@@ -40,10 +39,16 @@ const ocsEntryToNode = async function(ocsEntry: any): Promise<Folder | File | nu
4039
try {
4140
// Federated share handling
4241
if (ocsEntry?.remote_id !== undefined) {
43-
const mime = (await import('mime')).default
44-
// This won't catch files without an extension, but this is the best we can do
45-
ocsEntry.mimetype = mime.getType(ocsEntry.name)
46-
ocsEntry.item_type = ocsEntry.mimetype ? 'file' : 'folder'
42+
if (!ocsEntry.mimetype) {
43+
const mime = (await import('mime')).default
44+
// This won't catch files without an extension, but this is the best we can do
45+
ocsEntry.mimetype = mime.getType(ocsEntry.name)
46+
}
47+
ocsEntry.item_type = ocsEntry.type || (ocsEntry.mimetype ? 'file' : 'folder')
48+
49+
// different naming for remote shares
50+
ocsEntry.item_mtime = ocsEntry.mtime
51+
ocsEntry.file_target = ocsEntry.file_target || ocsEntry.mountpoint
4752

4853
// Need to set permissions to NONE for federated shares
4954
ocsEntry.item_permissions = Permission.NONE
@@ -60,14 +65,15 @@ const ocsEntryToNode = async function(ocsEntry: any): Promise<Folder | File | nu
6065

6166
// If this is an external share that is not yet accepted,
6267
// we don't have an id. We can fallback to the row id temporarily
63-
const fileid = ocsEntry.file_source || ocsEntry.id
68+
// local shares (this server) use `file_source`, but remote shares (federated) use `file_id`
69+
const fileid = ocsEntry.file_source || ocsEntry.file_id || ocsEntry.id
6470

6571
// Generate path and strip double slashes
66-
const path = ocsEntry?.path || ocsEntry.file_target || ocsEntry.name
72+
const path = ocsEntry.path || ocsEntry.file_target || ocsEntry.name
6773
const source = generateRemoteUrl(`dav/${rootPath}/${path}`.replaceAll(/\/\//gm, '/'))
6874

75+
let mtime = ocsEntry.item_mtime ? new Date((ocsEntry.item_mtime) * 1000) : undefined
6976
// Prefer share time if more recent than item mtime
70-
let mtime = ocsEntry?.item_mtime ? new Date((ocsEntry.item_mtime) * 1000) : undefined
7177
if (ocsEntry?.stime > (ocsEntry?.item_mtime || 0)) {
7278
mtime = new Date((ocsEntry.stime) * 1000)
7379
}
@@ -88,7 +94,8 @@ const ocsEntryToNode = async function(ocsEntry: any): Promise<Folder | File | nu
8894
'owner-id': ocsEntry?.uid_owner,
8995
'owner-display-name': ocsEntry?.displayname_owner,
9096
'share-types': ocsEntry?.share_type,
91-
favorite: ocsEntry?.tags?.includes(window.OC.TAG_FAVORITE) ? 1 : 0,
97+
'share-attributes': ocsEntry?.attributes || '[]',
98+
favorite: ocsEntry?.tags?.includes((window.OC as Nextcloud.v29.OC & { TAG_FAVORITE: string }).TAG_FAVORITE) ? 1 : 0,
9299
},
93100
})
94101
} catch (error) {
@@ -159,6 +166,8 @@ const getDeletedShares = function(): AxiosPromise<OCSResponse<any>> {
159166
/**
160167
* Group an array of objects (here Nodes) by a key
161168
* and return an array of arrays of them.
169+
* @param nodes Nodes to group
170+
* @param key The attribute to group by
162171
*/
163172
const groupBy = function(nodes: (Folder | File)[], key: string) {
164173
return Object.values(nodes.reduce(function(acc, curr) {
@@ -168,7 +177,7 @@ const groupBy = function(nodes: (Folder | File)[], key: string) {
168177
}
169178

170179
export const getContents = async (sharedWithYou = true, sharedWithOthers = true, pendingShares = false, deletedshares = false, filterTypes: number[] = []): Promise<ContentsWithRoot> => {
171-
const promises = [] as AxiosPromise<OCSResponse<any>>[]
180+
const promises = [] as AxiosPromise<OCSResponse<unknown>>[]
172181

173182
if (sharedWithYou) {
174183
promises.push(getSharedWithYou(), getRemoteShares())

0 commit comments

Comments
 (0)