refactor: rework async UserEdit

This commit is contained in:
axolotle 2024-08-13 00:33:19 +02:00
parent 1e2a1e2663
commit 66bf3a5560

View file

@ -4,11 +4,9 @@ import { useI18n } from 'vue-i18n'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import api from '@/api' import api from '@/api'
import type ViewBase from '@/components/globals/ViewBase.vue'
import { useDomains, useUsersAndGroups } from '@/composables/data' import { useDomains, useUsersAndGroups } from '@/composables/data'
import { useArrayRule, useForm } from '@/composables/form' import { useArrayRule, useForm } from '@/composables/form'
import { useInitialQueries } from '@/composables/useInitialQueries' import { arrayDiff, getKeys } from '@/helpers/commons'
import { arrayDiff } from '@/helpers/commons'
import { import {
emailForward, emailForward,
emailLocalPart, emailLocalPart,
@ -20,7 +18,8 @@ import {
sameAs, sameAs,
} from '@/helpers/validators' } from '@/helpers/validators'
import { formatAdress, formatForm, sizeToM } from '@/helpers/yunohostArguments' import { formatAdress, formatForm, sizeToM } from '@/helpers/yunohostArguments'
import type { AdressModelValue, FieldProps, FormFieldDict } from '@/types/form' import type { UserDetails } from '@/types/core/data'
import type { FieldProps, FormFieldDict } from '@/types/form'
const props = defineProps<{ const props = defineProps<{
name: string name: string
@ -28,29 +27,30 @@ const props = defineProps<{
const { t } = useI18n() const { t } = useI18n()
const router = useRouter() const router = useRouter()
const { loading } = useInitialQueries( await api.fetchAll([
[ {
{ uri: `users/${props.name}`,
uri: `users/${props.name}`, cachePath: `userDetails.${props.name}`,
cachePath: `userDetails.${props.name}`, },
}, { uri: 'domains', cachePath: 'domains' },
{ uri: 'domains', cachePath: 'domains' }, ])
],
{ onQueriesResponse },
)
const viewElem = ref<InstanceType<typeof ViewBase> | null>(null)
const { domainsAsChoices, mainDomain } = useDomains() const { domainsAsChoices, mainDomain } = useDomains()
const { user } = useUsersAndGroups(() => props.name)
// mailbox-quota could be 'No quota' or 'Pas de quota'...
const mailboxQuota =
parseInt(user.value['mailbox-quota'].limit) > 0
? sizeToM(user.value['mailbox-quota'].limit) ?? 0
: 0
type Form = typeof form.value type Form = typeof form.value
const form = ref({ const form = ref({
username: props.name, username: props.name,
fullname: '', fullname: user.value.fullname,
mail: { localPart: '', separator: '@', domain: '' } as AdressModelValue, mail: formatAdress(user.value.mail),
mailbox_quota: '' as string | number, mailbox_quota: mailboxQuota,
mail_aliases: [] as AdressModelValue[], mail_aliases: user.value['mail-aliases'].map((mail) => formatAdress(mail)),
mail_forward: [] as string[], mail_forward: [...user.value['mail-forward']],
change_password: '', change_password: '',
confirmation: '', confirmation: '',
}) })
@ -74,7 +74,10 @@ const fields = reactive({
mail: reactive({ mail: reactive({
component: 'AdressItem', component: 'AdressItem',
label: t('user_email'), label: t('user_email'),
rules: { localPart: { required, email: emailLocalPart } }, rules: {
localPart: { required, email: emailLocalPart },
domain: { required },
},
cProps: { id: 'mail', choices: domainsAsChoices }, cProps: { id: 'mail', choices: domainsAsChoices },
}) satisfies FieldProps<'AdressItem', Form['mail']>, }) satisfies FieldProps<'AdressItem', Form['mail']>,
@ -88,13 +91,17 @@ const fields = reactive({
cProps: { cProps: {
id: 'mailbox-quota', id: 'mailbox-quota',
placeholder: t('mailbox_quota_placeholder'), placeholder: t('mailbox_quota_placeholder'),
type: 'number',
}, },
} satisfies FieldProps<'InputItem', Form['mailbox_quota']>, } satisfies FieldProps<'InputItem', Form['mailbox_quota']>,
mail_aliases: reactive({ mail_aliases: reactive({
component: 'AdressItem', component: 'AdressItem',
label: t('user_emailaliases'),
id: 'mail_aliases',
rules: useArrayRule(() => form.value.mail_aliases, { rules: useArrayRule(() => form.value.mail_aliases, {
localPart: { required, email: emailLocalPart }, localPart: { required, email: emailLocalPart },
domain: { required },
}), }),
cProps: { cProps: {
placeholder: t('placeholder.username'), placeholder: t('placeholder.username'),
@ -104,6 +111,8 @@ const fields = reactive({
mail_forward: reactive({ mail_forward: reactive({
component: 'InputItem', component: 'InputItem',
label: t('user_emailforward'),
id: 'mail_forward',
rules: useArrayRule(() => form.value.mail_forward, { rules: useArrayRule(() => form.value.mail_forward, {
required, required,
emailForward, emailForward,
@ -145,57 +154,51 @@ const fields = reactive({
const { v, onSubmit } = useForm(form, fields) const { v, onSubmit } = useForm(form, fields)
function onQueriesResponse(user_: any) {
form.value.fullname = user_.fullname
form.value.mail = formatAdress(user_.mail)
if (user_['mail-aliases']) {
form.value.mail_aliases = user_['mail-aliases'].map((mail) =>
formatAdress(mail),
)
}
if (user_['mail-forward']) {
form.value.mail_forward = user_['mail-forward'].map((mail) => ({ mail })) // Copy value
}
// mailbox-quota could be 'No quota' or 'Pas de quota'...
if (parseInt(user_['mailbox-quota'].limit) > 0) {
form.value.mailbox_quota = sizeToM(user_['mailbox-quota'].limit)
} else {
form.value.mailbox_quota = ''
}
}
const onUserEdit = onSubmit(async (onError, serverErrors) => { const onUserEdit = onSubmit(async (onError, serverErrors) => {
const { username: _, ...formData } = await formatForm(form, { const {
username: _,
confirmation: __,
...formData
} = await formatForm(form, {
removeEmpty: true, removeEmpty: true,
}) })
const user_ = useUsersAndGroups(props.name).user.value! const data = {} as Partial<
const data = {} Omit<UserDetails, 'mail-aliases' | 'mail-forward' | 'mailbox-quota'> &
Record<
| 'add_mailalias'
| 'remove_mailalias'
| 'add_mailforward'
| 'remove_mailforward',
string[]
> & { mailbox_quota: string; change_password: string }
>
if (!Object.prototype.hasOwnProperty.call(formData, 'mailbox_quota')) { if (!Object.prototype.hasOwnProperty.call(formData, 'mailbox_quota')) {
formData.mailbox_quota = '' formData.mailbox_quota = 0
} }
// formData.mail_forward = formData.mail_forward?.map((v) => v.mail) for (const key of ['mail_aliases', 'mail_forward'] as const) {
const dashedKey = key.replace('_', '-') as 'mail-aliases' | 'mail-forward'
for (const key of ['mail_aliases', 'mail_forward']) { const newKey = key.replace('_', '').replace('es', '') as
const dashedKey = key.replace('_', '-') | 'mailalias'
const newKey = key.replace('_', '').replace('es', '') | 'mailforward'
const addDiff = arrayDiff(formData[key], user_[dashedKey]) const addDiff = arrayDiff(formData[key], user.value[dashedKey])
const rmDiff = arrayDiff(user_[dashedKey], formData[key]) const rmDiff = arrayDiff(user.value[dashedKey], formData[key])
if (addDiff.length) data['add_' + newKey] = addDiff if (addDiff.length) data[`add_${newKey}`] = addDiff
if (rmDiff.length) data['remove_' + newKey] = rmDiff if (rmDiff.length) data[`remove_${newKey}`] = rmDiff
} }
for (const key in formData) { getKeys(formData).forEach((key) => {
if (key === 'mail_aliases' || key === 'mail_forward') return
if (key === 'mailbox_quota') { if (key === 'mailbox_quota') {
const quota = if (formData[key] !== mailboxQuota) {
parseInt(formData[key]) > 0 ? formData[key] + 'M' : 'No quota' data[key] = formData[key]! > 0 ? formData[key] + 'M' : 'No quota'
if (parseInt(quota) !== parseInt(user_['mailbox-quota'].limit)) {
data[key] = quota === 'No quota' ? '0' : quota
} }
} else if (!key.includes('mail_') && formData[key] !== user_[key]) { } else if (key === 'change_password') {
data.change_password = formData[key]
} else if (formData[key] !== user.value[key]) {
data[key] = formData[key] data[key] = formData[key]
} }
} })
if (Object.keys(data).length === 0) { if (Object.keys(data).length === 0) {
serverErrors.global = [t('error_modify_something')] serverErrors.global = [t('error_modify_something')]
@ -217,7 +220,7 @@ const onUserEdit = onSubmit(async (onError, serverErrors) => {
</script> </script>
<template> <template>
<ViewBase ref="viewElem" :loading="loading" skeleton="CardFormSkeleton"> <div>
<CardForm <CardForm
v-model="form" v-model="form"
icon="user" icon="user"
@ -252,7 +255,7 @@ const onUserEdit = onSubmit(async (onError, serverErrors) => {
/> />
</template> </template>
</CardForm> </CardForm>
</ViewBase> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>