Skip to content

Commit 560be2c

Browse files
committed
fix(files): verify files are still accessible before downloading
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
1 parent f0c392e commit 560be2c

File tree

1 file changed

+55
-9
lines changed

1 file changed

+55
-9
lines changed

apps/files/src/actions/downloadAction.ts

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,28 @@
44
*/
55
import type { Node, View } from '@nextcloud/files'
66
import { FileAction, FileType, DefaultType } from '@nextcloud/files'
7+
import { showError } from '@nextcloud/dialogs'
78
import { t } from '@nextcloud/l10n'
8-
import { isDownloadable } from '../utils/permissions'
9+
import axios from '@nextcloud/axios'
910

1011
import ArrowDownSvg from '@mdi/svg/svg/arrow-down.svg?raw'
1112

13+
import { isDownloadable } from '../utils/permissions'
14+
import { usePathsStore } from '../store/paths'
15+
import { getPinia } from '../store'
16+
import { useFilesStore } from '../store/files'
17+
import { emit } from '@nextcloud/event-bus'
18+
1219
/**
1320
* Trigger downloading a file.
1421
*
1522
* @param url The url of the asset to download
1623
* @param name Optionally the recommended name of the download (browsers might ignore it)
1724
*/
18-
function triggerDownload(url: string, name?: string) {
25+
async function triggerDownload(url: string, name?: string) {
26+
// try to see if the resource is still available
27+
await axios.head(url)
28+
1929
const hiddenElement = document.createElement('a')
2030
hiddenElement.download = name ?? ''
2131
hiddenElement.href = url
@@ -44,12 +54,22 @@ function longestCommonPath(first: string, second: string): string {
4454
return base
4555
}
4656

47-
const downloadNodes = function(nodes: Node[]) {
57+
58+
/**
59+
* Download the given nodes.
60+
*
61+
* If only one node is given, it will be downloaded directly.
62+
* If multiple nodes are given, they will be zipped and downloaded.
63+
*
64+
* @param nodes The node(s) to download
65+
*/
66+
async function downloadNodes(nodes: Node[]) {
4867
let url: URL
4968

5069
if (nodes.length === 1) {
5170
if (nodes[0].type === FileType.File) {
52-
return triggerDownload(nodes[0].encodedSource, nodes[0].displayname)
71+
await triggerDownload(nodes[0].encodedSource, nodes[0].displayname)
72+
return
5373
} else {
5474
url = new URL(nodes[0].encodedSource)
5575
url.searchParams.append('accept', 'zip')
@@ -72,7 +92,21 @@ const downloadNodes = function(nodes: Node[]) {
7292
url.pathname = `${url.pathname}/`
7393
}
7494

75-
return triggerDownload(url.href)
95+
await triggerDownload(url.href)
96+
}
97+
98+
function getCurrentDirectory(view: View, directory: string): ?Node {
99+
const filesStore = useFilesStore(getPinia())
100+
const pathsStore = usePathsStore(getPinia())
101+
if (!view?.id) {
102+
return null
103+
}
104+
105+
if (directory === '/') {
106+
return filesStore.getRoot(view.id) || null
107+
}
108+
const fileId = pathsStore.getPath(view.id, directory)!
109+
return filesStore.getNode(fileId) || null
76110
}
77111

78112
export const action = new FileAction({
@@ -100,13 +134,25 @@ export const action = new FileAction({
100134
return nodes.every(isDownloadable)
101135
},
102136

103-
async exec(node: Node) {
104-
downloadNodes([node])
137+
async exec(node: Node, view: View, dir: string) {
138+
try {
139+
await downloadNodes([node])
140+
} catch (e) {
141+
showError(t('files', 'The requested file is not available.'))
142+
emit('files:node:deleted', node)
143+
}
105144
return null
106145
},
107146

108-
async execBatch(nodes: Node[]) {
109-
downloadNodes(nodes)
147+
async execBatch(nodes: Node[], view: View, dir: string) {
148+
try {
149+
await downloadNodes(nodes)
150+
} catch (e) {
151+
showError(t('files', 'The requested files are not available.'))
152+
// Try to reload the current directory to update the view
153+
const directory = getCurrentDirectory(view, dir)!
154+
emit('files:node:updated', directory)
155+
}
110156
return new Array(nodes.length).fill(null)
111157
},
112158

0 commit comments

Comments
 (0)