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.

Files.ts 2.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  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 type { ContentsWithRoot } from './Navigation'
  23. import type { FileStat, ResponseDataDetailed, DAVResultResponseProps } from 'webdav'
  24. import { File, Folder, davParsePermissions } from '@nextcloud/files'
  25. import { generateRemoteUrl } from '@nextcloud/router'
  26. import { getCurrentUser } from '@nextcloud/auth'
  27. import { getClient, rootPath } from './WebdavClient'
  28. import { getDefaultPropfind } from './DavProperties'
  29. import { hashCode } from '../utils/hashUtils'
  30. import logger from '../logger'
  31. const client = getClient()
  32. interface ResponseProps extends DAVResultResponseProps {
  33. permissions: string,
  34. fileid: number,
  35. size: number,
  36. }
  37. const resultToNode = function(node: FileStat): File | Folder {
  38. const props = node.props as ResponseProps
  39. const permissions = davParsePermissions(props?.permissions)
  40. const owner = getCurrentUser()?.uid as string
  41. const source = generateRemoteUrl('dav' + rootPath + node.filename)
  42. const id = props?.fileid < 0
  43. ? hashCode(source)
  44. : props?.fileid as number || 0
  45. const nodeData = {
  46. id,
  47. source,
  48. mtime: new Date(node.lastmod),
  49. mime: node.mime as string,
  50. size: props?.size as number || 0,
  51. permissions,
  52. owner,
  53. root: rootPath,
  54. attributes: {
  55. ...node,
  56. ...props,
  57. hasPreview: props?.['has-preview'],
  58. failed: props?.fileid < 0,
  59. },
  60. }
  61. delete nodeData.attributes.props
  62. return node.type === 'file'
  63. ? new File(nodeData)
  64. : new Folder(nodeData)
  65. }
  66. export const getContents = async (path = '/'): Promise<ContentsWithRoot> => {
  67. const propfindPayload = getDefaultPropfind()
  68. const contentsResponse = await client.getDirectoryContents(path, {
  69. details: true,
  70. data: propfindPayload,
  71. includeSelf: true,
  72. }) as ResponseDataDetailed<FileStat[]>
  73. const root = contentsResponse.data[0]
  74. const contents = contentsResponse.data.slice(1)
  75. if (root.filename !== path) {
  76. throw new Error('Root node does not match requested path')
  77. }
  78. return {
  79. folder: resultToNode(root) as Folder,
  80. contents: contents.map(result => {
  81. try {
  82. return resultToNode(result)
  83. } catch (error) {
  84. logger.error(`Invalid node detected '${result.basename}'`, { error })
  85. return null
  86. }
  87. }).filter(Boolean) as File[],
  88. }
  89. }