aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files_external/src/actions/enterCredentialsAction.ts
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files_external/src/actions/enterCredentialsAction.ts')
-rw-r--r--apps/files_external/src/actions/enterCredentialsAction.ts115
1 files changed, 115 insertions, 0 deletions
diff --git a/apps/files_external/src/actions/enterCredentialsAction.ts b/apps/files_external/src/actions/enterCredentialsAction.ts
new file mode 100644
index 00000000000..580f15ad876
--- /dev/null
+++ b/apps/files_external/src/actions/enterCredentialsAction.ts
@@ -0,0 +1,115 @@
+/**
+ * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+// eslint-disable-next-line n/no-extraneous-import
+import type { AxiosResponse } from '@nextcloud/axios'
+import type { Node } from '@nextcloud/files'
+import type { StorageConfig } from '../services/externalStorage'
+
+import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextcloud/password-confirmation'
+import { generateUrl } from '@nextcloud/router'
+import { showError, showSuccess, spawnDialog } from '@nextcloud/dialogs'
+import { translate as t } from '@nextcloud/l10n'
+import axios from '@nextcloud/axios'
+import LoginSvg from '@mdi/svg/svg/login.svg?raw'
+import Vue, { defineAsyncComponent } from 'vue'
+
+import { FileAction, DefaultType } from '@nextcloud/files'
+import { STORAGE_STATUS, isMissingAuthConfig } from '../utils/credentialsUtils'
+import { isNodeExternalStorage } from '../utils/externalStorageUtils'
+
+// Add password confirmation interceptors as
+// the backend requires the user to confirm their password
+addPasswordConfirmationInterceptors(axios)
+
+type CredentialResponse = {
+ login?: string,
+ password?: string,
+}
+
+/**
+ * Set credentials for external storage
+ *
+ * @param node The node for which to set the credentials
+ * @param login The username
+ * @param password The password
+ */
+async function setCredentials(node: Node, login: string, password: string): Promise<null|true> {
+ const configResponse = await axios.request({
+ method: 'PUT',
+ url: generateUrl('apps/files_external/userglobalstorages/{id}', { id: node.attributes.id }),
+ confirmPassword: PwdConfirmationMode.Strict,
+ data: {
+ backendOptions: { user: login, password },
+ },
+ }) as AxiosResponse<StorageConfig>
+
+ const config = configResponse.data
+ if (config.status !== STORAGE_STATUS.SUCCESS) {
+ showError(t('files_external', 'Unable to update this external storage config. {statusMessage}', {
+ statusMessage: config?.statusMessage || '',
+ }))
+ return null
+ }
+
+ // Success update config attribute
+ showSuccess(t('files_external', 'New configuration successfully saved'))
+ Vue.set(node.attributes, 'config', config)
+ return true
+}
+
+export const ACTION_CREDENTIALS_EXTERNAL_STORAGE = 'credentials-external-storage'
+
+export const action = new FileAction({
+ id: ACTION_CREDENTIALS_EXTERNAL_STORAGE,
+ displayName: () => t('files', 'Enter missing credentials'),
+ iconSvgInline: () => LoginSvg,
+
+ enabled: (nodes: Node[]) => {
+ // Only works on single node
+ if (nodes.length !== 1) {
+ return false
+ }
+
+ const node = nodes[0]
+ if (!isNodeExternalStorage(node)) {
+ return false
+ }
+
+ const config = (node.attributes?.config || {}) as StorageConfig
+ if (isMissingAuthConfig(config)) {
+ return true
+ }
+
+ return false
+ },
+
+ async exec(node: Node) {
+ const { login, password } = await new Promise<CredentialResponse>(resolve => spawnDialog(
+ defineAsyncComponent(() => import('../views/CredentialsDialog.vue')),
+ {},
+ (args) => {
+ resolve(args as CredentialResponse)
+ },
+ ))
+
+ if (login && password) {
+ try {
+ await setCredentials(node, login, password)
+ showSuccess(t('files_external', 'Credentials successfully set'))
+ } catch (error) {
+ showError(t('files_external', 'Error while setting credentials: {error}', {
+ error: (error as Error).message,
+ }))
+ }
+ }
+
+ return null
+ },
+
+ // Before openFolderAction
+ order: -1000,
+ default: DefaultType.DEFAULT,
+ inline: () => true,
+})