mirror of
https://github.com/nextcloud/server.git
synced 2026-03-28 21:33:40 -04:00
fix(files_external): properly handle API errors
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
This commit is contained in:
parent
5f74a4a216
commit
08a7b9d676
6 changed files with 66 additions and 24 deletions
|
|
@ -33,7 +33,7 @@ const open = defineModel<boolean>('open', { default: true })
|
|||
const {
|
||||
storage = { backendOptions: {}, mountOptions: {}, type: isAdmin ? 'system' : 'personal' },
|
||||
} = defineProps<{
|
||||
storage?: Partial<IStorage> & { backendOptions: IStorage['backendOptions'] }
|
||||
storage?: Partial<IStorage>
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
|
|
@ -88,7 +88,7 @@ watch(authMechanisms, () => {
|
|||
:label="t('files_external', 'Folder name')"
|
||||
required />
|
||||
|
||||
<MountOptions v-model="internalStorage.mountOptions" />
|
||||
<MountOptions v-model="internalStorage.mountOptions!" />
|
||||
|
||||
<ApplicableEntities
|
||||
v-if="isAdmin"
|
||||
|
|
@ -112,13 +112,13 @@ watch(authMechanisms, () => {
|
|||
required />
|
||||
|
||||
<BackendConfiguration
|
||||
v-if="backend"
|
||||
v-if="backend && internalStorage.backendOptions"
|
||||
v-model="internalStorage.backendOptions"
|
||||
:class="$style.externalStorageDialog__configuration"
|
||||
:configuration="backend.configuration" />
|
||||
|
||||
<AuthMechanismConfiguration
|
||||
v-if="authMechanism"
|
||||
v-if="authMechanism && internalStorage.backendOptions"
|
||||
v-model="internalStorage.backendOptions"
|
||||
:class="$style.externalStorageDialog__configuration"
|
||||
:authMechanism="authMechanism" />
|
||||
|
|
|
|||
|
|
@ -14,17 +14,14 @@ import NcButton from '@nextcloud/vue/components/NcButton'
|
|||
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'
|
||||
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
|
||||
import NcSelect from '@nextcloud/vue/components/NcSelect'
|
||||
import { parseMountOptions } from '../../store/storages.ts'
|
||||
import { MountOptionsCheckFilesystem } from '../../types.ts'
|
||||
|
||||
const mountOptions = defineModel<Partial<IMountOptions>>({ required: true })
|
||||
watchEffect(() => {
|
||||
if (Object.keys(mountOptions.value).length === 0) {
|
||||
mountOptions.value.encrypt = true
|
||||
mountOptions.value.previews = true
|
||||
mountOptions.value.enable_sharing = false
|
||||
mountOptions.value.filesystem_check_changes = MountOptionsCheckFilesystem.OncePerRequest
|
||||
mountOptions.value.encoding_compatibility = false
|
||||
mountOptions.value.readonly = false
|
||||
// parse and initialize with defaults if needed
|
||||
mountOptions.value = parseMountOptions(mountOptions.value)
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import type { IStorage } from '../types.d.ts'
|
||||
import type { IStorage } from '../types.ts'
|
||||
|
||||
import axios from '@nextcloud/axios'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
|
|
@ -11,6 +11,7 @@ import { addPasswordConfirmationInterceptors, PwdConfirmationMode } from '@nextc
|
|||
import { generateUrl } from '@nextcloud/router'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, toRaw } from 'vue'
|
||||
import { MountOptionsCheckFilesystem } from '../types.ts'
|
||||
|
||||
const { isAdmin } = loadState<{ isAdmin: boolean }>('files_external', 'settings')
|
||||
|
||||
|
|
@ -30,7 +31,7 @@ export const useStorages = defineStore('files_external--storages', () => {
|
|||
toRaw(storage),
|
||||
{ confirmPassword: PwdConfirmationMode.Strict },
|
||||
)
|
||||
globalStorages.value.push(data)
|
||||
globalStorages.value.push(parseStorage(data))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -45,7 +46,7 @@ export const useStorages = defineStore('files_external--storages', () => {
|
|||
toRaw(storage),
|
||||
{ confirmPassword: PwdConfirmationMode.Strict },
|
||||
)
|
||||
userStorages.value.push(data)
|
||||
userStorages.value.push(parseStorage(data))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -77,7 +78,7 @@ export const useStorages = defineStore('files_external--storages', () => {
|
|||
{ confirmPassword: PwdConfirmationMode.Strict },
|
||||
)
|
||||
|
||||
overrideStorage(data)
|
||||
overrideStorage(parseStorage(data))
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -87,7 +88,7 @@ export const useStorages = defineStore('files_external--storages', () => {
|
|||
*/
|
||||
async function reloadStorage(storage: IStorage) {
|
||||
const { data } = await axios.get(getUrl(storage))
|
||||
overrideStorage(data)
|
||||
overrideStorage(parseStorage(data))
|
||||
}
|
||||
|
||||
// initialize the store
|
||||
|
|
@ -111,6 +112,7 @@ export const useStorages = defineStore('files_external--storages', () => {
|
|||
const url = `apps/files_external/${type}`
|
||||
const { data } = await axios.get<Record<number, IStorage>>(generateUrl(url))
|
||||
return Object.values(data)
|
||||
.map(parseStorage)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -150,3 +152,45 @@ export const useStorages = defineStore('files_external--storages', () => {
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* @param storage - The storage from API
|
||||
*/
|
||||
function parseStorage(storage: IStorage) {
|
||||
return {
|
||||
...storage,
|
||||
mountOptions: parseMountOptions(storage.mountOptions),
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the mount options and convert string boolean values to
|
||||
* actual booleans and numeric strings to numbers
|
||||
*
|
||||
* @param options - The mount options to parse
|
||||
*/
|
||||
export function parseMountOptions(options: IStorage['mountOptions']) {
|
||||
const mountOptions = { ...options }
|
||||
mountOptions.encrypt = convertBooleanOptions(mountOptions.encrypt, true)
|
||||
mountOptions.previews = convertBooleanOptions(mountOptions.previews, true)
|
||||
mountOptions.enable_sharing = convertBooleanOptions(mountOptions.enable_sharing, false)
|
||||
mountOptions.filesystem_check_changes = typeof mountOptions.filesystem_check_changes === 'string'
|
||||
? Number.parseInt(mountOptions.filesystem_check_changes)
|
||||
: (mountOptions.filesystem_check_changes ?? MountOptionsCheckFilesystem.OncePerRequest)
|
||||
mountOptions.encoding_compatibility = convertBooleanOptions(mountOptions.encoding_compatibility, false)
|
||||
mountOptions.readonly = convertBooleanOptions(mountOptions.readonly, false)
|
||||
return mountOptions
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert backend encoding of boolean options
|
||||
*
|
||||
* @param option - The option value from API
|
||||
* @param fallback - The fallback (default) value
|
||||
*/
|
||||
function convertBooleanOptions(option: unknown, fallback = false) {
|
||||
if (option === undefined) {
|
||||
return fallback
|
||||
}
|
||||
return option === true || option === 'true' || option === '1'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,8 @@ async function addStorage(storage?: Partial<IStorage>) {
|
|||
}
|
||||
newStorage.value = undefined
|
||||
} catch (error) {
|
||||
logger.error('Failed to add external storage', { error })
|
||||
logger.error('Failed to add external storage', { error, storage })
|
||||
newStorage.value = { ...storage }
|
||||
showDialog.value = true
|
||||
}
|
||||
}
|
||||
|
|
@ -134,8 +135,8 @@ async function addStorage(storage?: Partial<IStorage>) {
|
|||
</NcButton>
|
||||
|
||||
<AddExternalStorageDialog
|
||||
v-model="newStorage"
|
||||
v-model:open="showDialog"
|
||||
:storage="newStorage"
|
||||
@close="addStorage" />
|
||||
|
||||
<UserMountSettings v-if="settings.isAdmin" />
|
||||
|
|
|
|||
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -22,7 +22,7 @@
|
|||
"@nextcloud/initial-state": "^3.0.0",
|
||||
"@nextcloud/l10n": "^3.4.1",
|
||||
"@nextcloud/logger": "^3.0.3",
|
||||
"@nextcloud/password-confirmation": "^6.0.3",
|
||||
"@nextcloud/password-confirmation": "^6.1.0",
|
||||
"@nextcloud/paths": "^3.1.0",
|
||||
"@nextcloud/router": "^3.1.0",
|
||||
"@nextcloud/sharing": "^0.4.0",
|
||||
|
|
@ -2476,9 +2476,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@nextcloud/password-confirmation": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-6.0.3.tgz",
|
||||
"integrity": "sha512-tgbzwfhlXXd9Eq8ZnYrTeH8bEkdyIgybN45Tkip01b3xABUlr0tMGGj8+ZNp2pozytcK+k1l6fyvRPc09g0rIw==",
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@nextcloud/password-confirmation/-/password-confirmation-6.1.0.tgz",
|
||||
"integrity": "sha512-N2ChXDbPcUcQCoAjj1yc65zfc61yiKpdM3qm/y3Y/y//NG7XWNNINwBg85lqJ2SISgmVStpsQ1d0blpFCoQXkQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@nextcloud/auth": "^2.5.3",
|
||||
|
|
@ -2486,8 +2486,8 @@
|
|||
"@nextcloud/l10n": "^3.4.1",
|
||||
"@nextcloud/logger": "^3.0.3",
|
||||
"@nextcloud/router": "^3.1.0",
|
||||
"@nextcloud/vue": "^9.5.0",
|
||||
"vue": "^3.5.29"
|
||||
"@nextcloud/vue": "^9.6.0",
|
||||
"vue": "^3.5.30"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.0.0 || ^22.0.0 || ^24.0.0"
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
"@nextcloud/initial-state": "^3.0.0",
|
||||
"@nextcloud/l10n": "^3.4.1",
|
||||
"@nextcloud/logger": "^3.0.3",
|
||||
"@nextcloud/password-confirmation": "^6.0.3",
|
||||
"@nextcloud/password-confirmation": "^6.1.0",
|
||||
"@nextcloud/paths": "^3.1.0",
|
||||
"@nextcloud/router": "^3.1.0",
|
||||
"@nextcloud/sharing": "^0.4.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue