mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
add UserEdit and api PUT
This commit is contained in:
parent
68dff35b23
commit
bbc94179b3
6 changed files with 337 additions and 4 deletions
|
@ -50,6 +50,14 @@ export default {
|
||||||
}).then(response => handleResponse(response))
|
}).then(response => handleResponse(response))
|
||||||
},
|
},
|
||||||
|
|
||||||
|
put (uri, data) {
|
||||||
|
return fetch('/api/' + uri, {
|
||||||
|
...this.options,
|
||||||
|
method: 'PUT',
|
||||||
|
body: objectToParams(data)
|
||||||
|
}).then(response => handleResponse(response))
|
||||||
|
},
|
||||||
|
|
||||||
login (password) {
|
login (password) {
|
||||||
return fetch('/api/login', {
|
return fetch('/api/login', {
|
||||||
...this.options,
|
...this.options,
|
||||||
|
|
|
@ -7,21 +7,34 @@ export default {
|
||||||
users: undefined, // basic user data: Object {username: {data}}
|
users: undefined, // basic user data: Object {username: {data}}
|
||||||
users_details: {} // precise user data: Object {username: {data}}
|
users_details: {} // precise user data: Object {username: {data}}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
mutations: {
|
mutations: {
|
||||||
'SET_DOMAINS' (state, domains) {
|
'SET_DOMAINS' (state, domains) {
|
||||||
state.domains = domains
|
state.domains = domains
|
||||||
},
|
},
|
||||||
|
|
||||||
'SET_USERS' (state, users) {
|
'SET_USERS' (state, users) {
|
||||||
state.users = Object.keys(users).length === 0 ? null : users
|
state.users = Object.keys(users).length === 0 ? null : users
|
||||||
},
|
},
|
||||||
|
|
||||||
'ADD_USER' (state, user) {
|
'ADD_USER' (state, user) {
|
||||||
// FIXME will trigger an error if first created user
|
// FIXME will trigger an error if first created user
|
||||||
Vue.set(state.users, user.username, user)
|
Vue.set(state.users, user.username, user)
|
||||||
},
|
},
|
||||||
|
|
||||||
'SET_USERS_PARAM' (state, [username, userData]) {
|
'SET_USERS_PARAM' (state, [username, userData]) {
|
||||||
Vue.set(state.users_details, username, userData)
|
Vue.set(state.users_details, username, userData)
|
||||||
|
if (!state.users) return
|
||||||
|
const user = state.users[username]
|
||||||
|
for (const key of ['firstname', 'lastname', 'mail']) {
|
||||||
|
if (user[key] !== userData[key]) {
|
||||||
|
Vue.set(user, key, userData[key])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Vue.set(user, 'fullname', `${userData.firstname} ${userData.lastname}`)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
'FETCH' ({ state, commit }, { uri, param, storeKey = uri, force = false }) {
|
'FETCH' ({ state, commit }, { uri, param, storeKey = uri, force = false }) {
|
||||||
const currentState = param ? state[storeKey][param] : state[storeKey]
|
const currentState = param ? state[storeKey][param] : state[storeKey]
|
||||||
|
@ -39,10 +52,23 @@ export default {
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
'POST' ({ state, commit }, { uri, param, data, storeKey }) {
|
'POST' ({ state, commit }, { uri, data }) {
|
||||||
return api.post(uri, data)
|
return api.post(uri, data)
|
||||||
|
},
|
||||||
|
|
||||||
|
'PUT' ({ state, commit }, { uri, param, data, storeKey = uri }) {
|
||||||
|
return api.put(param ? `${uri}/${param}` : uri, data).then(async responseData => {
|
||||||
|
const data = responseData[uri] ? responseData[uri] : responseData
|
||||||
|
if (param) {
|
||||||
|
commit(`SET_${uri.toUpperCase()}_PARAM`, [param, data])
|
||||||
|
} else {
|
||||||
|
commit('SET_' + uri.toUpperCase(), data)
|
||||||
|
}
|
||||||
|
return param ? state[storeKey][param] : state[storeKey]
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
getters: {
|
getters: {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Home from './views/Home'
|
import Home from './views/Home'
|
||||||
import Login from './views/Login'
|
import Login from './views/Login'
|
||||||
import { UserList, UserCreate, User } from './views/user'
|
import { UserList, UserCreate, User, UserEdit } from './views/user'
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ name: 'home', path: '/', component: Home },
|
{ name: 'home', path: '/', component: Home },
|
||||||
|
@ -35,6 +35,19 @@ const routes = [
|
||||||
{ name: 'user-info', param: 'name' }
|
{ name: 'user-info', param: 'name' }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'user-edit',
|
||||||
|
path: '/users/:name/edit',
|
||||||
|
component: UserEdit,
|
||||||
|
props: true,
|
||||||
|
meta: {
|
||||||
|
breadcrumb: [
|
||||||
|
{ name: 'user-list', trad: 'users' },
|
||||||
|
{ name: 'user-info', param: 'name' },
|
||||||
|
{ name: 'user-edit', param: 'name', trad: 'user_username_edit' }
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -165,8 +165,8 @@ export default {
|
||||||
const quota = data.mailbox_quota
|
const quota = data.mailbox_quota
|
||||||
data.mailbox_quota = parseInt(quota) ? quota + 'M' : 0
|
data.mailbox_quota = parseInt(quota) ? quota + 'M' : 0
|
||||||
|
|
||||||
this.$store.dispatch('POST',
|
this.$store.dispatch(
|
||||||
{ uri: 'users', data, param: data.username, storeKey: '' }
|
'POST', { uri: 'users', data }
|
||||||
).then(responseData => {
|
).then(responseData => {
|
||||||
// FIXME API doesn't return the same data as '/users'
|
// FIXME API doesn't return the same data as '/users'
|
||||||
this.$store.commit('ADD_USER', responseData)
|
this.$store.commit('ADD_USER', responseData)
|
||||||
|
|
285
app/src/views/user/UserEdit.vue
Normal file
285
app/src/views/user/UserEdit.vue
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
<template lang="html">
|
||||||
|
<div class="user-edit">
|
||||||
|
<b-card v-if="this.form.firstname" :header="user ? $t('user_username_edit', { name: user.username }) : ''" header-tag="h2">
|
||||||
|
<b-form id="user-edit" @submit.prevent="onSubmit">
|
||||||
|
<!-- USER FULLNAME -->
|
||||||
|
<b-form-group label-cols="auto">
|
||||||
|
<template v-slot:label aria-hidden="true">
|
||||||
|
{{ $t('user_fullname') }}
|
||||||
|
</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"
|
||||||
|
/>
|
||||||
|
</b-input-group>
|
||||||
|
|
||||||
|
<b-input-group>
|
||||||
|
<b-input-group-prepend
|
||||||
|
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"
|
||||||
|
/>
|
||||||
|
</b-input-group>
|
||||||
|
</div>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<!-- USER EMAIL -->
|
||||||
|
<b-form-group label-cols="auto" :label="$t('user_email')" label-for="input-email">
|
||||||
|
<splitted-mail-input
|
||||||
|
id="input-email" feedback="email-feedback"
|
||||||
|
v-model="form.mail" :domains="domains"
|
||||||
|
:state="isValid.mail" @input="validateEmail"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<b-form-invalid-feedback id="email-feedback" :state="isValid.mail">
|
||||||
|
{{ this.error.mail }}
|
||||||
|
</b-form-invalid-feedback>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<!-- MAILBOX QUOTA -->
|
||||||
|
<hr>
|
||||||
|
<b-form-group
|
||||||
|
label-cols="auto" :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-form-group>
|
||||||
|
|
||||||
|
<!-- MAIL ALIASES -->
|
||||||
|
<hr>
|
||||||
|
<b-form-group label-cols="auto" :label="$t('user_emailaliases')" class="mail-list">
|
||||||
|
<splitted-mail-input
|
||||||
|
v-for="(alias, index) in form['mail-aliases']" :key="index"
|
||||||
|
feedback="mail-aliases-feedback"
|
||||||
|
v-model="form['mail-aliases'][index]" :domains="domains"
|
||||||
|
/>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<!-- MAIL FORWARD -->
|
||||||
|
<hr>
|
||||||
|
<b-form-group label-cols="auto" :label="$t('user_emailforward')" class="mail-list">
|
||||||
|
<b-input
|
||||||
|
v-for="(forward, index) in form['mail-forward']" :key="index"
|
||||||
|
id="input-mailbox-quota" :placeholder="$t('user_new_forward')"
|
||||||
|
v-model="form['mail-forward'][index]" type="email"
|
||||||
|
/>
|
||||||
|
</b-form-group>
|
||||||
|
|
||||||
|
<!-- USER PASSWORD -->
|
||||||
|
<hr>
|
||||||
|
<b-form-group label-cols="auto" :label="$t('password')" label-for="input-password">
|
||||||
|
<b-input
|
||||||
|
id="input-password" placeholder="••••••••"
|
||||||
|
aria-describedby="password-feedback"
|
||||||
|
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 -->
|
||||||
|
<b-form-group
|
||||||
|
label-cols="auto" :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"
|
||||||
|
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>
|
||||||
|
</b-form>
|
||||||
|
|
||||||
|
<template v-slot:footer>
|
||||||
|
<div class="d-flex d-flex justify-content-end">
|
||||||
|
<b-button type="submit" form="user-edit" variant="success">
|
||||||
|
{{ $t('save') }}
|
||||||
|
</b-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</b-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SplittedMailInput from '@/components/SplittedMailInput'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UserEdit',
|
||||||
|
props: {
|
||||||
|
name: { type: String, required: true }
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
form: {
|
||||||
|
firstname: '',
|
||||||
|
lastname: '',
|
||||||
|
mail: '',
|
||||||
|
'mailbox-quota': '',
|
||||||
|
'mail-aliases': [],
|
||||||
|
'mail-forward': [],
|
||||||
|
password: '',
|
||||||
|
confirmation: ''
|
||||||
|
},
|
||||||
|
isValid: {
|
||||||
|
mail: null,
|
||||||
|
password: null,
|
||||||
|
confirmation: null
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
mail: ''
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
isValid: null,
|
||||||
|
error: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
user () {
|
||||||
|
return this.$store.state.data.users_details[this.name]
|
||||||
|
},
|
||||||
|
domains () {
|
||||||
|
return this.$store.state.data.domains
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onSubmit () {
|
||||||
|
for (const key in this.isValid) {
|
||||||
|
if (this.isValid[key] === false) return
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = {}
|
||||||
|
|
||||||
|
for (const key of ['firstname', 'lastname', 'mail']) {
|
||||||
|
if (this.form[key] !== this.user[key]) data[key] = this.form[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
let quota = this.form['mailbox-quota']
|
||||||
|
quota = parseInt(quota) ? quota + 'M' : 'No quota'
|
||||||
|
if (quota !== this.user['mailbox-quota'].limit) {
|
||||||
|
data.mailbox_quota = quota !== 'No quota' ? quota : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const mails = {
|
||||||
|
add_mailalias: arrayDiff(this.form['mail-aliases'], this.user['mail-aliases']),
|
||||||
|
remove_mailalias: arrayDiff(this.user['mail-aliases'], this.form['mail-aliases']),
|
||||||
|
add_mailforward: arrayDiff(this.form['mail-forward'], this.user['mail-forward']),
|
||||||
|
remove_mailforward: arrayDiff(this.user['mail-forward'], this.form['mail-forward'])
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(mails)) {
|
||||||
|
if (value.length > 0) data[key] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayDiff (arr1 = [], arr2 = []) {
|
||||||
|
return arr1.filter(item => ((arr2.indexOf(item) === -1) && (item !== '')))
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(data)
|
||||||
|
this.$store.dispatch('PUT',
|
||||||
|
{ uri: 'users', data, param: this.user.username, storeKey: 'users_details' }
|
||||||
|
).then(() => {
|
||||||
|
this.$router.push({ name: 'user-list' })
|
||||||
|
}).catch(error => {
|
||||||
|
this.server.error = error.message
|
||||||
|
this.server.isValid = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
validateEmail () {
|
||||||
|
// FIXME check allowed characters
|
||||||
|
const isValid = this.form.mail.split('@')[0].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 () {
|
||||||
|
this.$store.dispatch('FETCH', { uri: 'domains' })
|
||||||
|
this.$store.dispatch('FETCH',
|
||||||
|
{ uri: 'users', param: this.name, storeKey: 'users_details' }
|
||||||
|
).then(userData => {
|
||||||
|
this.form.firstname = userData.firstname
|
||||||
|
this.form.lastname = userData.lastname
|
||||||
|
this.form.mail = userData.mail
|
||||||
|
this.form['mail-aliases'] = userData['mail-aliases'] ? [...userData['mail-aliases'], ''] : ['']
|
||||||
|
this.form['mail-forward'] = userData['mail-forward'] ? [...userData['mail-forward'], ''] : ['']
|
||||||
|
if (userData['mailbox-quota'].limit !== 'No quota') {
|
||||||
|
console.log(userData['mailbox-quota'])
|
||||||
|
this.form['mailbox-quota'] = userData['mailbox-quota'].limit.slice(0, -1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
SplittedMailInput
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@include media-breakpoint-down(xs) {
|
||||||
|
.form-group:not(:first-of-type) {
|
||||||
|
padding-top: .5rem;
|
||||||
|
border-top: $thin-border;
|
||||||
|
}
|
||||||
|
hr {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include media-breakpoint-up(md) {
|
||||||
|
.input-double {
|
||||||
|
display: flex;
|
||||||
|
.input-group + .input-group {
|
||||||
|
margin-left: .5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.mail-list .col > *:not(:first-of-type) {
|
||||||
|
margin-top: .5rem;
|
||||||
|
|
||||||
|
input {
|
||||||
|
max-width: 10rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -1,3 +1,4 @@
|
||||||
export { default as UserList } from './UserList'
|
export { default as UserList } from './UserList'
|
||||||
export { default as UserCreate } from './UserCreate'
|
export { default as UserCreate } from './UserCreate'
|
||||||
export { default as User } from './User'
|
export { default as User } from './User'
|
||||||
|
export { default as UserEdit } from './UserEdit'
|
||||||
|
|
Loading…
Add table
Reference in a new issue