Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/files/src/actions/convertAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export function registerConvertActions() {
// cannot create the converted file in a public share if we don't have create permissions
return false
}
// Conversion reads the source file, so it requires read permission
if (nodes.some((node) => (node.permissions & Permission.READ) === 0)) {
return false
}
// Check that all nodes have the same mime type
return nodes.every((node) => from === node.mime)
},
Expand Down
28 changes: 28 additions & 0 deletions apps/files_sharing/src/services/SharingService.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,34 @@ describe('SharingService share to Node mapping', () => {
expect(file.attributes.favorite).toBe(0)
})

test('Pending share has no permissions', async () => {
axios.get
.mockReturnValueOnce(Promise.resolve({
data: { ocs: { data: [shareFile] } },
}))
.mockReturnValueOnce(Promise.resolve({
data: { ocs: { data: [] } },
}))

const shares = await getContents(false, false, true, false)

expect(axios.get).toHaveBeenCalledTimes(2)
expect(shares.contents).toHaveLength(1)
expect(shares.contents[0].permissions).toBe(0)
})

test('Deleted share has no permissions', async () => {
axios.get.mockReturnValueOnce(Promise.resolve({
data: { ocs: { data: [shareFolder] } },
}))

const shares = await getContents(false, false, false, true)

expect(axios.get).toHaveBeenCalledTimes(1)
expect(shares.contents).toHaveLength(1)
expect(shares.contents[0].permissions).toBe(0)
})

test('Empty', async () => {
vi.spyOn(logger, 'error').mockImplementationOnce(() => {})
axios.get.mockReturnValueOnce(Promise.resolve({
Expand Down
27 changes: 18 additions & 9 deletions apps/files_sharing/src/services/SharingService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ const headers = {
/**
*
* @param ocsEntry
* @param unmounted whether the share is not mounted into the filesystem (pending or deleted)
*/
async function ocsEntryToNode(ocsEntry: any): Promise<Folder | File | null> {
async function ocsEntryToNode(ocsEntry: any, unmounted = false): Promise<Folder | File | null> {
try {
// Federated share handling
if (ocsEntry?.remote_id !== undefined) {
Expand Down Expand Up @@ -57,6 +58,13 @@ async function ocsEntryToNode(ocsEntry: any): Promise<Folder | File | null> {
ocsEntry.displayname_owner = ocsEntry.owner
}

// Pending and deleted shares are not mounted into the user's filesystem,
// so no file operation can act on them until they are accepted or restored.
if (unmounted) {
ocsEntry.item_permissions = Permission.NONE
ocsEntry.permissions = Permission.NONE
}

const isFolder = ocsEntry?.item_type === 'folder'
const hasPreview = ocsEntry?.has_preview === true
const Node = isFolder ? Folder : File
Expand Down Expand Up @@ -238,24 +246,25 @@ function groupBy(nodes: (Folder | File)[], key: string) {
* @param filterTypes
*/
export async function getContents(sharedWithYou = true, sharedWithOthers = true, pendingShares = false, deletedshares = false, filterTypes: number[] = []): Promise<ContentsWithRoot> {
const promises = [] as AxiosPromise<OCSResponse<any>>[]
const requests = [] as { promise: AxiosPromise<OCSResponse<any>>, unmounted: boolean }[]

if (sharedWithYou) {
promises.push(getSharedWithYou(), getRemoteShares())
requests.push({ promise: getSharedWithYou(), unmounted: false }, { promise: getRemoteShares(), unmounted: false })
}
if (sharedWithOthers) {
promises.push(getSharedWithOthers())
requests.push({ promise: getSharedWithOthers(), unmounted: false })
}
if (pendingShares) {
promises.push(getPendingShares(), getRemotePendingShares())
requests.push({ promise: getPendingShares(), unmounted: true }, { promise: getRemotePendingShares(), unmounted: true })
}
if (deletedshares) {
promises.push(getDeletedShares())
requests.push({ promise: getDeletedShares(), unmounted: true })
}

const responses = await Promise.all(promises)
const data = responses.map((response) => response.data.ocs.data).flat()
let contents = (await Promise.all(data.map(ocsEntryToNode)))
const responses = await Promise.all(requests.map(({ promise }) => promise))
const data = responses.flatMap((response, index) => response.data.ocs.data
.map((entry) => ({ entry, unmounted: requests[index].unmounted })))
let contents = (await Promise.all(data.map(({ entry, unmounted }) => ocsEntryToNode(entry, unmounted))))
.filter((node) => node !== null) as (Folder | File)[]

if (filterTypes.length > 0) {
Expand Down
Loading