[enh] Add Import user view

This commit is contained in:
ljf 2020-11-30 10:38:00 +01:00
parent d90cc05d58
commit f2dbbe91d0
5 changed files with 171 additions and 9 deletions

View file

@ -38,8 +38,8 @@ import { openWebSocket, getResponseData, handleError } from './handlers'
* @param {Boolean} [options.addLocale=false] - Option to append the locale to the query string.
* @return {URLSearchParams}
*/
export function objectToParams (obj, { addLocale = false } = {}) {
const urlParams = new URLSearchParams()
export function objectToParams (obj, { addLocale = false } = {}, formData = false) {
const urlParams = (formData) ? new FormData() : new URLSearchParams()
for (const [key, value] of Object.entries(obj)) {
if (Array.isArray(value)) {
value.forEach(v => urlParams.append(key, v))
@ -96,14 +96,9 @@ export default {
if (method === 'GET') {
uri += `${uri.includes('?') ? '&' : '?'}locale=${store.getters.locale}`
} else {
options = { ...options, method, body: objectToParams(data, { addLocale: true }) }
options = { ...options, method, body: objectToParams(data, { addLocale: true }, true) }
}
const response = await fetch('/yunohost/api/' + uri, options)
const responseData = await getResponseData(response)
store.dispatch('END_REQUEST', { request, success: response.ok, wait })
return response.ok ? responseData : handleError(request, response, responseData)
},

View file

@ -0,0 +1,31 @@
<template>
<b-form-file
:id="id"
v-model="file"
v-on="$listeners"
:placeholder="placeholder"
:drop-placeholder="dropPlaceholder"
:state="Boolean(file)"
:required="required"
:accept="accept"
@blur="$parent.$emit('touch', name)"
/>
</template>
<script>
export default {
name: 'FileItem',
data () {
return { file: null }
},
props: {
id: { type: String, default: null },
placeholder: { type: String, default: null },
dropPlaceholder: { type: String, default: null },
required: { type: Boolean, default: false },
state: { type: Boolean, default: null },
name: { type: String, default: null },
accept: { type: String, default: null }
}
}
</script>

View file

@ -293,7 +293,8 @@
"firstname": "John",
"lastname": "Doe",
"groupname": "My group name",
"domain": "my-domain.com"
"domain": "my-domain.com",
"file": "Browse a file or drag and drop it"
},
"logs": "Logs",
"logs_suboperations": "Sub-operations",
@ -489,6 +490,15 @@
"users": "Users",
"users_new": "New user",
"users_no": "No users.",
"users_import": "Import users",
"users_import_csv_file": "CSV File",
"users_import_update": "Update existing users",
"users_import_delete": "Delete non listed users",
"users_import_csv_file_desc": "The CSV file should be in UTF-8 and with columns username, password, groups, email and quota. See <a href=''>example import csv file</a>.",
"users_import_update_desc": "If checked, all existing users contained in the csv file will be updated with the ne new value",
"users_import_delete_desc": "If checked, all existing users that are not in the csv file will be deleted (and purged).",
"users_import_confirm_destructive": "Are you sure you want to delete users that are not present in this file?",
"users_import_delete_others": "Delete unlisted users",
"version": "Version",
"warnings": "{count} warnings",
"words": {

View file

@ -60,6 +60,16 @@ const routes = [
breadcrumb: ['user-list', 'user-create']
}
},
{
name: 'user-import',
path: '/users/import',
component: () => import(/* webpackChunkName: "views/user/import" */ '@/views/user/UserImport'),
props: true,
meta: {
args: { param: 'name' },
breadcrumb: ['user-list', 'user-import']
}
},
{
name: 'user-info',
path: '/users/:name',

View file

@ -0,0 +1,116 @@
<template>
<div>
<card-form
:title="$t('users_import')" icon="user-plus"
:validation="$v" :server-error="serverError"
@submit.prevent="beforeImport"
>
<!-- CSV FILE -->
<form-field component="FileItem" v-bind="fields.csv" v-model="form.csv"
:validation="$v.form.csv" accept=".csv" />
<!-- UPDATE -->
<form-field component="CheckboxItem" v-bind="fields.update" v-model="form.update"
:validation="$v.form.update" />
<!-- DELETE -->
<form-field component="CheckboxItem" v-bind="fields.delete" v-model="form.delete"
:validation="$v.form.delete" />
</card-form>
<!-- CONFIRM DESTRUCTIVE IMPORT MODAL -->
<b-modal
id="confirm-destructive-import-modal" ref="confirm-destructive-import-modal" centered
body-bg-variant="danger" body-text-variant="light"
@ok="onSubmit" hide-header
:ok-title="$t('users_import_delete_others')"
>
{{ $t('users_import_confirm_destructive') }}
</b-modal>
</div>
</template>
<script>
// import { mapGetters } from 'vuex'
import { validationMixin } from 'vuelidate'
import { formatFormData } from '@/helpers/yunohostArguments'
import {
required
} from '@/helpers/validators'
export default {
name: 'UserImport',
mixins: [validationMixin],
data () {
return {
form: {
csv: '',
update: false,
delete: false
},
serverError: '',
fields: {
csv: {
label: this.$i18n.t('users_import_csv_file'),
description: this.$i18n.t('users_import_csv_file_desc'),
props: {
id: 'csv',
placeholder: this.$i18n.t('placeholder.file')
}
},
update: {
label: this.$i18n.t('users_import_update'),
description: this.$i18n.t('users_import_update_desc'),
props: {
id: 'update'
}
},
delete: {
label: this.$i18n.t('users_import_delete'),
description: this.$i18n.t('users_import_delete_desc'),
props: {
id: 'delete'
}
}
}
}
},
validations () {
return {
form: {
csv: { required },
update: { },
delete: { }
}
}
},
methods: {
beforeImport () {
if (this.form.delete) {
this.$refs['confirm-destructive-import-modal'].show()
} else {
this.onSubmit()
}
},
onSubmit () {
const data = formatFormData(this.form, { flatten: true })
this.$store.dispatch(
'POST', { uri: 'users/import', data }
).then(() => {
this.$router.push({ name: 'user-list' })
}).catch(error => {
this.serverError = error.message
})
}
},
created () {
}
}
</script>