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!: Revert breaking changes in DAV endpoint handling #1419

Merged
merged 2 commits into from
Aug 16, 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
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@

All notable changes to this project will be documented in this file.

## 5.3.6
[Full Changelog](https://github.com/nextcloud-libraries/nextcloud-dialogs/compare/v5.3.5...v5.3.6)

### Breaking

In v5.3.3 breaking changes were introduced as it dropped support for Nextcloud 28 and older on public shares.
This reverts the changes to the DAV handling, for Nextcloud 29+ please use the now released version v6.0.0+.

### Changed
* chore: Enhance docs about generic dialogs and export all related types [\#1380](https://github.com/nextcloud-libraries/nextcloud-dialogs/pull/1380) \([susnux](https://github.com/susnux)\)
* Migrate REUSE to TOML format [\#1386](https://github.com/nextcloud-libraries/nextcloud-dialogs/pull/1386) \([AndyScherzinger](https://github.com/AndyScherzinger)\)
* chore(deps): Bump @nextcloud/typings to 1.9.1
* chore(deps): Bump @nextcloud/sharing to 0.2.3
* chore(deps): Bump fast-xml-parser to 4.4.1
* chore(deps): Bump @nextcloud/files to 3.8.0
* chore(deps): Bump @vueuse/core to 10.11.1
* chore(deps): Bump webdav to 5.7.1
* chore(deps): Bump axios to 1.7.4

## 5.3.5
[Full Changelog](https://github.com/nextcloud-libraries/nextcloud-dialogs/compare/v5.3.4...v5.3.5)

Expand Down
6 changes: 1 addition & 5 deletions lib/composables/dav.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const waitRefLoaded = (isLoading: Ref<boolean>) => new Promise((resolve) => {
})

const TestComponent = defineComponent({
props: ['currentView', 'currentPath', 'isPublic'],
props: ['currentView', 'currentPath'],
setup(props) {
const dav = useDAVFiles(toRef(props, 'currentView'), toRef(props, 'currentPath'))
return {
Expand All @@ -60,7 +60,6 @@ describe('dav composable', () => {
propsData: {
currentView: 'files',
currentPath: '/',
isPublic: false,
},
})
// Loading is set to true
Expand All @@ -85,7 +84,6 @@ describe('dav composable', () => {
propsData: {
currentView: 'files',
currentPath: '/',
isPublic: false,
},
})

Expand All @@ -105,7 +103,6 @@ describe('dav composable', () => {
propsData: {
currentView: 'files',
currentPath: '/',
isPublic: false,
},
})

Expand Down Expand Up @@ -133,7 +130,6 @@ describe('dav composable', () => {
propsData: {
currentView: 'files',
currentPath: '/',
isPublic: false,
},
})

Expand Down
106 changes: 95 additions & 11 deletions lib/composables/dav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
*/
import type { ContentsWithRoot, Folder, Node } from '@nextcloud/files'
import type { ComputedRef, Ref } from 'vue'
import type { FileStat, ResponseDataDetailed, SearchResult } from 'webdav'

import { davGetClient, davRootPath, getFavoriteNodes } from '@nextcloud/files'
import { CancelablePromise } from 'cancelable-promise'
import { davGetClient, davGetDefaultPropfind, davGetRecentSearch, davRemoteURL, davResultToNode, davRootPath, getFavoriteNodes } from '@nextcloud/files'
import { generateRemoteUrl } from '@nextcloud/router'
import { isPublicShare } from '@nextcloud/sharing/public'
import { join } from 'node:path'
import { onMounted, ref, shallowRef, watch } from 'vue'
import { getFile, getNodes, getRecentNodes } from '../utils/dav'
import { computed, onMounted, ref, shallowRef, watch } from 'vue'
import { CancelablePromise } from 'cancelable-promise'

/**
* Handle file loading using WebDAV
Expand All @@ -22,10 +24,76 @@ export const useDAVFiles = function(
currentPath: Ref<string> | ComputedRef<string>,
) {

const isPublicEndpoint = isPublicShare()

const defaultRootPath = isPublicEndpoint ? '/' : davRootPath

const defaultRemoteUrl = computed(() => {
if (isPublicEndpoint) {
return generateRemoteUrl('webdav').replace('/remote.php', '/public.php')
}
return davRemoteURL
})

/**
* The WebDAV client
*/
const client = davGetClient()
const client = computed(() => {
if (isPublicEndpoint) {
const token = (document.getElementById('sharingToken')! as HTMLInputElement).value
const authorization = btoa(`${token}:null`)

return davGetClient(defaultRemoteUrl.value, {
Authorization: `Basic ${authorization}`,
})
}

return davGetClient()
})

const resultToNode = (result: FileStat) => davResultToNode(result, defaultRootPath, defaultRemoteUrl.value)

const getRecentNodes = (): CancelablePromise<Node[]> => {
const controller = new AbortController()
// unix timestamp in seconds, two weeks ago
const lastTwoWeek = Math.round(Date.now() / 1000) - (60 * 60 * 24 * 14)
return new CancelablePromise(async (resolve, reject, onCancel) => {
onCancel(() => controller.abort())
try {
const { data } = await client.value.search('/', {
signal: controller.signal,
details: true,
data: davGetRecentSearch(lastTwoWeek),
}) as ResponseDataDetailed<SearchResult>
const nodes = data.results.map(resultToNode)
resolve(nodes)
} catch (error) {
reject(error)
}
})
}

const getNodes = (): CancelablePromise<Node[]> => {
const controller = new AbortController()
return new CancelablePromise(async (resolve, reject, onCancel) => {
onCancel(() => controller.abort())
try {
const results = await client.value.getDirectoryContents(`${defaultRootPath}${currentPath.value}`, {
signal: controller.signal,
details: true,
data: davGetDefaultPropfind(),
}) as ResponseDataDetailed<FileStat[]>
let nodes = results.data.map(resultToNode)
// Hack for the public endpoint which always returns folder itself
if (isPublicEndpoint) {
nodes = nodes.filter((file) => file.path !== currentPath.value)
}
resolve(nodes)
} catch (error) {
reject(error)
}
})
}

/**
* All files in current view and path
Expand All @@ -51,17 +119,33 @@ export const useDAVFiles = function(
* Create a new directory in the current path
* The directory will be added to the current file list
* @param name Name of the new directory
* @return {Promise<Folder>} The created directory
* @return The created directory
*/
async function createDirectory(name: string): Promise<Folder> {
const path = join(currentPath.value, name)

await client.createDirectory(join(davRootPath, path))
const directory = await getFile(client, path) as Folder
await client.value.createDirectory(join(defaultRootPath, path))
const directory = await getFile(path) as Folder
files.value = [...files.value, directory]
return directory
}

/**
* Get information for one file
*
* @param path The path of the file or folder
* @param rootPath DAV root path, defaults to '/files/USERID'
*/
async function getFile(path: string, rootPath: string|undefined = undefined) {
rootPath = rootPath ?? defaultRootPath

const { data } = await client.value.stat(`${rootPath}${path}`, {
details: true,
data: davGetDefaultPropfind(),
}) as ResponseDataDetailed<FileStat>
return resultToNode(data)
}

/**
* Force reload files using the DAV client
*/
Expand All @@ -72,11 +156,11 @@ export const useDAVFiles = function(
isLoading.value = true

if (currentView.value === 'favorites') {
promise.value = getFavoriteNodes(client, currentPath.value)
promise.value = getFavoriteNodes(client.value, currentPath.value, defaultRootPath)
} else if (currentView.value === 'recent') {
promise.value = getRecentNodes(client)
promise.value = getRecentNodes()
} else {
promise.value = getNodes(client, currentPath.value)
promise.value = getNodes()
}
const content = await promise.value
if ('folder' in content) {
Expand Down
4 changes: 2 additions & 2 deletions lib/composables/filesSettings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import { useFilesSettings } from './filesSettings'
const axios = vi.hoisted(() => ({
get: vi.fn(),
}))
const isPublic = vi.hoisted(() => ({ value: false }))
const nextcloudSharing = vi.hoisted(() => ({ isPublicShare: vi.fn(() => false) }))

vi.mock('@nextcloud/axios', () => ({ default: axios }))
vi.mock('./isPublic', () => ({ useIsPublic: () => ({ isPublic }) }))
vi.mock('@nextcloud/sharing/public', () => nextcloudSharing)

const TestComponent = defineComponent({
setup() {
Expand Down
2 changes: 1 addition & 1 deletion lib/toast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ export function showUndo(text: string, onUndo: (e: MouseEvent) => void, options?
// force 10 seconds of timeout
timeout: TOAST_UNDO_TIMEOUT,
// remove close button
close: false
close: false,
})

// Generate undo layout
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/dav.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,4 @@ describe('DAV utils', () => {
expect(client.stat).toBeCalledWith(`${nextcloudFiles.davRootPath}/some/path/file.ext`, { details: true, data: 'propfind content' })
expect(nextcloudFiles.davResultToNode).toBeCalledWith({ path: `${nextcloudFiles.davRootPath}/some/path/file.ext` })
})
})
})
1 change: 1 addition & 0 deletions lib/utils/dialogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Vue, { toRaw } from 'vue'
* @param props Properties to pass to the dialog
* @param onClose Callback when the dialog is closed
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const spawnDialog = (dialog: Component | AsyncComponent, props: any, onClose: (...rest: unknown[]) => void = () => {}): Vue => {
const el = document.createElement('div')

Expand Down
4 changes: 2 additions & 2 deletions 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
@@ -1,6 +1,6 @@
{
"name": "@nextcloud/dialogs",
"version": "5.3.5",
"version": "5.3.6",
"description": "Nextcloud dialog helpers",
"types": "dist/index.d.ts",
"main": "dist/index.cjs",
Expand Down
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
"lib": ["DOM", "ESNext"],
"outDir": "./dist",
"rootDir": "lib/",
"module": "ESNext",
"moduleResolution": "Bundler",
"target": "ESNext",
"sourceMap": true,
"plugins": [
{ "name": "typescript-plugin-css-modules" }
Expand Down
Loading