mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-19 05:58:34 +02:00
Better domain creation form.
This commit is contained in:
+36
-5
@@ -13,11 +13,31 @@
|
||||
<router-view/>
|
||||
</v-container>
|
||||
</v-main>
|
||||
<v-snackbar
|
||||
v-model="snackbar"
|
||||
:color="notificationColor"
|
||||
:timeout="notificationTimeout"
|
||||
top
|
||||
>
|
||||
{{ notification }}
|
||||
|
||||
<template v-slot:action="{ attrs }">
|
||||
<v-btn
|
||||
color="white"
|
||||
text
|
||||
v-bind="attrs"
|
||||
@click="snackbar = false"
|
||||
>
|
||||
<translate>Close</translate>
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-snackbar>
|
||||
</v-app>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { bus } from '@/main'
|
||||
import Navbar from '@/components/layout/Navbar'
|
||||
|
||||
export default {
|
||||
@@ -30,12 +50,23 @@ export default {
|
||||
components: {
|
||||
Navbar
|
||||
},
|
||||
// created () {
|
||||
// this.$store.dispatch('auth/initialize')
|
||||
// },
|
||||
created () {
|
||||
// this.$store.dispatch('auth/initialize')
|
||||
bus.$on('notification', this.showNotification)
|
||||
},
|
||||
data: () => ({
|
||||
//
|
||||
})
|
||||
snackbar: false,
|
||||
notification: '',
|
||||
notificationColor: 'success',
|
||||
notificationTimeout: 2000
|
||||
}),
|
||||
methods: {
|
||||
showNotification (options) {
|
||||
this.notification = options.msg
|
||||
this.notificationColor = (options.type) ? options.type : 'success'
|
||||
this.snackbar = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -4,20 +4,39 @@
|
||||
<span class="headline">{{ title }}</span>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field v-model="form.name" label="Name" />
|
||||
<v-select
|
||||
v-model="form.target"
|
||||
:items="domains"
|
||||
item-text="name"
|
||||
item-value="pk"
|
||||
label="Choose a domain"
|
||||
single-line
|
||||
></v-select>
|
||||
<v-switch
|
||||
v-model="form.enabled"
|
||||
label="Enabled"
|
||||
color="primary"
|
||||
/>
|
||||
<validation-observer ref="observer">
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
name="name"
|
||||
rules="required"
|
||||
>
|
||||
<v-text-field
|
||||
v-model="form.name"
|
||||
:label="'Name' | translate"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</validation-provider>
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
name="target"
|
||||
rules="required"
|
||||
>
|
||||
<v-select
|
||||
v-model="form.target"
|
||||
:items="domains"
|
||||
item-text="name"
|
||||
item-value="pk"
|
||||
:label="'Choose a domain' | translate"
|
||||
:error-messages="errors"
|
||||
single-line
|
||||
/>
|
||||
</validation-provider>
|
||||
<v-switch
|
||||
v-model="form.enabled"
|
||||
label="Enabled"
|
||||
color="primary"
|
||||
/>
|
||||
</validation-observer>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
@@ -41,6 +60,7 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { bus } from '@/main'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
@@ -69,17 +89,27 @@ export default {
|
||||
this.$emit('close')
|
||||
this.form = {}
|
||||
},
|
||||
submit () {
|
||||
if (!this.form.pk) {
|
||||
this.$store.dispatch('domains/addDomainAlias', this.form).then(resp => {
|
||||
this.close()
|
||||
})
|
||||
} else {
|
||||
const data = JSON.parse(JSON.stringify(this.form))
|
||||
data.target = data.target.pk
|
||||
this.$store.dispatch('domains/updateDomainAlias', { id: this.form.pk, data: data }).then(resp => {
|
||||
this.close()
|
||||
})
|
||||
async submit () {
|
||||
const valid = await this.$refs.observer.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
if (!this.form.pk) {
|
||||
await this.$store.dispatch('domains/addDomainAlias', this.form).then(resp => {
|
||||
bus.$emit('notification', { msg: this.$gettext('Domain alias created') })
|
||||
this.close()
|
||||
})
|
||||
} else {
|
||||
const data = JSON.parse(JSON.stringify(this.form))
|
||||
data.target = data.target.pk
|
||||
await this.$store.dispatch('domains/updateDomainAlias', { id: this.form.pk, data: data }).then(resp => {
|
||||
bus.$emit('notification', { msg: this.$gettext('Domain alias updated') })
|
||||
this.close()
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
this.$refs.observer.setErrors(error.response.data)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="d-flex justify-center inner">
|
||||
<v-stepper v-model="step">
|
||||
<v-stepper-header class=" align-center">
|
||||
<v-stepper-header class="align-center px-10">
|
||||
<v-img
|
||||
src="../../assets/Modoboa_RVB-ORANGE-SANS.png"
|
||||
max-width="190"
|
||||
@@ -15,7 +15,7 @@
|
||||
<v-stepper-step :complete="step > 3" step="3">
|
||||
<translate>Limitations</translate>
|
||||
</v-stepper-step>
|
||||
<v-stepper-step step="4">
|
||||
<v-stepper-step :complete="step > 4" step="4">
|
||||
<translate>Options</translate>
|
||||
</v-stepper-step>
|
||||
<v-stepper-step step="5">
|
||||
@@ -25,8 +25,12 @@
|
||||
<v-icon color="primary" x-large>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
</v-stepper-header>
|
||||
<v-stepper-items class="mx-16 mt-4">
|
||||
<v-stepper-content step="1">
|
||||
<v-stepper-items class="mt-4 d-flex justify-center">
|
||||
<v-stepper-content step="1" class="flex-grow-0">
|
||||
<div class="mb-6 text-h5">
|
||||
<translate class="grey--text text--darken-1">New domain</translate> /
|
||||
<translate>General</translate>
|
||||
</div>
|
||||
<validation-observer ref="observer_1">
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
@@ -61,17 +65,21 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-stepper-content>
|
||||
<v-stepper-content step="2">
|
||||
<v-stepper-content step="2" class="flex-grow-0">
|
||||
<div class="mb-6 text-h5">
|
||||
<translate class="grey--text text--darken-1">New domain</translate> /
|
||||
<translate>DNS</translate>
|
||||
</div>
|
||||
<v-switch
|
||||
label="Enable DNS checks"
|
||||
:label="'Enable DNS checks' | translate"
|
||||
v-model="domain.enable_dns_checks"
|
||||
/>
|
||||
<v-switch
|
||||
label="Enable DKIM signing"
|
||||
:label="'Enable DKIM signing' | translate"
|
||||
v-model="domain.enable_dkim"
|
||||
/>
|
||||
<v-text-field
|
||||
label="DKIM key selector"
|
||||
:label="'DKIM key selector' | translate"
|
||||
v-model="domain.dkim_key_selector"
|
||||
:disabled="!domain.enable_dkim"
|
||||
outlined
|
||||
@@ -80,6 +88,7 @@
|
||||
v-model="domain.dkim_key_length"
|
||||
:label="'DKIM key length' | translate"
|
||||
:choices="dkimKeyLengths"
|
||||
:disabled="!domain.enable_dkim"
|
||||
/>
|
||||
<div class="d-flex justify-center mt-8">
|
||||
<v-btn @click="step = 1" class="mr-10" text>
|
||||
@@ -94,31 +103,47 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-stepper-content>
|
||||
<v-stepper-content step="3">
|
||||
<v-stepper-content step="3" class="flex-grow-0">
|
||||
<div class="mb-6 text-h5">
|
||||
<translate class="grey--text text--darken-1">New domain</translate> /
|
||||
<translate>Limitations</translate>
|
||||
</div>
|
||||
<validation-observer ref="observer_3">
|
||||
<v-text-field
|
||||
:label="'Quota' | translate"
|
||||
:hint="'Quota shared between mailboxes. Can be expressed in KB, MB (default) or GB. A value of 0 means no quota.' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.quota"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
/>
|
||||
<v-text-field
|
||||
:label="'Default mailbox quota' | translate"
|
||||
:hint="'Default quota applied to mailboxes. Can be expressed in KB, MB (default) or GB. A value of 0 means no quota.' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.default_mailbox_quota"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
/>
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="number"
|
||||
rules="required"
|
||||
>
|
||||
<v-text-field
|
||||
:label="'Quota' | translate"
|
||||
:hint="'Quota shared between mailboxes. Can be expressed in KB, MB (default) or GB. A value of 0 means no quota.' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.quota"
|
||||
:error-messages="errors"
|
||||
class="mb-4"
|
||||
outlined
|
||||
/>
|
||||
</validation-provider>
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="required"
|
||||
>
|
||||
<v-text-field
|
||||
:label="'Default mailbox quota' | translate"
|
||||
:hint="'Default quota applied to mailboxes. Can be expressed in KB, MB (default) or GB. A value of 0 means no quota.' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.default_mailbox_quota"
|
||||
:error-messages="errors"
|
||||
class="mb-4"
|
||||
outlined
|
||||
/>
|
||||
</validation-provider>
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="numeric"
|
||||
>
|
||||
<v-text-field
|
||||
:label="'Message sending limit' | translate"
|
||||
:hint="'Number of messages this domain can send per day.' | translate"
|
||||
:hint="'Number of messages this domain can send per day. Leave empty for no limit.' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.message_sending_limit"
|
||||
:error-messages="errors"
|
||||
@@ -139,33 +164,43 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-stepper-content>
|
||||
<v-stepper-content step="4">
|
||||
<v-stepper-content step="4" class="flex-grow-0">
|
||||
<div class="mb-6 text-h5">
|
||||
<translate class="grey--text text--darken-1">New domain</translate> /
|
||||
<translate>Options</translate>
|
||||
</div>
|
||||
<validation-observer ref="observer_4">
|
||||
<v-switch v-model="createAdmin"
|
||||
:label="'Create a domain administrator' | translate"
|
||||
/>
|
||||
<v-text-field
|
||||
:label="'Name' | translate"
|
||||
:hint="'Name of the administrator' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.dom_admin_username"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
:disabled="!createAdmin"
|
||||
/>
|
||||
<v-switch v-model="domain.dom_admin_random_password"
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
:rules="(createAdmin) ? 'required' : ''"
|
||||
>
|
||||
<v-text-field
|
||||
:label="'Name' | translate"
|
||||
:hint="'Name of the administrator' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.domain_admin.username"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
:disabled="!createAdmin"
|
||||
:suffix="`@${domain.name}`"
|
||||
/>
|
||||
</validation-provider>
|
||||
<v-switch v-model="domain.domain_admin.with_random_password"
|
||||
:label="'Random password' | translate"
|
||||
:disabled="!createAdmin"
|
||||
:hint="'Generate a random password for the administrator.' | translate"
|
||||
persistent-hint
|
||||
/>
|
||||
<v-switch v-model="domain.dom_admin_with_mailbox"
|
||||
<v-switch v-model="domain.domain_admin.with_mailbox"
|
||||
:label="'With a mailbox' | translate"
|
||||
:disabled="!createAdmin"
|
||||
:hint="'Create a mailbox for the administrator.' | translate"
|
||||
persistent-hint
|
||||
/>
|
||||
<v-switch v-model="domain.dom_admin_create_aliases"
|
||||
<v-switch v-model="domain.domain_admin.with_aliases"
|
||||
:label="'Create aliases' | translate"
|
||||
:disabled="!createAdmin"
|
||||
:hint="'Create standard aliases for the domain.' | translate"
|
||||
@@ -186,10 +221,11 @@
|
||||
</v-btn>
|
||||
</div>
|
||||
</v-stepper-content>
|
||||
<v-stepper-content step="5">
|
||||
<v-stepper-content step="5" class="flex-grow-0">
|
||||
<div class="text-center text-h3"><translate>Summary</translate></div>
|
||||
<div class="subtitle text-subtitle-1 mt-4">
|
||||
<translate>General</translate>
|
||||
<div class="subtitle mt-4 d-flex">
|
||||
<translate class="text-h6">General</translate>
|
||||
<a href="#" class="edit-link ml-auto" @click="step = 1"><translate>Modify</translate></a>
|
||||
</div>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Name</translate></v-col>
|
||||
@@ -201,18 +237,19 @@
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Enabled</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.enabled }}</v-col>
|
||||
<v-col class="text-right">{{ domain.enabled|yesno }}</v-col>
|
||||
</v-row>
|
||||
<div class="subtitle text-subtitle-1 mt-4">
|
||||
<translate>DNS</translate>
|
||||
<div class="subtitle mt-4 d-flex">
|
||||
<translate class="text-h6">DNS</translate>
|
||||
<a href="#" class="edit-link ml-auto" @click="step = 2"><translate>Modify</translate></a>
|
||||
</div>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Enable DNS checks</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.enable_dns_checks }}</v-col>
|
||||
<v-col class="text-right">{{ domain.enable_dns_checks|yesno }}</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Enable DKIM signing</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.enable_dkim }}</v-col>
|
||||
<v-col class="text-right">{{ domain.enable_dkim|yesno }}</v-col>
|
||||
</v-row>
|
||||
<v-row dense v-if="domain.enable_dkim">
|
||||
<v-col><translate class="grey--text">DKIM key selector</translate></v-col>
|
||||
@@ -222,8 +259,9 @@
|
||||
<v-col><translate class="grey--text">DKIM key length</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.dkim_key_length }}</v-col>
|
||||
</v-row>
|
||||
<div class="subtitle text-subtitle-1 mt-4">
|
||||
<translate>Limitations</translate>
|
||||
<div class="subtitle mt-4 d-flex">
|
||||
<translate class="text-h6">Limitations</translate>
|
||||
<a href="#" class="edit-link ml-auto" @click="step = 3"><translate>Modify</translate></a>
|
||||
</div>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Quota</translate></v-col>
|
||||
@@ -237,29 +275,30 @@
|
||||
<v-col><translate class="grey--text">Message sending limit</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.message_sending_limit }}</v-col>
|
||||
</v-row>
|
||||
<div class="subtitle text-subtitle-1 mt-4">
|
||||
<translate>Options</translate>
|
||||
<div class="subtitle mt-4 d-flex">
|
||||
<translate class="text-h6">Options</translate>
|
||||
<a href="#" class="edit-link ml-auto" @click="step = 4"><translate>Modify</translate></a>
|
||||
</div>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Create a domain administrator</translate></v-col>
|
||||
<v-col class="text-right">{{ createAdmin }}</v-col>
|
||||
<v-col class="text-right">{{ createAdmin|yesno }}</v-col>
|
||||
</v-row>
|
||||
<div v-if="createAdmin">
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Administrator name</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.dom_admin_username }}</v-col>
|
||||
<v-col class="text-right">{{ domain.domain_admin.username }}</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Random password</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.dom_admin_random_password }}</v-col>
|
||||
<v-col class="text-right">{{ domain.domain_admin.with_random_password|yesno }}</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">With mailbox</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.dom_admin_with_mailbox }}</v-col>
|
||||
<v-col class="text-right">{{ domain.domain_admin.with_mailbox|yesno }}</v-col>
|
||||
</v-row>
|
||||
<v-row dense>
|
||||
<v-col><translate class="grey--text">Create aliases</translate></v-col>
|
||||
<v-col class="text-right">{{ domain.dom_admin_create_aliases }}</v-col>
|
||||
<v-col class="text-right">{{ domain.domain_admin.with_aliases|yesno }}</v-col>
|
||||
</v-row>
|
||||
</div>
|
||||
<div class="d-flex justify-center mt-8">
|
||||
@@ -278,7 +317,9 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { bus } from '@/main'
|
||||
import ChoiceField from '@/components/tools/ChoiceField'
|
||||
|
||||
export default {
|
||||
props: ['value'],
|
||||
components: {
|
||||
@@ -287,7 +328,9 @@ export default {
|
||||
data () {
|
||||
return {
|
||||
createAdmin: false,
|
||||
domain: {},
|
||||
domain: {
|
||||
domain_admin: {}
|
||||
},
|
||||
domainTypes: [
|
||||
{
|
||||
label: 'Domain',
|
||||
@@ -324,6 +367,7 @@ export default {
|
||||
methods: {
|
||||
initDomain () {
|
||||
this.domain = {
|
||||
name: '',
|
||||
type: 'domain',
|
||||
enabled: true,
|
||||
enable_dns_checks: true,
|
||||
@@ -331,10 +375,12 @@ export default {
|
||||
dkim_key_selector: 'modoboa',
|
||||
quota: 0,
|
||||
default_mailbox_quota: 0,
|
||||
dom_admin_username: 'admin',
|
||||
dom_admin_random_password: false,
|
||||
dom_admin_with_mailbox: false,
|
||||
dom_admin_create_aliases: false
|
||||
domain_admin: {
|
||||
username: 'admin',
|
||||
with_random_password: false,
|
||||
with_mailbox: false,
|
||||
with_aliases: false
|
||||
}
|
||||
}
|
||||
},
|
||||
close () {
|
||||
@@ -350,7 +396,12 @@ export default {
|
||||
this.step = next
|
||||
},
|
||||
submit () {
|
||||
this.$store.dispatch('domains/createDomain', this.domain).then(resp => {
|
||||
const data = JSON.parse(JSON.stringify(this.domain))
|
||||
if (!this.createAdmin) {
|
||||
delete data.domain_admin
|
||||
}
|
||||
this.$store.dispatch('domains/createDomain', data).then(resp => {
|
||||
bus.$emit('notification', { msg: this.$gettext('Domain created') })
|
||||
this.close()
|
||||
})
|
||||
}
|
||||
@@ -358,17 +409,28 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss">
|
||||
.inner {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
.v-stepper {
|
||||
height: 100%;
|
||||
width: 70%;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
|
||||
&__content {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
&__items {
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
.subtitle {
|
||||
color: #000;
|
||||
border-bottom: 1px solid #DBDDDF;
|
||||
}
|
||||
|
||||
.edit-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div v-for="(choice, index) in choices"
|
||||
:key="index"
|
||||
class="choice rounded pa-10 mr-4 text-center"
|
||||
:class="{ 'choice--selected': currentChoice === choice.value }"
|
||||
:class="{ 'choice--disabled': disabled, 'choice--selected': !disabled && currentChoice === choice.value }"
|
||||
@click="selectChoice(choice.value)">
|
||||
<v-icon v-if="choice.icon" class="d-block mb-2" :color="iconColor(choice.value)" x-large>{{ choice.icon }}</v-icon>
|
||||
<translate class="grey--text text--darken-1">{{ choice.label }}</translate>
|
||||
@@ -16,20 +16,39 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['value', 'label', 'choices'],
|
||||
props: {
|
||||
value: [Number, String],
|
||||
label: String,
|
||||
choices: Array,
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
currentChoice: this.value
|
||||
currentChoice: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
iconColor (value) {
|
||||
return (value === this.currentChoice) ? 'primary' : ''
|
||||
return (!this.disabled && value === this.currentChoice) ? 'primary' : ''
|
||||
},
|
||||
selectChoice (value) {
|
||||
if (this.disabled) {
|
||||
return
|
||||
}
|
||||
this.currentChoice = value
|
||||
this.$emit('input', value)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value: {
|
||||
handler (val) {
|
||||
this.currentChoice = val
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -44,5 +63,9 @@ export default {
|
||||
&--selected {
|
||||
border-color: #046BF8 !important;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
cursor: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
import Vue from 'vue'
|
||||
import { translate } from 'vue-gettext'
|
||||
const { gettext: $gettext } = translate
|
||||
|
||||
Vue.filter('yesno', function (value) {
|
||||
return (value) ? $gettext('yes') : $gettext('no')
|
||||
})
|
||||
@@ -3,6 +3,7 @@ import './plugins/axios'
|
||||
import './plugins/vee-validate'
|
||||
import './plugins/vue-cookie'
|
||||
import './plugins/vue-gettext'
|
||||
import './filters'
|
||||
import App from './App.vue'
|
||||
import router from './router'
|
||||
import store from './store'
|
||||
@@ -10,6 +11,8 @@ import vuetify from './plugins/vuetify'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
|
||||
export const bus = new Vue()
|
||||
|
||||
new Vue({
|
||||
router,
|
||||
store,
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
<v-dialog
|
||||
v-model="showDomainWizard"
|
||||
fullscreen
|
||||
scrollable
|
||||
transition="dialog-bottom-transition"
|
||||
>
|
||||
<domain-creation-form @close="showDomainWizard = false" />
|
||||
|
||||
@@ -38,12 +38,16 @@ class DomainViewSet(viewsets.ModelViewSet):
|
||||
"""Domain viewset."""
|
||||
|
||||
permission_classes = [IsAuthenticated, DjangoModelPermissions, ]
|
||||
serializer_class = serializers.DomainSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
"""Filter queryset based on current user."""
|
||||
return models.Domain.objects.get_for_admin(self.request.user)
|
||||
|
||||
def get_serializer_class(self, *args, **kwargs):
|
||||
if self.request.version == "v2" and self.action == "create":
|
||||
return serializers.DomainSerializerV2
|
||||
return serializers.DomainSerializer
|
||||
|
||||
def perform_destroy(self, instance):
|
||||
"""Add custom args to delete call."""
|
||||
instance.delete(self.request.user)
|
||||
|
||||
@@ -110,6 +110,85 @@ class DomainSerializer(serializers.ModelSerializer):
|
||||
return domain
|
||||
|
||||
|
||||
class CreateDomainAdminSerializer(serializers.Serializer):
|
||||
"""Sub serializer for domain administrator creation."""
|
||||
|
||||
username = serializers.CharField()
|
||||
with_random_password = serializers.BooleanField(default=False)
|
||||
with_mailbox = serializers.BooleanField(default=False)
|
||||
with_aliases = serializers.BooleanField(default=False)
|
||||
|
||||
|
||||
class DomainSerializerV2(DomainSerializer):
|
||||
"""Domain serializer for v2 API."""
|
||||
|
||||
domain_admin = CreateDomainAdminSerializer(required=False)
|
||||
|
||||
class Meta(DomainSerializer.Meta):
|
||||
fields = DomainSerializer.Meta.fields + (
|
||||
"domain_admin",
|
||||
)
|
||||
|
||||
def create(self, validated_data):
|
||||
"""Create administrator and other stuff if needed."""
|
||||
domain_admin = validated_data.pop("domain_admin", None)
|
||||
domain = super().create(validated_data)
|
||||
if not domain_admin:
|
||||
return domain
|
||||
|
||||
# 1. Create a domain administrator
|
||||
username = "%s@%s" % (domain_admin["username"], domain.name)
|
||||
try:
|
||||
da = core_models.User.objects.get(username=username)
|
||||
except core_models.User.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
raise lib_exceptions.Conflict(
|
||||
_("User '%s' already exists") % username)
|
||||
user = self.context["request"].user
|
||||
core_signals.can_create_object.send(
|
||||
self.__class__, context=user, klass=models.Mailbox)
|
||||
da = core_models.User(username=username, email=username, is_active=True)
|
||||
if domain_admin["with_random_password"]:
|
||||
password = lib.make_password()
|
||||
else:
|
||||
password = param_tools.get_global_parameter(
|
||||
"default_password", app="core")
|
||||
da.set_password(password)
|
||||
da.save()
|
||||
da.role = "DomainAdmins"
|
||||
da.post_create(user)
|
||||
|
||||
# 2. Create mailbox if needed
|
||||
if domain_admin["with_mailbox"]:
|
||||
dom_admin_username = domain_admin["username"]
|
||||
mb = models.Mailbox(
|
||||
address=dom_admin_username, domain=domain,
|
||||
user=da, use_domain_quota=True
|
||||
)
|
||||
mb.set_quota(
|
||||
override_rules=user.has_perm("admin.change_domain"))
|
||||
mb.save(creator=user)
|
||||
|
||||
# 3. Create aliases if needed
|
||||
condition = (
|
||||
domain.type == "domain" and
|
||||
domain_admin["with_aliases"] and
|
||||
dom_admin_username != "postmaster"
|
||||
)
|
||||
if condition:
|
||||
core_signals.can_create_object.send(
|
||||
self.__class__, context=user, klass=models.Alias)
|
||||
address = u"postmaster@{}".format(domain.name)
|
||||
alias = models.Alias.objects.create(
|
||||
address=address, domain=domain, enabled=True)
|
||||
alias.set_recipients([mb.full_address])
|
||||
alias.post_create(user)
|
||||
|
||||
domain.add_admin(da)
|
||||
return domain
|
||||
|
||||
|
||||
class DomainAliasSerializer(FlexFieldsModelSerializer):
|
||||
"""Base DomainAlias serializer."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user