aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_sharing
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-09-01 00:37:56 +0200
committerAndy Scherzinger <info@andy-scherzinger.de>2024-09-03 07:13:21 +0200
commit5535151cc3d44ad11472d9db9451b562cd455c7f (patch)
tree955a39f6d1f27dfae3b6a41567af1ba21566e2b4 /apps/files_sharing
parent8b7329bfb19209521ca6fcef278abd45e1c68833 (diff)
downloadnextcloud-server-5535151cc3d44ad11472d9db9451b562cd455c7f.tar.gz
nextcloud-server-5535151cc3d44ad11472d9db9451b562cd455c7f.zip
fix(files): Correctly parse external shares for files UI
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'apps/files_sharing')
-rw-r--r--apps/files_sharing/src/services/SharingService.spec.ts58
-rw-r--r--apps/files_sharing/src/services/SharingService.ts27
2 files changed, 70 insertions, 15 deletions
diff --git a/apps/files_sharing/src/services/SharingService.spec.ts b/apps/files_sharing/src/services/SharingService.spec.ts
index ba0591a765a..388b0a7cc26 100644
--- a/apps/files_sharing/src/services/SharingService.spec.ts
+++ b/apps/files_sharing/src/services/SharingService.spec.ts
@@ -4,12 +4,12 @@
*/
import type { OCSResponse } from '@nextcloud/typings/ocs'
import { expect } from '@jest/globals'
-import { Type } from '@nextcloud/sharing'
+import { File, Folder } from '@nextcloud/files'
+import { ShareType } from '@nextcloud/sharing'
import * as auth from '@nextcloud/auth'
import axios from '@nextcloud/axios'
import { getContents } from './SharingService'
-import { File, Folder } from '@nextcloud/files'
import logger from './logger'
window.OC = {
@@ -142,7 +142,7 @@ describe('SharingService filtering', () => {
data: [
{
id: '62',
- share_type: Type.SHARE_TYPE_USER,
+ share_type: ShareType.User,
uid_owner: 'test',
displayname_owner: 'test',
permissions: 31,
@@ -173,7 +173,7 @@ describe('SharingService filtering', () => {
})
test('Shared with others filtering', async () => {
- const shares = await getContents(false, true, false, false, [Type.SHARE_TYPE_USER])
+ const shares = await getContents(false, true, false, false, [ShareType.User])
expect(axios.get).toHaveBeenCalledTimes(1)
expect(shares.contents).toHaveLength(1)
@@ -182,7 +182,7 @@ describe('SharingService filtering', () => {
})
test('Shared with others filtering empty', async () => {
- const shares = await getContents(false, true, false, false, [Type.SHARE_TYPE_LINK])
+ const shares = await getContents(false, true, false, false, [ShareType.Link])
expect(axios.get).toHaveBeenCalledTimes(1)
expect(shares.contents).toHaveLength(0)
@@ -278,6 +278,25 @@ describe('SharingService share to Node mapping', () => {
tags: [window.OC.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,
+ }
+
test('File', async () => {
jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({
data: {
@@ -337,6 +356,35 @@ describe('SharingService share to Node mapping', () => {
expect(folder.attributes.favorite).toBe(1)
})
+ test('Remote file', async () => {
+ jest.spyOn(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://localhost/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 () => {
jest.spyOn(logger, 'error').mockImplementationOnce(() => {})
jest.spyOn(axios, 'get').mockReturnValueOnce(Promise.resolve({
diff --git a/apps/files_sharing/src/services/SharingService.ts b/apps/files_sharing/src/services/SharingService.ts
index 4206e4a305a..e168f202fba 100644
--- a/apps/files_sharing/src/services/SharingService.ts
+++ b/apps/files_sharing/src/services/SharingService.ts
@@ -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) {