Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/node-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
CYPRESS_INSTALL_BINARY: 0
run: |
npm ci
npx playwright install --with-deps
npm run build --if-present

- name: Test
Expand Down
2 changes: 1 addition & 1 deletion __tests__/start-nextcloud-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export async function setup(project) {
// Start the Nextcloud docker container
const ip = await start()
await waitOnNextcloud(ip)
await configureNextcloud(['end_to_end_encryption'])
await configureNextcloud([])

project.provide('ip', ip)

Expand Down
55 changes: 54 additions & 1 deletion __tests__/uploader/upload.e2e.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('Uploader (current API)', () => {
await expect(client.getFileContents('/files/admin/test-multi/c.txt', { format: 'text' })).resolves.toBe('content-c')
})

it('should upload a folder structure', async () => {
it('should upload a new folder structure', async () => {
const client = getClient()
await client.deleteFile('/files/admin/test-folder').catch(() => {})
await client.createDirectory('/files/admin/test-folder')
Expand All @@ -75,6 +75,59 @@ describe('Uploader (current API)', () => {
})
const uploader = new Uploader(false, folder)

const finishedPromise = new Promise<void>((resolve) => uploader.addEventListener('finished', () => resolve()))
await uploader.batchUpload('', [
fileWithPath('root file', 'root.txt'),
fileWithPath('nested file', 'subdir/nested.txt'),
fileWithPath('deep file', 'subdir/deep/deep.txt'),
])
await finishedPromise

await expect(client.stat('/files/admin/test-folder')).resolves.toEqual(expect.objectContaining({ type: 'directory' }))
await expect(client.getFileContents('/files/admin/test-folder/root.txt', { format: 'text' })).resolves.toBe('root file')
await expect(client.getFileContents('/files/admin/test-folder/subdir/nested.txt', { format: 'text' })).resolves.toBe('nested file')
await expect(client.getFileContents('/files/admin/test-folder/subdir/deep/deep.txt', { format: 'text' })).resolves.toBe('deep file')
})

it('should upload a folder structure into a subfolder', async () => {
const client = getClient()
await client.deleteFile('/files/admin/test-folder').catch(() => {})
await client.createDirectory('/files/admin/test-folder')

const folder = new Folder({
owner: 'admin',
root: '/files/admin',
source: `${defaultRemoteURL}/files/admin/test-folder`,
})
const uploader = new Uploader(false, folder)

const finishedPromise = new Promise<void>((resolve) => uploader.addEventListener('finished', () => resolve()))
await uploader.batchUpload('upload', [
fileWithPath('root file', 'root.txt'),
fileWithPath('nested file', 'subdir/nested.txt'),
fileWithPath('deep file', 'subdir/deep/deep.txt'),
])
await finishedPromise

await expect(client.stat('/files/admin/test-folder/upload')).resolves.toEqual(expect.objectContaining({ type: 'directory' }))
await expect(client.getFileContents('/files/admin/test-folder/upload/root.txt', { format: 'text' })).resolves.toBe('root file')
await expect(client.getFileContents('/files/admin/test-folder/upload/subdir/nested.txt', { format: 'text' })).resolves.toBe('nested file')
await expect(client.getFileContents('/files/admin/test-folder/upload/subdir/deep/deep.txt', { format: 'text' })).resolves.toBe('deep file')
})

it('should upload a folder structure into an existing subfolder', async () => {
const client = getClient()
await client.deleteFile('/files/admin/test-folder').catch(() => {})
await client.createDirectory('/files/admin/test-folder')
await client.createDirectory('/files/admin/test-folder/upload')

const folder = new Folder({
owner: 'admin',
root: '/files/admin',
source: `${defaultRemoteURL}/files/admin/test-folder`,
})
const uploader = new Uploader(false, folder)

const finishedPromise = new Promise<void>((resolve) => uploader.addEventListener('finished', () => resolve()))
await uploader.batchUpload('upload', [
fileWithPath('root file', 'root.txt'),
Expand Down
21 changes: 17 additions & 4 deletions lib/upload/uploader/UploadFileTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,10 +134,7 @@ export class UploadFileTree extends Upload implements IUpload {
this.uploadedBytes = 0

this.status = UploadStatus.UPLOADING
// if this is not the root of a tree, we need to create the directory first before uploading the children
if (this.#directory.webkitRelativePath) {
await this.#createDirectory(queue)
}
await this.#createDirectory(queue)
if (this.needConflictResolution && this.#conflictsCallback) {
const nodes = await this.#conflictsCallback(
this.#directory.children.map((node) => basename(node.name)),
Expand Down Expand Up @@ -193,6 +190,22 @@ export class UploadFileTree extends Upload implements IUpload {
*/
async #createDirectory(queue: PQueue): Promise<void> {
await queue.add(async () => {
try {
await axios.head(this.source, {
signal: this.signal,
headers: {
...this.#customHeaders,
},
})
return // directory already exists, no need to create it
} catch (error) {
if (isRequestAborted(error)) {
this.cancel()
return
}
}

// directory does not exist, we need to create it
try {
await axios.request({
method: 'MKCOL',
Expand Down
Loading