4
4
*/
5
5
import type { ContentsWithRoot , Folder , Node } from '@nextcloud/files'
6
6
import type { ComputedRef , Ref } from 'vue'
7
+ import type { FileStat , ResponseDataDetailed , SearchResult } from 'webdav'
7
8
8
- import { davGetClient , davRootPath , getFavoriteNodes } from '@nextcloud/files'
9
- import { CancelablePromise } from 'cancelable-promise'
9
+ import { davGetClient , davGetDefaultPropfind , davGetRecentSearch , davRemoteURL , davResultToNode , davRootPath , getFavoriteNodes } from '@nextcloud/files'
10
+ import { generateRemoteUrl } from '@nextcloud/router'
11
+ import { isPublicShare } from '@nextcloud/sharing/public'
10
12
import { join } from 'node:path'
11
- import { onMounted , ref , shallowRef , watch } from 'vue'
12
- import { getFile , getNodes , getRecentNodes } from '../utils/dav '
13
+ import { computed , onMounted , ref , shallowRef , watch } from 'vue'
14
+ import { CancelablePromise } from 'cancelable-promise '
13
15
14
16
/**
15
17
* Handle file loading using WebDAV
@@ -22,10 +24,76 @@ export const useDAVFiles = function(
22
24
currentPath : Ref < string > | ComputedRef < string > ,
23
25
) {
24
26
27
+ const isPublicEndpoint = isPublicShare ( )
28
+
29
+ const defaultRootPath = isPublicEndpoint ? '/' : davRootPath
30
+
31
+ const defaultRemoteUrl = computed ( ( ) => {
32
+ if ( isPublicEndpoint ) {
33
+ return generateRemoteUrl ( 'webdav' ) . replace ( '/remote.php' , '/public.php' )
34
+ }
35
+ return davRemoteURL
36
+ } )
37
+
25
38
/**
26
39
* The WebDAV client
27
40
*/
28
- const client = davGetClient ( )
41
+ const client = computed ( ( ) => {
42
+ if ( isPublicEndpoint ) {
43
+ const token = ( document . getElementById ( 'sharingToken' ) ! as HTMLInputElement ) . value
44
+ const authorization = btoa ( `${ token } :null` )
45
+
46
+ return davGetClient ( defaultRemoteUrl . value , {
47
+ Authorization : `Basic ${ authorization } ` ,
48
+ } )
49
+ }
50
+
51
+ return davGetClient ( )
52
+ } )
53
+
54
+ const resultToNode = ( result : FileStat ) => davResultToNode ( result , defaultRootPath , defaultRemoteUrl . value )
55
+
56
+ const getRecentNodes = ( ) : CancelablePromise < Node [ ] > => {
57
+ const controller = new AbortController ( )
58
+ // unix timestamp in seconds, two weeks ago
59
+ const lastTwoWeek = Math . round ( Date . now ( ) / 1000 ) - ( 60 * 60 * 24 * 14 )
60
+ return new CancelablePromise ( async ( resolve , reject , onCancel ) => {
61
+ onCancel ( ( ) => controller . abort ( ) )
62
+ try {
63
+ const { data } = await client . value . search ( '/' , {
64
+ signal : controller . signal ,
65
+ details : true ,
66
+ data : davGetRecentSearch ( lastTwoWeek ) ,
67
+ } ) as ResponseDataDetailed < SearchResult >
68
+ const nodes = data . results . map ( resultToNode )
69
+ resolve ( nodes )
70
+ } catch ( error ) {
71
+ reject ( error )
72
+ }
73
+ } )
74
+ }
75
+
76
+ const getNodes = ( ) : CancelablePromise < Node [ ] > => {
77
+ const controller = new AbortController ( )
78
+ return new CancelablePromise ( async ( resolve , reject , onCancel ) => {
79
+ onCancel ( ( ) => controller . abort ( ) )
80
+ try {
81
+ const results = await client . value . getDirectoryContents ( `${ defaultRootPath } ${ currentPath . value } ` , {
82
+ signal : controller . signal ,
83
+ details : true ,
84
+ data : davGetDefaultPropfind ( ) ,
85
+ } ) as ResponseDataDetailed < FileStat [ ] >
86
+ let nodes = results . data . map ( resultToNode )
87
+ // Hack for the public endpoint which always returns folder itself
88
+ if ( isPublicEndpoint ) {
89
+ nodes = nodes . filter ( ( file ) => file . path !== currentPath . value )
90
+ }
91
+ resolve ( nodes )
92
+ } catch ( error ) {
93
+ reject ( error )
94
+ }
95
+ } )
96
+ }
29
97
30
98
/**
31
99
* All files in current view and path
@@ -51,17 +119,33 @@ export const useDAVFiles = function(
51
119
* Create a new directory in the current path
52
120
* The directory will be added to the current file list
53
121
* @param name Name of the new directory
54
- * @return { Promise<Folder> } The created directory
122
+ * @return The created directory
55
123
*/
56
124
async function createDirectory ( name : string ) : Promise < Folder > {
57
125
const path = join ( currentPath . value , name )
58
126
59
- await client . createDirectory ( join ( davRootPath , path ) )
60
- const directory = await getFile ( client , path ) as Folder
127
+ await client . value . createDirectory ( join ( defaultRootPath , path ) )
128
+ const directory = await getFile ( path ) as Folder
61
129
files . value = [ ...files . value , directory ]
62
130
return directory
63
131
}
64
132
133
+ /**
134
+ * Get information for one file
135
+ *
136
+ * @param path The path of the file or folder
137
+ * @param rootPath DAV root path, defaults to '/files/USERID'
138
+ */
139
+ async function getFile ( path : string , rootPath : string | undefined = undefined ) {
140
+ rootPath = rootPath ?? defaultRootPath
141
+
142
+ const { data } = await client . value . stat ( `${ rootPath } ${ path } ` , {
143
+ details : true ,
144
+ data : davGetDefaultPropfind ( ) ,
145
+ } ) as ResponseDataDetailed < FileStat >
146
+ return resultToNode ( data )
147
+ }
148
+
65
149
/**
66
150
* Force reload files using the DAV client
67
151
*/
@@ -72,11 +156,11 @@ export const useDAVFiles = function(
72
156
isLoading . value = true
73
157
74
158
if ( currentView . value === 'favorites' ) {
75
- promise . value = getFavoriteNodes ( client , currentPath . value )
159
+ promise . value = getFavoriteNodes ( client . value , currentPath . value , defaultRootPath )
76
160
} else if ( currentView . value === 'recent' ) {
77
- promise . value = getRecentNodes ( client )
161
+ promise . value = getRecentNodes ( )
78
162
} else {
79
- promise . value = getNodes ( client , currentPath . value )
163
+ promise . value = getNodes ( )
80
164
}
81
165
const content = await promise . value
82
166
if ( 'folder' in content ) {
0 commit comments