]> source.dussan.org Git - nextcloud-server.git/commitdiff
fix(files_external): broken credentials dialog
authorJohn Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
Fri, 13 Sep 2024 11:57:30 +0000 (13:57 +0200)
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>
Fri, 13 Sep 2024 15:20:43 +0000 (15:20 +0000)
Signed-off-by: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
[skip ci]

apps/files_external/appinfo/routes.php
apps/files_external/src/actions/enterCredentialsAction.ts
apps/files_external/src/views/CredentialsDialog.vue [new file with mode: 0644]

index 996c6aba0dcc4263651f284e0a2886dc89a908ab..df0a9922dd7d6e8cb7596881d3bd8c00806d080a 100644 (file)
@@ -62,10 +62,5 @@ return [
                        'url' => '/api/v1/mounts',
                        'verb' => 'GET',
                ],
-               [
-                       'name' => 'Api#askNativeAuth',
-                       'url' => '/api/v1/auth',
-                       'verb' => 'GET',
-               ],
        ],
 ];
index 162a359f48866ec7c1c779da275ec554b383013a..42055b00e9024348e0168f2e3a2c81b68133edd1 100644 (file)
@@ -24,29 +24,39 @@ import type { AxiosResponse } from 'axios'
 import type { Node } from '@nextcloud/files'
 import type { StorageConfig } from '../services/externalStorage'
 
-import { generateOcsUrl, generateUrl } from '@nextcloud/router'
-import { showError, showSuccess } from '@nextcloud/dialogs'
+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 from 'vue'
+import Vue, { defineAsyncComponent } from 'vue'
 
 import { FileAction, DefaultType } from '@nextcloud/files'
 import { STORAGE_STATUS, isMissingAuthConfig } from '../utils/credentialsUtils'
 import { isNodeExternalStorage } from '../utils/externalStorageUtils'
 
-type OCSAuthResponse = {
-       ocs: {
-               meta: {
-                       status: string
-                       statuscode: number
-                       message: string
-               },
-               data: {
-                       user?: string,
-                       password?: string,
-               }
+type CredentialResponse = {
+       login?: string,
+       password?: string,
+}
+
+async function setCredentials(node: Node, login: string, password: string): Promise<null|true> {
+       const configResponse = await axios.put(generateUrl('apps/files_external/userglobalstorages/{id}', node.attributes), {
+               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 = new FileAction({
@@ -74,30 +84,16 @@ export const action = new FileAction({
        },
 
        async exec(node: Node) {
-               // always resolve auth request, we'll process the data afterwards
-               // Using fetch as axios have integrated auth handling and X-Requested-With header
-               const response = await fetch(generateOcsUrl('/apps/files_external/api/v1/auth'), {
-                       headers: new Headers({ Accept: 'application/json' }),
-                       credentials: 'include',
-               })
-
-               const data = (await response?.json() || {}) as OCSAuthResponse
-               if (data.ocs.data.user && data.ocs.data.password) {
-                       const configResponse = await axios.put(generateUrl('apps/files_external/userglobalstorages/{id}', node.attributes), {
-                               backendOptions: data.ocs.data,
-                       }) 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
-                       }
+               const { login, password } = await new Promise<CredentialResponse>(resolve => spawnDialog(
+                       defineAsyncComponent(() => import('../views/CredentialsDialog.vue')),
+                       {},
+                       (args) => {
+                               resolve(args as CredentialResponse)
+                       },
+               ))
 
-                       // Success update config attribute
-                       showSuccess(t('files_external', 'New configuration successfully saved'))
-                       Vue.set(node.attributes, 'config', config)
+               if (login && password) {
+                       return await setCredentials(node, login, password)
                }
 
                return null
diff --git a/apps/files_external/src/views/CredentialsDialog.vue b/apps/files_external/src/views/CredentialsDialog.vue
new file mode 100644 (file)
index 0000000..c9a9539
--- /dev/null
@@ -0,0 +1,86 @@
+<!--
+  - SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
+  - SPDX-License-Identifier: AGPL-3.0-or-later
+-->
+
+<template>
+       <NcDialog :buttons="dialogButtons"
+               class="external-storage-auth"
+               close-on-click-outside
+               data-cy-external-storage-auth
+               is-form
+               :name="t('files_external', 'Storage credentials')"
+               out-transition
+               @submit="$emit('close', {login, password})"
+               @update:open="$emit('close')">
+               <!-- Header -->
+               <NcNoteCard class="external-storage-auth__header"
+                       :text="t('files_external', 'To access the storage, you need to provide the authentification informations.')"
+                       type="info" />
+
+               <!-- Login -->
+               <NcTextField ref="login"
+                       class="external-storage-auth__login"
+                       data-cy-external-storage-auth-dialog-login
+                       :label="t('files_external', 'Login')"
+                       :placeholder="t('files_external', 'Enter the storage login')"
+                       minlength="2"
+                       name="login"
+                       required
+                       :value.sync="login" />
+
+               <!-- Password -->
+               <NcPasswordField ref="password"
+                       class="external-storage-auth__password"
+                       data-cy-external-storage-auth-dialog-password
+                       :label="t('files_external', 'Password')"
+                       :placeholder="t('files_external', 'Enter the storage password')"
+                       name="password"
+                       required
+                       :value.sync="password" />
+       </NcDialog>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue'
+import { t } from '@nextcloud/l10n'
+
+import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'
+import NcNoteCard from '@nextcloud/vue/dist/Components/NcNoteCard.js'
+import NcPasswordField from '@nextcloud/vue/dist/Components/NcPasswordField.js'
+import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
+
+export default defineComponent({
+       name: 'CredentialsDialog',
+
+       components: {
+               NcDialog,
+               NcNoteCard,
+               NcTextField,
+               NcPasswordField,
+       },
+
+       setup() {
+               return {
+                       t,
+               }
+       },
+
+       data() {
+               return {
+                       login: '',
+                       password: '',
+               }
+       },
+
+       computed: {
+               dialogButtons() {
+                       return [{
+                               label: t('files_external', 'Submit'),
+                               type: 'primary',
+                               nativeType: 'submit',
+                       }]
+               },
+       },
+})
+</script>