mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
update UserCreate with new helpers
This commit is contained in:
parent
f2d980594a
commit
8dfae8835d
2 changed files with 184 additions and 199 deletions
|
@ -143,19 +143,28 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
usersAsOptions: state => {
|
users: state => state.users,
|
||||||
const choices = Object.values(state.users).map(({ username, fullname, mail }) => {
|
|
||||||
return { text: `${fullname} (${mail})`, value: username }
|
userNames: state => {
|
||||||
})
|
if (state.users !== undefined) return Object.keys(state.users)
|
||||||
return { choices, value: choices[0].value }
|
return undefined
|
||||||
},
|
},
|
||||||
|
|
||||||
domainsAsOptions: state => {
|
usersAsChoices: state => {
|
||||||
|
return Object.values(state.users).map(({ username, fullname, mail }) => {
|
||||||
|
return { text: `${fullname} (${mail})`, value: username }
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
domains: state => state.domains,
|
||||||
|
|
||||||
|
mainDomain: state => state.main_domain,
|
||||||
|
|
||||||
|
domainsAsChoices: state => {
|
||||||
const mainDomain = state.main_domain
|
const mainDomain = state.main_domain
|
||||||
const choices = state.domains.map(domain => {
|
return state.domains.map(domain => {
|
||||||
return { value: domain, text: domain === mainDomain ? domain + ' ★' : domain }
|
return { value: domain, text: domain === mainDomain ? domain + ' ★' : domain }
|
||||||
})
|
})
|
||||||
return { choices, value: mainDomain }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,251 +1,227 @@
|
||||||
<template lang="html">
|
<template>
|
||||||
<basic-form :header="$t('users_new')" @submit.prevent="onSubmit">
|
<basic-form
|
||||||
<!-- USER NAME -->
|
:title="$t('users_new')" icon="user"
|
||||||
<b-form-group
|
:validation="$v" :server-error="serverError"
|
||||||
label-cols-md="4" label-cols-lg="2"
|
@submit.prevent="onSubmit"
|
||||||
:label="$t('user_username')" label-for="input-username"
|
|
||||||
>
|
>
|
||||||
<b-input
|
<!-- USER NAME -->
|
||||||
id="input-username" :placeholder="$t('placeholder.username')"
|
<form-field v-bind="fields.username" v-model="form.username" :validation="$v.form.username" />
|
||||||
aria-describedby="username-feedback" required
|
|
||||||
v-model="form.username" :state="isValid.username"
|
|
||||||
@input="validateUsername" @blur="populateEmail"
|
|
||||||
/>
|
|
||||||
<b-form-invalid-feedback id="username-feedback" :state="isValid.username">
|
|
||||||
{{ this.error.username }}
|
|
||||||
</b-form-invalid-feedback>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<!-- USER FULLNAME -->
|
<!-- USER FULLNAME -->
|
||||||
<b-form-group label-cols-md="4" label-cols-lg="2">
|
<form-field
|
||||||
<template v-slot:label aria-hidden="true">
|
v-bind="fields.fullname" :validation="$v.form.fullname"
|
||||||
{{ $t('user_fullname') }}
|
>
|
||||||
|
<template #default="{ self }">
|
||||||
|
<b-input-group>
|
||||||
|
<template v-for="fname in ['firstname', 'lastname']">
|
||||||
|
<b-input-group-prepend :key="fname + 'prepend'">
|
||||||
|
<b-input-group-text :id="fname + '-label'" tag="label">
|
||||||
|
{{ self[fname].label }}
|
||||||
|
</b-input-group-text>
|
||||||
|
</b-input-group-prepend>
|
||||||
|
|
||||||
|
<input-item
|
||||||
|
v-bind="self[fname]" v-model="form.fullname[fname]" :key="fname + 'input'"
|
||||||
|
:name="self[fname].id" :aria-labelledby="fname + '-label'"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div class="input-double">
|
|
||||||
<b-input-group>
|
|
||||||
<b-input-group-prepend
|
|
||||||
tag="label" class="ssr-only" is-text
|
|
||||||
for="input-firstname"
|
|
||||||
>
|
|
||||||
{{ $t('common.firstname') }}
|
|
||||||
</b-input-group-prepend>
|
|
||||||
|
|
||||||
<b-input
|
|
||||||
id="input-firstname" :placeholder="$t('placeholder.firstname')"
|
|
||||||
v-model="form.firstname" required
|
|
||||||
/>
|
|
||||||
</b-input-group>
|
</b-input-group>
|
||||||
|
</template>
|
||||||
<b-input-group>
|
</form-field>
|
||||||
<b-input-group-prepend
|
<hr>
|
||||||
tag="label" class="ssr-only" is-text
|
|
||||||
for="input-lastname"
|
|
||||||
>
|
|
||||||
{{ $t('common.lastname') }}
|
|
||||||
</b-input-group-prepend>
|
|
||||||
|
|
||||||
<b-input
|
|
||||||
id="input-firstname" :placeholder="$t('placeholder.lastname')"
|
|
||||||
v-model="form.lastname" required
|
|
||||||
/>
|
|
||||||
</b-input-group>
|
|
||||||
</div>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<!-- USER EMAIL -->
|
<!-- USER EMAIL -->
|
||||||
<b-form-group
|
<form-field v-bind="fields.domain" :validation="$v.form.domain">
|
||||||
label-cols-md="4" label-cols-lg="2"
|
<template #default="{ self }">
|
||||||
:label="$t('user_email')" label-for="input-email"
|
<b-input-group>
|
||||||
>
|
<b-input-group-append>
|
||||||
<adress-input-select
|
<b-input-group-text id="local-part" tag="label" class="border-right-0">
|
||||||
id="input-email" feedback-id="email-feedback"
|
{{ form.username }}@
|
||||||
v-model="form.mail" :options="domains"
|
</b-input-group-text>
|
||||||
:state="isValid.mail" @input="validateEmail"
|
</b-input-group-append>
|
||||||
/>
|
|
||||||
|
|
||||||
<b-form-invalid-feedback id="email-feedback" :state="isValid.mail">
|
<select-item
|
||||||
{{ this.error.mail }}
|
aria-labelledby="local-part" aria-describedby="mail__BV_description_"
|
||||||
</b-form-invalid-feedback>
|
v-model="form.domain" v-bind="self"
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<!-- MAILBOX QUOTA -->
|
|
||||||
<b-form-group
|
|
||||||
label-cols-md="4" label-cols-lg="2"
|
|
||||||
:label="$t('user_mailbox_quota')" label-for="input-mailbox-quota"
|
|
||||||
:description="$t('mailbox_quota_description')"
|
|
||||||
>
|
|
||||||
<b-input-group append="M">
|
|
||||||
<b-input
|
|
||||||
id="input-mailbox-quota" :placeholder="$t('mailbox_quota_placeholder')"
|
|
||||||
v-model="form.mailbox_quota" type="number" min="0"
|
|
||||||
/>
|
/>
|
||||||
</b-input-group>
|
</b-input-group>
|
||||||
</b-form-group>
|
</template>
|
||||||
|
</form-field>
|
||||||
|
|
||||||
|
<!-- MAILBOX QUOTA -->
|
||||||
|
<form-field v-bind="fields.mailbox_quota" :validation="$v.form.mailbox_quota">
|
||||||
|
<template #default="{ self }">
|
||||||
|
<b-input-group append="M">
|
||||||
|
<input-item v-bind="self" v-model="form.mailbox_quota" />
|
||||||
|
</b-input-group>
|
||||||
|
</template>
|
||||||
|
</form-field>
|
||||||
|
<hr>
|
||||||
|
|
||||||
<!-- USER PASSWORD -->
|
<!-- USER PASSWORD -->
|
||||||
<b-form-group
|
<form-field v-bind="fields.password" v-model="form.password" :validation="$v.form.password" />
|
||||||
label-cols-md="4" label-cols-lg="2"
|
|
||||||
:label="$t('password')" label-for="input-password"
|
|
||||||
>
|
|
||||||
<b-input
|
|
||||||
id="input-password" placeholder="••••••••"
|
|
||||||
aria-describedby="password-feedback" required
|
|
||||||
v-model="form.password" type="password"
|
|
||||||
:state="isValid.password" @input="validatePassword"
|
|
||||||
/>
|
|
||||||
<b-form-invalid-feedback id="password-feedback" :state="isValid.password">
|
|
||||||
{{ $t('passwords_too_short') }}
|
|
||||||
</b-form-invalid-feedback>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<!-- USER PASSWORD CONFIRMATION -->
|
<!-- USER PASSWORD CONFIRMATION -->
|
||||||
<b-form-group
|
<form-field v-bind="fields.confirmation" v-model="form.confirmation" :validation="$v.form.confirmation" />
|
||||||
label-cols-md="4" label-cols-lg="2"
|
|
||||||
:label="$t('password_confirmation')" label-for="input-confirmation"
|
|
||||||
:description="$t('good_practices_about_user_password')"
|
|
||||||
>
|
|
||||||
<b-input
|
|
||||||
id="input-confirmation" placeholder="••••••••"
|
|
||||||
aria-describedby="confirmation-feedback" required
|
|
||||||
v-model="form.confirmation" type="password"
|
|
||||||
:state="isValid.confirmation" @input="validatePassword"
|
|
||||||
/>
|
|
||||||
<b-form-invalid-feedback id="confirmation-feedback" :state="isValid.confirmation">
|
|
||||||
{{ $t('passwords_dont_match') }}
|
|
||||||
</b-form-invalid-feedback>
|
|
||||||
</b-form-group>
|
|
||||||
|
|
||||||
<b-form-invalid-feedback id="global-feedback" :state="server.isValid">
|
|
||||||
{{ this.server.error }}
|
|
||||||
</b-form-invalid-feedback>
|
|
||||||
</basic-form>
|
</basic-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import BasicForm from '@/components/BasicForm'
|
import { mapGetters } from 'vuex'
|
||||||
import AdressInputSelect from '@/components/AdressInputSelect'
|
import { formatFormData } from '@/helpers/yunohostArguments'
|
||||||
|
import { validationMixin } from 'vuelidate'
|
||||||
|
import {
|
||||||
|
alphalownum_, unique, required, minLength, alpha, sameAs, integer, minValue
|
||||||
|
} from '@/helpers/validators'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'UserCreate',
|
name: 'UserCreate',
|
||||||
|
|
||||||
|
mixins: [validationMixin],
|
||||||
|
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
form: {
|
form: {
|
||||||
username: '',
|
username: '',
|
||||||
|
fullname: {
|
||||||
firstname: '',
|
firstname: '',
|
||||||
lastname: '',
|
lastname: ''
|
||||||
mail: ['', ''],
|
},
|
||||||
mailbox_quota: '',
|
domain: '',
|
||||||
|
mailbox_quota: 0,
|
||||||
password: '',
|
password: '',
|
||||||
confirmation: ''
|
confirmation: ''
|
||||||
},
|
},
|
||||||
isValid: {
|
|
||||||
username: null,
|
serverError: '',
|
||||||
mail: null,
|
|
||||||
password: null,
|
fields: {
|
||||||
confirmation: null
|
username: {
|
||||||
|
label: this.$i18n.t('user_username'),
|
||||||
|
props: {
|
||||||
|
id: 'username',
|
||||||
|
placeholder: this.$i18n.t('placeholder.username')
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: {
|
|
||||||
username: '',
|
fullname: {
|
||||||
mail: ''
|
label: this.$i18n.t('user_fullname'),
|
||||||
|
id: 'fullname',
|
||||||
|
props: {
|
||||||
|
firstname: {
|
||||||
|
id: 'firstname',
|
||||||
|
label: this.$i18n.t('common.firstname'),
|
||||||
|
placeholder: this.$i18n.t('placeholder.firstname')
|
||||||
},
|
},
|
||||||
server: {
|
lastname: {
|
||||||
isValid: null,
|
id: 'lastname',
|
||||||
error: ''
|
label: this.$i18n.t('common.lastname'),
|
||||||
|
placeholder: this.$i18n.t('placeholder.lastname')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
domain: {
|
||||||
|
id: 'mail',
|
||||||
|
label: this.$i18n.t('user_email'),
|
||||||
|
description: this.$i18n.t('user_email_description'),
|
||||||
|
props: {
|
||||||
|
choices: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mailbox_quota: {
|
||||||
|
label: this.$i18n.t('user_mailbox_quota'),
|
||||||
|
description: this.$i18n.t('mailbox_quota_description'),
|
||||||
|
example: this.$i18n.t('mailbox_quota_example'),
|
||||||
|
props: {
|
||||||
|
id: 'mailbox-quota',
|
||||||
|
placeholder: this.$i18n.t('mailbox_quota_placeholder'),
|
||||||
|
type: 'number'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
password: {
|
||||||
|
label: this.$i18n.t('password'),
|
||||||
|
description: this.$i18n.t('good_practices_about_user_password'),
|
||||||
|
props: {
|
||||||
|
id: 'password',
|
||||||
|
placeholder: '••••••••',
|
||||||
|
type: 'password'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmation: {
|
||||||
|
label: this.$i18n.t('password_confirmation'),
|
||||||
|
props: {
|
||||||
|
id: 'confirmation',
|
||||||
|
placeholder: '••••••••',
|
||||||
|
type: 'password'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
validations () {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
username: { required, alphalownum_, notInUser: unique(this.userNames) },
|
||||||
|
fullname: {
|
||||||
|
firstname: { required, alpha },
|
||||||
|
lastname: { required, alpha }
|
||||||
|
},
|
||||||
|
domain: { required },
|
||||||
|
mailbox_quota: { positiveIntegrer: required, integer, minValue: minValue(0) },
|
||||||
|
password: {
|
||||||
|
required,
|
||||||
|
passwordLenght: minLength(8)
|
||||||
|
},
|
||||||
|
confirmation: {
|
||||||
|
required,
|
||||||
|
passwordMatch: sameAs('password')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
domains () {
|
...mapGetters(['userNames', 'domainsAsChoices', 'mainDomain'])
|
||||||
return this.$store.state.data.domains || []
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
onSubmit () {
|
onSubmit () {
|
||||||
for (const key in this.isValid) {
|
const data = formatFormData(this.form, { flatten: true })
|
||||||
if (this.isValid[key] === false) return
|
if (parseInt(data.mailbox_quota) !== 0) {
|
||||||
|
data.mailbox_quota += 'M'
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = JSON.parse(JSON.stringify(this.form))
|
|
||||||
data.mail = data.mail.join('@')
|
|
||||||
const quota = data.mailbox_quota
|
|
||||||
data.mailbox_quota = parseInt(quota) ? quota + 'M' : 0
|
|
||||||
|
|
||||||
this.$store.dispatch(
|
this.$store.dispatch(
|
||||||
'POST', { uri: 'users', data }
|
'POST', { uri: 'users', data }
|
||||||
).then(() => {
|
).then(() => {
|
||||||
this.$router.push({ name: 'user-list' })
|
this.$router.push({ name: 'user-list' })
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
this.server.error = error.message
|
this.serverError = error.message
|
||||||
this.server.isValid = false
|
|
||||||
})
|
})
|
||||||
},
|
|
||||||
|
|
||||||
populateEmail () {
|
|
||||||
if (this.form.mail[0] === '') {
|
|
||||||
this.form.mail.splice(0, 1, this.form.username)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
validateUsername () {
|
|
||||||
const username = this.form.username
|
|
||||||
let error = ''
|
|
||||||
if (!username.match('^[a-z0-9_]+$')) {
|
|
||||||
// FIXME check allowed characters
|
|
||||||
error = this.$i18n.t('form_errors.username_syntax')
|
|
||||||
} else if (Object.keys(this.$store.state.data.users).includes(username)) {
|
|
||||||
error = this.$i18n.t('form_errors.username_exists', { name: username })
|
|
||||||
}
|
|
||||||
this.error.username = error
|
|
||||||
this.isValid.username = error === '' ? null : false
|
|
||||||
},
|
|
||||||
|
|
||||||
validateEmail () {
|
|
||||||
// FIXME check allowed characters
|
|
||||||
const isValid = this.form.mail.text.match('^[A-Za-z0-9-_]+$')
|
|
||||||
this.error.mail = isValid ? '' : this.$i18n.t('form_errors.email_syntax')
|
|
||||||
this.isValid.mail = isValid ? null : false
|
|
||||||
},
|
|
||||||
|
|
||||||
validatePassword () {
|
|
||||||
const { password, confirmation } = this.form
|
|
||||||
this.isValid.password = password.length >= 8 ? null : false
|
|
||||||
this.isValid.confirmation = password === confirmation ? null : false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created () {
|
created () {
|
||||||
this.$store.dispatch('FETCH_ALL',
|
this.$store.dispatch('FETCH_ALL',
|
||||||
[{ uri: 'domains' }, { uri: 'users' }]
|
[{ uri: 'domains' }, { uri: 'users' }, { uri: 'domains/main', storeKey: 'main_domain' }]
|
||||||
).then(([domains]) => {
|
).then(([domains]) => {
|
||||||
this.form.mail.splice(1, 1, domains[0])
|
this.fields.domain.props.choices = this.domainsAsChoices
|
||||||
|
this.form.domain = this.mainDomain
|
||||||
})
|
})
|
||||||
},
|
|
||||||
|
|
||||||
components: {
|
|
||||||
AdressInputSelect,
|
|
||||||
BasicForm
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@include media-breakpoint-down(xs) {
|
#lastname-label {
|
||||||
.form-group + .form-group {
|
border-left: 0;
|
||||||
padding-top: .5rem;
|
|
||||||
border-top: $thin-border;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@include media-breakpoint-up(md) {
|
.custom-select {
|
||||||
.input-double {
|
flex-basis: 40%;
|
||||||
display: flex;
|
|
||||||
.input-group + .input-group {
|
|
||||||
margin-left: .5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
Loading…
Add table
Reference in a new issue