You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Recent.ts 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. /**
  2. * @copyright Copyright (c) 2023 John Molakvoæ <skjnldsv@protonmail.com>
  3. *
  4. * @author John Molakvoæ <skjnldsv@protonmail.com>
  5. *
  6. * @license AGPL-3.0-or-later
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as
  10. * published by the Free Software Foundation, either version 3 of the
  11. * License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. import { File, Folder, Permission, davParsePermissions } from '@nextcloud/files'
  23. import { generateRemoteUrl } from '@nextcloud/router'
  24. import { getClient, rootPath } from './WebdavClient'
  25. import { getCurrentUser } from '@nextcloud/auth'
  26. import { getDavNameSpaces, getDavProperties } from './DavProperties'
  27. import type { ContentsWithRoot } from './Navigation'
  28. import type { FileStat, ResponseDataDetailed, DAVResultResponseProps } from 'webdav'
  29. const client = getClient(generateRemoteUrl('dav'))
  30. const lastTwoWeeksTimestamp = Math.round((Date.now() / 1000) - (60 * 60 * 24 * 14))
  31. const searchPayload = `<?xml version="1.0" encoding="UTF-8"?>
  32. <d:searchrequest ${getDavNameSpaces()}
  33. xmlns:ns="https://github.com/icewind1991/SearchDAV/ns">
  34. <d:basicsearch>
  35. <d:select>
  36. <d:prop>
  37. ${getDavProperties()}
  38. </d:prop>
  39. </d:select>
  40. <d:from>
  41. <d:scope>
  42. <d:href>/files/${getCurrentUser()?.uid}/</d:href>
  43. <d:depth>infinity</d:depth>
  44. </d:scope>
  45. </d:from>
  46. <d:where>
  47. <d:and>
  48. <d:or>
  49. <d:not>
  50. <d:eq>
  51. <d:prop>
  52. <d:getcontenttype/>
  53. </d:prop>
  54. <d:literal>httpd/unix-directory</d:literal>
  55. </d:eq>
  56. </d:not>
  57. <d:eq>
  58. <d:prop>
  59. <oc:size/>
  60. </d:prop>
  61. <d:literal>0</d:literal>
  62. </d:eq>
  63. </d:or>
  64. <d:gt>
  65. <d:prop>
  66. <d:getlastmodified/>
  67. </d:prop>
  68. <d:literal>${lastTwoWeeksTimestamp}</d:literal>
  69. </d:gt>
  70. </d:and>
  71. </d:where>
  72. <d:orderby>
  73. <d:order>
  74. <d:prop>
  75. <d:getlastmodified/>
  76. </d:prop>
  77. <d:descending/>
  78. </d:order>
  79. </d:orderby>
  80. <d:limit>
  81. <d:nresults>100</d:nresults>
  82. <ns:firstresult>0</ns:firstresult>
  83. </d:limit>
  84. </d:basicsearch>
  85. </d:searchrequest>`
  86. interface ResponseProps extends DAVResultResponseProps {
  87. permissions: string,
  88. fileid: number,
  89. size: number,
  90. }
  91. const resultToNode = function(node: FileStat): File | Folder {
  92. const props = node.props as ResponseProps
  93. const permissions = davParsePermissions(props?.permissions)
  94. const owner = getCurrentUser()?.uid as string
  95. const nodeData = {
  96. id: props?.fileid as number || 0,
  97. source: generateRemoteUrl('dav' + node.filename),
  98. mtime: new Date(node.lastmod),
  99. mime: node.mime as string,
  100. size: props?.size as number || 0,
  101. permissions,
  102. owner,
  103. root: rootPath,
  104. attributes: {
  105. ...node,
  106. ...props,
  107. hasPreview: props?.['has-preview'],
  108. },
  109. }
  110. delete nodeData.attributes.props
  111. return node.type === 'file'
  112. ? new File(nodeData)
  113. : new Folder(nodeData)
  114. }
  115. export const getContents = async (path = '/'): Promise<ContentsWithRoot> => {
  116. const contentsResponse = await client.getDirectoryContents(path, {
  117. details: true,
  118. data: searchPayload,
  119. headers: {
  120. // Patched in WebdavClient.ts
  121. method: 'SEARCH',
  122. // Somehow it's needed to get the correct response
  123. 'Content-Type': 'application/xml; charset=utf-8',
  124. },
  125. deep: true,
  126. }) as ResponseDataDetailed<FileStat[]>
  127. const contents = contentsResponse.data
  128. return {
  129. folder: new Folder({
  130. id: 0,
  131. source: generateRemoteUrl('dav' + rootPath),
  132. root: rootPath,
  133. owner: getCurrentUser()?.uid || null,
  134. permissions: Permission.READ,
  135. }),
  136. contents: contents.map(resultToNode),
  137. }
  138. }