Skip to content

Commit

Permalink
fix: Make davRootPath and davRemoteURL support public shares
Browse files Browse the repository at this point in the history
Signed-off-by: Ferdinand Thiessen <[email protected]>
  • Loading branch information
susnux committed Jun 20, 2024
1 parent 7731474 commit 790b705
Show file tree
Hide file tree
Showing 8 changed files with 144 additions and 136 deletions.
111 changes: 0 additions & 111 deletions __tests__/dav/dav-public.spec.ts

This file was deleted.

6 changes: 1 addition & 5 deletions __tests__/dav/dav.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* SPDX-FileCopyrightText: 2023-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
import { afterAll, afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
import { readFile } from 'node:fs/promises'

import { File, Folder, davRemoteURL, davGetFavoritesReport, davRootPath, getFavoriteNodes, davResultToNode, NodeStatus } from '../../lib'
Expand All @@ -15,10 +15,6 @@ import { URL as FileURL } from 'node:url'
vi.mock('@nextcloud/auth')
vi.mock('@nextcloud/router')

afterAll(() => {
vi.resetAllMocks()
})

describe('DAV functions', () => {
test('root path is correct', () => {
expect(davRootPath).toBe('/files/test')
Expand Down
102 changes: 102 additions & 0 deletions __tests__/dav/public-shares.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { ArgumentsType } from 'vitest'
import type { FileStat } from 'webdav'
import type { davResultToNode } from '../../lib/dav/dav'
import { beforeEach, describe, expect, test, vi } from 'vitest'

const auth = vi.hoisted(() => ({ getCurrentUser: vi.fn() }))
const router = vi.hoisted(() => ({ generateRemoteUrl: vi.fn() }))
const sharing = vi.hoisted(() => ({ isPublicShare: vi.fn(), getSharingToken: vi.fn() }))

vi.mock('@nextcloud/auth', () => auth)
vi.mock('@nextcloud/router', () => router)
vi.mock('@nextcloud/sharing/public', () => sharing)

const restoreMocks = () => {
vi.resetAllMocks()
router.generateRemoteUrl.mockImplementation((service) => `https://example.com/remote.php/${service}`)
}

const mockPublicShare = () => {
auth.getCurrentUser.mockImplementationOnce(() => null)
sharing.isPublicShare.mockImplementation(() => true)
sharing.getSharingToken.mockImplementation(() => 'token-1234')
}

describe('DAV path functions', () => {

beforeEach(() => {
vi.resetModules()
restoreMocks()
})

test('root path is correct on public shares', async () => {
mockPublicShare()

const { davGetRootPath } = await import('../../lib/dav/dav')
expect(davGetRootPath()).toBe('/files/token-1234')
})

test('remote URL is correct on public shares', async () => {
mockPublicShare()

const { davGetRemoteURL } = await import('../../lib/dav/dav')
expect(davGetRemoteURL()).toBe('https://example.com/public.php/dav')
})
})

describe('on public shares', () => {
beforeEach(() => {
vi.resetAllMocks()
vi.resetModules()
})

// Wrapper function as we can not static import the function to allow mocking the modules
const resultToNode = async (...rest: ArgumentsType<typeof davResultToNode>) => {
const { davResultToNode } = await import('../../lib/dav/dav')
return davResultToNode(...rest)
}

/*
* Result of:
* davGetClient().getDirectoryContents(`${davRootPath}${path}`, { details: true })
*/
const result: FileStat = {
filename: '/files/test/New folder/Neue Textdatei.md',
basename: 'Neue Textdatei.md',
lastmod: 'Tue, 25 Jul 2023 12:29:34 GMT',
size: 123,
type: 'file',
etag: '7a27142de0a62ed27a7293dbc16e93bc',
mime: 'text/markdown',
props: {
resourcetype: { collection: false },
displayname: 'New File',
getcontentlength: '123',
getcontenttype: 'text/markdown',
getetag: '"7a27142de0a62ed27a7293dbc16e93bc"',
getlastmodified: 'Tue, 25 Jul 2023 12:29:34 GMT',
},
}

describe('davResultToNode', () => {
beforeEach(() => {
vi.resetModules()
restoreMocks()
})

test('has correct owner set on public shares', async () => {
mockPublicShare()

const remoteResult = { ...result, filename: '/root/New folder/Neue Textdatei.md' }
const node = await resultToNode(remoteResult, '/root', 'http://example.com/remote.php/dav')

expect(node.isDavRessource).toBe(true)
expect(node.owner).toBe('anonymous')
})
})
})
30 changes: 27 additions & 3 deletions lib/dav/dav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { getCurrentUser, getRequestToken, onRequestTokenUpdate } from '@nextclou
import { generateRemoteUrl } from '@nextcloud/router'
import { CancelablePromise } from 'cancelable-promise'
import { createClient, getPatcher } from 'webdav'
import { isPublicShare } from '../utils/isPublic'
import { getSharingToken, isPublicShare } from '@nextcloud/sharing/public'

/**
* Nextcloud DAV result response
Expand All @@ -29,15 +29,39 @@ interface ResponseProps extends DAVResultResponseProps {
'owner-id': string | number
}

/**
* Get the DAV root path for the current user or public share
*/
export function davGetRootPath(): string {
if (isPublicShare()) {
return `/files/${getSharingToken()}`
}
return `/files/${getCurrentUser()?.uid}`
}

/**
* The DAV root path for the current user
* This is a cached version of `davGetRemoteURL`
*/
export const davRootPath = `/files/${getCurrentUser()?.uid}`
export const davRootPath = davGetRootPath()

/**
* Get the DAV remote URL used as base URL for the WebDAV client
* It also handles public shares
*/
export function davGetRemoteURL(): string {
const url = generateRemoteUrl('dav')
if (isPublicShare()) {
return url.replace('remote.php', 'public.php')
}
return url
}

/**
* The DAV remote URL used as base URL for the WebDAV client
* This is a cached version of `davGetRemoteURL`
*/
export const davRemoteURL = generateRemoteUrl('dav')
export const davRemoteURL = davGetRemoteURL()

/**
* Get a WebDAV client configured to include the Nextcloud request token
Expand Down
1 change: 0 additions & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export { Node, NodeStatus, type INode } from './files/node'

export { isFilenameValid, getUniqueName } from './utils/filename'
export { formatFileSize, parseFileSize } from './utils/fileSize'
export { isPublicShare } from './utils/isPublic'
export { orderBy } from './utils/sorting'
export { sortNodes, FilesSortingMode, type FilesSortingOptions } from './utils/fileSorting'

Expand Down
14 changes: 0 additions & 14 deletions lib/utils/isPublic.ts

This file was deleted.

14 changes: 13 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,11 @@
},
"dependencies": {
"@nextcloud/auth": "^2.3.0",
"@nextcloud/initial-state": "^2.2.0",
"@nextcloud/l10n": "^3.1.0",
"@nextcloud/logger": "^3.0.2",
"@nextcloud/paths": "^2.1.0",
"@nextcloud/router": "^3.0.1",
"@nextcloud/sharing": "^0.2.1",
"cancelable-promise": "^4.3.1",
"is-svg": "^5.0.1",
"typescript-event-target": "^1.1.1",
Expand Down

0 comments on commit 790b705

Please sign in to comment.