Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: make davRootPath and davRemoteURL support public shares #996

Merged
merged 1 commit into from
Jun 20, 2024
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
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
Loading