1919 * along with this program. If not, see <http://www.gnu.org/licenses/>.
2020 *
2121 */
22- import type { Node } from '@nextcloud/files'
22+ import type { Folder , Node } from '@nextcloud/files'
2323import type { ComputedRef , Ref } from 'vue'
24- import type { FileStat , ResponseDataDetailed , WebDAVClient } from 'webdav'
24+ import type { FileStat , ResponseDataDetailed , SearchResult } from 'webdav'
2525
26- import { davGetClient , davGetDefaultPropfind , davGetFavoritesReport , davGetRecentSearch , davResultToNode , davRootPath } from '@nextcloud/files'
26+ import { davGetClient , davGetDefaultPropfind , davGetRecentSearch , davRemoteURL , davResultToNode , davRootPath , getFavoriteNodes } from '@nextcloud/files'
2727import { generateRemoteUrl } from '@nextcloud/router'
28- import { ref , watch } from 'vue'
28+ import { dirname , join } from 'path'
29+ import { computed , ref , watch } from 'vue'
2930
3031/**
3132 * Handle file loading using WebDAV
3233 *
3334 * @param currentView Reference to the current files view
3435 * @param currentPath Reference to the current files path
36+ * @param isPublicEndpoint Whether the filepicker is used on a public share
3537 */
36- export const useDAVFiles = function ( currentView : Ref < 'files' | 'recent' | 'favorites' > | ComputedRef < 'files' | 'recent' | 'favorites' > , currentPath : Ref < string > | ComputedRef < string > ) : { isLoading : Ref < boolean > , client : WebDAVClient , files : Ref < Node [ ] > , loadFiles : ( ) => void , getFile : ( path : string ) => Promise < Node > } {
38+ export const useDAVFiles = function (
39+ currentView : Ref < 'files' | 'recent' | 'favorites' > | ComputedRef < 'files' | 'recent' | 'favorites' > ,
40+ currentPath : Ref < string > | ComputedRef < string > ,
41+ isPublicEndpoint : Ref < boolean > | ComputedRef < boolean > ,
42+ ) : { isLoading : Ref < boolean > , createDirectory : ( name : string ) => Promise < Folder > , files : Ref < Node [ ] > , loadFiles : ( ) => Promise < void > , getFile : ( path : string ) => Promise < Node > } {
43+
44+ const defaultRootPath = computed ( ( ) => isPublicEndpoint . value ? '/' : davRootPath )
45+
46+ const defaultRemoteUrl = computed ( ( ) => {
47+ if ( isPublicEndpoint . value ) {
48+ return generateRemoteUrl ( 'webdav' ) . replace ( '/remote.php' , '/public.php' )
49+ }
50+ return davRemoteURL
51+ } )
52+
3753 /**
3854 * The WebDAV client
3955 */
40- const client = davGetClient ( generateRemoteUrl ( 'dav' ) )
56+ const client = computed ( ( ) => {
57+ if ( isPublicEndpoint . value ) {
58+ const token = ( document . getElementById ( 'sharingToken' ) ! as HTMLInputElement ) . value
59+ const autorization = btoa ( `${ token } :null` )
60+
61+ const client = davGetClient ( defaultRemoteUrl . value )
62+ client . setHeaders ( { Authorization : `Basic ${ autorization } ` } )
63+ return client
64+ }
65+
66+ return davGetClient ( )
67+ } )
68+
69+ const resultToNode = ( result : FileStat ) => {
70+ const node = davResultToNode ( result , defaultRootPath . value , defaultRemoteUrl . value )
71+ // Fixed for @nextcloud /files 3.1.0 but not supported on Nextcloud 27 so patching it
72+ if ( isPublicEndpoint . value ) {
73+ return new Proxy ( node , {
74+ get ( node , prop ) {
75+ if ( prop === 'dirname' || prop === 'path' ) {
76+ const source = node . source
77+ let path = source . slice ( defaultRemoteUrl . value . length )
78+ if ( path [ 0 ] !== '/' ) {
79+ path = `/${ path } `
80+ }
81+ if ( prop === 'dirname' ) {
82+ return dirname ( path )
83+ }
84+ return path
85+ }
86+ return ( node as never ) [ prop ]
87+ } ,
88+ } )
89+ }
90+ return node
91+ }
4192
4293 /**
4394 * All queried files
@@ -49,15 +100,32 @@ export const useDAVFiles = function(currentView: Ref<'files'|'recent'|'favorites
49100 */
50101 const isLoading = ref ( true )
51102
103+ /**
104+ * Create a new directory in the current path
105+ * @param name Name of the new directory
106+ * @return {Promise<Folder> } The created directory
107+ */
108+ async function createDirectory ( name : string ) : Promise < Folder > {
109+ const path = join ( currentPath . value , name )
110+
111+ await client . value . createDirectory ( join ( defaultRootPath . value , path ) )
112+ const directory = await getFile ( path ) as Folder
113+ files . value . push ( directory )
114+ return directory
115+ }
116+
52117 /**
53118 * Get information for one file
54119 * @param path The path of the file or folder
120+ * @param rootPath The dav root path to use (or the default is nothing set)
55121 */
56- async function getFile ( path : string ) {
57- const result = await client . stat ( `${ davRootPath } ${ path } ` , {
122+ async function getFile ( path : string , rootPath : string | undefined = undefined ) {
123+ rootPath = rootPath ?? defaultRootPath . value
124+
125+ const { data } = await client . value . stat ( `${ rootPath } ${ path } ` , {
58126 details : true ,
59127 } ) as ResponseDataDetailed < FileStat >
60- return davResultToNode ( result . data )
128+ return resultToNode ( data )
61129 }
62130
63131 /**
@@ -67,34 +135,26 @@ export const useDAVFiles = function(currentView: Ref<'files'|'recent'|'favorites
67135 isLoading . value = true
68136
69137 if ( currentView . value === 'favorites' ) {
70- files . value = await client . getDirectoryContents ( `${ davRootPath } ${ currentPath . value } ` , {
71- details : true ,
72- data : davGetFavoritesReport ( ) ,
73- headers : {
74- method : 'REPORT' ,
75- } ,
76- includeSelf : false ,
77- } ) . then ( ( result ) => ( result as ResponseDataDetailed < FileStat [ ] > ) . data . map ( ( data ) => davResultToNode ( data ) ) )
138+ files . value = await getFavoriteNodes ( client . value , currentPath . value , defaultRootPath . value )
78139 } else if ( currentView . value === 'recent' ) {
79140 // unix timestamp in seconds, two weeks ago
80141 const lastTwoWeek = Math . round ( Date . now ( ) / 1000 ) - ( 60 * 60 * 24 * 14 )
81- const results = await client . getDirectoryContents ( currentPath . value , {
142+ const { data } = await client . value . search ( '/' , {
82143 details : true ,
83144 data : davGetRecentSearch ( lastTwoWeek ) ,
84- headers : {
85- method : 'SEARCH' ,
86- 'Content-Type' : 'application/xml; charset=utf-8' ,
87- } ,
88- deep : true ,
89- } ) as ResponseDataDetailed < FileStat [ ] >
90-
91- files . value = results . data . map ( ( r ) => davResultToNode ( r ) )
145+ } ) as ResponseDataDetailed < SearchResult >
146+ files . value = data . results . map ( resultToNode )
92147 } else {
93- const results = await client . getDirectoryContents ( `${ davRootPath } ${ currentPath . value } ` , {
148+ const results = await client . value . getDirectoryContents ( `${ defaultRootPath . value } ${ currentPath . value } ` , {
94149 details : true ,
95150 data : davGetDefaultPropfind ( ) ,
96151 } ) as ResponseDataDetailed < FileStat [ ] >
97- files . value = results . data . map ( ( r ) => davResultToNode ( r ) )
152+ files . value = results . data . map ( resultToNode )
153+
154+ // Hack for the public endpoint which always returns folder itself
155+ if ( isPublicEndpoint . value ) {
156+ files . value = files . value . filter ( ( file ) => file . path !== currentPath . value )
157+ }
98158 }
99159
100160 isLoading . value = false
@@ -110,6 +170,6 @@ export const useDAVFiles = function(currentView: Ref<'files'|'recent'|'favorites
110170 files,
111171 loadFiles : ( ) => loadDAVFiles ( ) ,
112172 getFile,
113- client ,
173+ createDirectory ,
114174 }
115175}
0 commit comments