enterCredentialsAction.ts 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /**
  2. * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
  3. * SPDX-License-Identifier: AGPL-3.0-or-later
  4. */
  5. // eslint-disable-next-line n/no-extraneous-import
  6. import type { AxiosResponse } from '@nextcloud/axios'
  7. import type { Node } from '@nextcloud/files'
  8. import type { StorageConfig } from '../services/externalStorage'
  9. import { generateOcsUrl, generateUrl } from '@nextcloud/router'
  10. import { showError, showSuccess } from '@nextcloud/dialogs'
  11. import { translate as t } from '@nextcloud/l10n'
  12. import axios from '@nextcloud/axios'
  13. import LoginSvg from '@mdi/svg/svg/login.svg?raw'
  14. import Vue from 'vue'
  15. import { FileAction, DefaultType } from '@nextcloud/files'
  16. import { STORAGE_STATUS, isMissingAuthConfig } from '../utils/credentialsUtils'
  17. import { isNodeExternalStorage } from '../utils/externalStorageUtils'
  18. type OCSAuthResponse = {
  19. ocs: {
  20. meta: {
  21. status: string
  22. statuscode: number
  23. message: string
  24. },
  25. data: {
  26. user?: string,
  27. password?: string,
  28. }
  29. }
  30. }
  31. export const action = new FileAction({
  32. id: 'credentials-external-storage',
  33. displayName: () => t('files', 'Enter missing credentials'),
  34. iconSvgInline: () => LoginSvg,
  35. enabled: (nodes: Node[]) => {
  36. // Only works on single node
  37. if (nodes.length !== 1) {
  38. return false
  39. }
  40. const node = nodes[0]
  41. if (!isNodeExternalStorage(node)) {
  42. return false
  43. }
  44. const config = (node.attributes?.config || {}) as StorageConfig
  45. if (isMissingAuthConfig(config)) {
  46. return true
  47. }
  48. return false
  49. },
  50. async exec(node: Node) {
  51. // always resolve auth request, we'll process the data afterwards
  52. // Using fetch as axios have integrated auth handling and X-Requested-With header
  53. const response = await fetch(generateOcsUrl('/apps/files_external/api/v1/auth'), {
  54. headers: new Headers({ Accept: 'application/json' }),
  55. credentials: 'include',
  56. })
  57. const data = (await response?.json() || {}) as OCSAuthResponse
  58. if (data.ocs.data.user && data.ocs.data.password) {
  59. const configResponse = await axios.put(generateUrl('apps/files_external/userglobalstorages/{id}', node.attributes), {
  60. backendOptions: data.ocs.data,
  61. }) as AxiosResponse<StorageConfig>
  62. const config = configResponse.data
  63. if (config.status !== STORAGE_STATUS.SUCCESS) {
  64. showError(t('files_external', 'Unable to update this external storage config. {statusMessage}', {
  65. statusMessage: config?.statusMessage || '',
  66. }))
  67. return null
  68. }
  69. // Success update config attribute
  70. showSuccess(t('files_external', 'New configuration successfully saved'))
  71. Vue.set(node.attributes, 'config', config)
  72. }
  73. return null
  74. },
  75. // Before openFolderAction
  76. order: -1000,
  77. default: DefaultType.DEFAULT,
  78. inline: () => true,
  79. })