mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Better domain update form.
This commit is contained in:
@@ -26,6 +26,9 @@ export default {
|
||||
updateDomain (domainId, data) {
|
||||
return repository.put(`/${domainResource}/${domainId}/`, data)
|
||||
},
|
||||
deleteDomain (domainId, data) {
|
||||
return repository.post(`/${domainResource}/${domainId}/delete/`, data)
|
||||
},
|
||||
createDomainAlias (data) {
|
||||
return repository.post(`/${domainAliasResource}/`, data)
|
||||
},
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<translate>Close</translate>
|
||||
</v-btn>
|
||||
<v-btn
|
||||
v-if="domainAlias.pk"
|
||||
v-if="domainAlias && domainAlias.pk"
|
||||
color="error"
|
||||
text
|
||||
@click="deleteAlias"
|
||||
@@ -73,7 +73,10 @@ import domains from '@/api/domains'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
domainAlias: Object
|
||||
domainAlias: {
|
||||
type: Object,
|
||||
default: () => null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
@@ -96,7 +99,9 @@ export default {
|
||||
methods: {
|
||||
close () {
|
||||
this.$emit('close')
|
||||
this.form = {}
|
||||
this.form = {
|
||||
enabled: true
|
||||
}
|
||||
},
|
||||
deleteAlias () {
|
||||
domains.deleteDomainAlias(this.domainAlias.pk).then(resp => {
|
||||
|
||||
@@ -31,35 +31,7 @@
|
||||
<translate class="grey--text text--darken-1">New domain</translate> /
|
||||
<translate>General</translate>
|
||||
</div>
|
||||
<validation-observer ref="observer_1">
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="required"
|
||||
>
|
||||
<v-text-field
|
||||
:label="'Domain name (ex: domain.tld)' | translate"
|
||||
v-model="domain.name"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
/>
|
||||
</validation-provider>
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="required"
|
||||
>
|
||||
<choice-field v-model="domain.type"
|
||||
:label="'Type' | translate"
|
||||
:choices="domainTypes"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</validation-provider>
|
||||
<v-switch
|
||||
:label="'Enabled' | translate"
|
||||
v-model="domain.enabled"
|
||||
:hint="'Control if this domain will be allowed to send and receive messages' | translate"
|
||||
persistent-hint
|
||||
/>
|
||||
</validation-observer>
|
||||
<domain-general-form ref="form_1" :domain="domain" />
|
||||
<div class="d-flex justify-end">
|
||||
<v-btn
|
||||
color="primary"
|
||||
@@ -75,26 +47,7 @@
|
||||
<translate class="grey--text text--darken-1">New domain</translate> /
|
||||
<translate>DNS</translate>
|
||||
</div>
|
||||
<v-switch
|
||||
:label="'Enable DNS checks' | translate"
|
||||
v-model="domain.enable_dns_checks"
|
||||
/>
|
||||
<v-switch
|
||||
:label="'Enable DKIM signing' | translate"
|
||||
v-model="domain.enable_dkim"
|
||||
/>
|
||||
<v-text-field
|
||||
:label="'DKIM key selector' | translate"
|
||||
v-model="domain.dkim_key_selector"
|
||||
:disabled="!domain.enable_dkim"
|
||||
outlined
|
||||
/>
|
||||
<choice-field
|
||||
v-model="domain.dkim_key_length"
|
||||
:label="'DKIM key length' | translate"
|
||||
:choices="dkimKeyLengths"
|
||||
:disabled="!domain.enable_dkim"
|
||||
/>
|
||||
<domain-dns-form ref="form_2" :domain="domain" />
|
||||
<div class="d-flex justify-end mt-8">
|
||||
<v-btn @click="step = 1" class="mr-10" text>
|
||||
<translate>Back</translate>
|
||||
@@ -113,49 +66,7 @@
|
||||
<translate class="grey--text text--darken-1">New domain</translate> /
|
||||
<translate>Limitations</translate>
|
||||
</div>
|
||||
<validation-observer ref="observer_3">
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
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. Leave empty for no limit.' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.message_sending_limit"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
/>
|
||||
</validation-provider>
|
||||
</validation-observer>
|
||||
<domain-limitations-form ref="form_3" :domain="domain" />
|
||||
<div class="d-flex justify-end mt-8">
|
||||
<v-btn @click="step = 2" class="mr-10" text>
|
||||
<translate>Back</translate>
|
||||
@@ -174,45 +85,7 @@
|
||||
<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"
|
||||
/>
|
||||
<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.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.domain_admin.with_aliases"
|
||||
:label="'Create aliases' | translate"
|
||||
:disabled="!createAdmin"
|
||||
:hint="'Create standard aliases for the domain.' | translate"
|
||||
persistent-hint
|
||||
/>
|
||||
|
||||
</validation-observer>
|
||||
<domain-options-form ref="form_4" :domain="domain" @createAdmin="updateCreateAdmin" />
|
||||
<div class="d-flex justify-end mt-8">
|
||||
<v-btn @click="step = 3" class="mr-10" text>
|
||||
<translate>Back</translate>
|
||||
@@ -324,14 +197,20 @@
|
||||
|
||||
<script>
|
||||
import { bus } from '@/main'
|
||||
import ChoiceField from '@/components/tools/ChoiceField'
|
||||
import ConfirmDialog from '@/components/layout/ConfirmDialog'
|
||||
import DomainDNSForm from './DomainDNSForm'
|
||||
import DomainGeneralForm from './DomainGeneralForm'
|
||||
import DomainLimitationsForm from './DomainLimitationsForm'
|
||||
import DomainOptionsForm from './DomainOptionsForm'
|
||||
|
||||
export default {
|
||||
props: ['value'],
|
||||
components: {
|
||||
ChoiceField,
|
||||
ConfirmDialog
|
||||
ConfirmDialog,
|
||||
'domain-dns-form': DomainDNSForm,
|
||||
DomainGeneralForm,
|
||||
DomainLimitationsForm,
|
||||
DomainOptionsForm
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
@@ -339,32 +218,6 @@ export default {
|
||||
domain: {
|
||||
domain_admin: {}
|
||||
},
|
||||
domainTypes: [
|
||||
{
|
||||
label: 'Domain',
|
||||
icon: 'mdi-earth',
|
||||
value: 'domain'
|
||||
},
|
||||
{
|
||||
label: 'Relay domain',
|
||||
icon: 'mdi-earth',
|
||||
value: 'relaydomain'
|
||||
}
|
||||
],
|
||||
dkimKeyLengths: [
|
||||
{
|
||||
label: '1024',
|
||||
value: 1024
|
||||
},
|
||||
{
|
||||
label: '2048',
|
||||
value: 2048
|
||||
},
|
||||
{
|
||||
label: '4096',
|
||||
value: 4096
|
||||
}
|
||||
],
|
||||
formErrors: {},
|
||||
step: 1
|
||||
}
|
||||
@@ -412,12 +265,15 @@ export default {
|
||||
this.$refs.observer_4.reset()
|
||||
},
|
||||
async goToNextStep (current, next) {
|
||||
const valid = await this.$refs[`observer_${current}`].validate()
|
||||
const valid = await this.$refs[`form_${current}`].$refs.observer.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
this.step = next
|
||||
},
|
||||
updateCreateAdmin (value) {
|
||||
this.createAdmin = value
|
||||
},
|
||||
submit () {
|
||||
const data = JSON.parse(JSON.stringify(this.domain))
|
||||
if (!this.createAdmin) {
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-switch
|
||||
:label="'Enable DNS checks' | translate"
|
||||
v-model="domain.enable_dns_checks"
|
||||
/>
|
||||
<v-switch
|
||||
:label="'Enable DKIM signing' | translate"
|
||||
v-model="domain.enable_dkim"
|
||||
/>
|
||||
<v-text-field
|
||||
:label="'DKIM key selector' | translate"
|
||||
v-model="domain.dkim_key_selector"
|
||||
:disabled="!domain.enable_dkim"
|
||||
outlined
|
||||
/>
|
||||
<choice-field
|
||||
v-model="domain.dkim_key_length"
|
||||
:label="'DKIM key length' | translate"
|
||||
:choices="dkimKeyLengths"
|
||||
:disabled="!domain.enable_dkim"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ChoiceField from '@/components/tools/ChoiceField'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChoiceField
|
||||
},
|
||||
props: ['domain'],
|
||||
data () {
|
||||
return {
|
||||
dkimKeyLengths: [
|
||||
{
|
||||
label: '1024',
|
||||
value: 1024
|
||||
},
|
||||
{
|
||||
label: '2048',
|
||||
value: 2048
|
||||
},
|
||||
{
|
||||
label: '4096',
|
||||
value: 4096
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -3,68 +3,122 @@
|
||||
<v-flex>
|
||||
<v-card>
|
||||
<v-card-title>
|
||||
<h1 class="title" v-if="!domain.pk">Add domain</h1>
|
||||
<h1 class="title" v-else>Edit domain</h1>
|
||||
<h1 class="headline"><translate>Edit domain</translate></h1>
|
||||
</v-card-title>
|
||||
<v-card-text>
|
||||
<v-text-field label="Name"
|
||||
v-model="domain.name"
|
||||
:error="formErrors['name'] !== undefined"
|
||||
:error-messages="formErrors['name']"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-select label="Type" :items="domainTypes" />
|
||||
<v-text-field label="Quota"
|
||||
v-model="domain.quota"
|
||||
suffix="MB"
|
||||
:error="formErrors['quota'] !== undefined"
|
||||
:error-messages="formErrors['quota']"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field label="Default mailbox quota"
|
||||
v-model="domain.default_mailbox_quota"
|
||||
suffix="MB"
|
||||
:error="formErrors['default_mailbox_quota']"
|
||||
:error-messages="formErrors['default_mailbox_quota']"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field label="Message sending limit"
|
||||
v-model="domain.message_limit"
|
||||
suffix="per day"
|
||||
:error="formErrors['message_limit']"
|
||||
:error-messages="formErrors['message_limit']"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-checkbox label="Enabled"
|
||||
v-model="domain.enabled"
|
||||
>
|
||||
</v-checkbox>
|
||||
<v-checkbox label="Enable DNS checks"
|
||||
v-model="domain.enable_dns_checks"
|
||||
>
|
||||
</v-checkbox>
|
||||
<v-checkbox label="Enable DKIM signing"
|
||||
v-model="domain.enable_dkim"
|
||||
>
|
||||
</v-checkbox>
|
||||
<v-text-field label="DKIM key selector"
|
||||
v-model="domain.dkim_key_selector"
|
||||
v-if="domain.enable_dkim"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-text-field label="DKIM key length"
|
||||
v-model="domain.dkim_key_length"
|
||||
v-if="domain.enable_dkim"
|
||||
>
|
||||
</v-text-field>
|
||||
<v-expansion-panels v-model="panel">
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-header v-slot="{ open }">
|
||||
<v-row no-gutters>
|
||||
<v-col cols="4">
|
||||
<translate>General</translate>
|
||||
</v-col>
|
||||
<v-col
|
||||
cols="8"
|
||||
class="text--secondary"
|
||||
>
|
||||
<v-fade-transition leave-absolute>
|
||||
<span v-if="open"></span>
|
||||
<v-row
|
||||
v-else
|
||||
no-gutters
|
||||
style="width: 100%"
|
||||
>
|
||||
<v-col cols="6">
|
||||
<translate>Name: </translate> {{ editedDomain.name }}
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
<translate>Type: </translate> {{ editedDomain.type }}
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-fade-transition>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<domain-general-form ref="generalForm" :domain="editedDomain" />
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-header v-slot="{ open }">
|
||||
<v-row no-gutters>
|
||||
<v-col cols="4">
|
||||
<translate>DNS</translate>
|
||||
</v-col>
|
||||
<v-col
|
||||
cols="8"
|
||||
class="text--secondary"
|
||||
>
|
||||
<v-fade-transition leave-absolute>
|
||||
<span v-if="open"></span>
|
||||
<v-row
|
||||
v-else
|
||||
no-gutters
|
||||
style="width: 100%"
|
||||
>
|
||||
<v-col cols="6">
|
||||
<translate class="mr-2">DNS checks</translate>
|
||||
<v-icon color="success" v-if="editedDomain.enable_dns_checks">mdi-check-circle-outline</v-icon>
|
||||
<v-icon v-else>mdi-close-circle-outline</v-icon>
|
||||
</v-col>
|
||||
<v-col cols="6">
|
||||
<translate class="mr-2">DKIM signing</translate>
|
||||
<v-icon color="success" v-if="editedDomain.enable_dkim">mdi-check-circle-outline</v-icon>
|
||||
<v-icon v-else>mdi-close-circle-outline</v-icon>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-fade-transition>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<domain-dns-form ref="dnsForm" :domain="editedDomain" />
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
<v-expansion-panel>
|
||||
<v-expansion-panel-header v-slot="{ open }">
|
||||
<v-row no-gutters>
|
||||
<v-col cols="4">
|
||||
<translate>Limitations</translate>
|
||||
</v-col>
|
||||
<v-col
|
||||
cols="8"
|
||||
class="text--secondary"
|
||||
>
|
||||
<v-fade-transition leave-absolute>
|
||||
<span v-if="open"></span>
|
||||
<v-row
|
||||
v-else
|
||||
no-gutters
|
||||
style="width: 100%"
|
||||
>
|
||||
<v-col cols="6">
|
||||
<translate class="mr-2">Quota: </translate> {{ domain.quota }}
|
||||
</v-col>
|
||||
<v-col cols="6" v-if="domain.message_sending_limit">
|
||||
<translate class="mr-2">Sending limit: </translate> {{ domain.message_sending_limit }}
|
||||
</v-col>
|
||||
<v-col cols="6" v-else>
|
||||
<translate class="mr-2">No sending limit</translate>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-fade-transition>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<domain-limitations-form :domain="editedDomain" />
|
||||
</v-expansion-panel-content>
|
||||
</v-expansion-panel>
|
||||
</v-expansion-panels>
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn color="blue darken-1" text @click="cancel">
|
||||
Cancel
|
||||
<v-btn color="grey darken-1" text @click="close">
|
||||
<translate>Cancel</translate>
|
||||
</v-btn>
|
||||
<v-btn color="blue darken-1" text @click="save">
|
||||
Save
|
||||
<v-btn color="primary darken-1" text @click="save">
|
||||
<translate>Save</translate>
|
||||
</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
@@ -73,63 +127,51 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { bus } from '@/main'
|
||||
import DomainDNSForm from './DomainDNSForm'
|
||||
import DomainGeneralForm from './DomainGeneralForm'
|
||||
import DomainLimitationsForm from './DomainLimitationsForm'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
'domain-dns-form': DomainDNSForm,
|
||||
DomainGeneralForm,
|
||||
DomainLimitationsForm
|
||||
},
|
||||
props: ['domain'],
|
||||
data () {
|
||||
return {
|
||||
formErrors: {},
|
||||
domain: {},
|
||||
domainTypes: ['Domain', 'Relay domain']
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
getDomainByPk: 'domains/getDomainByPk'
|
||||
})
|
||||
},
|
||||
mounted () {
|
||||
var domainPk = this.$route.params.domainPk
|
||||
if (domainPk) {
|
||||
if (!this.$store.state.domainsLoaded) {
|
||||
this.$store.dispatch('domains/getDomains').then(response => {
|
||||
this.loadDomain(domainPk)
|
||||
})
|
||||
} else {
|
||||
this.loadDomain(domainPk)
|
||||
}
|
||||
editedDomain: {},
|
||||
panel: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadDomain (pk) {
|
||||
this.domain = JSON.parse(
|
||||
JSON.stringify(this.getDomainByPk(pk))
|
||||
)
|
||||
close () {
|
||||
this.$emit('close')
|
||||
this.editedDomain = {}
|
||||
this.panel = 0
|
||||
},
|
||||
onSaveError (response) {
|
||||
this.formErrors = response.data
|
||||
},
|
||||
save () {
|
||||
var action
|
||||
var msg
|
||||
if (this.domain.pk) {
|
||||
action = 'domains/updateDomain'
|
||||
msg = 'Domain updated.'
|
||||
} else {
|
||||
action = 'domains/createDomain'
|
||||
msg = 'Domain created.'
|
||||
async save () {
|
||||
if (this.$refs.generalForm !== undefined) {
|
||||
const valid = await this.$refs.generalForm.$refs.observer.validate()
|
||||
if (!valid) {
|
||||
return
|
||||
}
|
||||
}
|
||||
this.$store.dispatch(action, this.domain).then(response => {
|
||||
this.$router.push({ name: 'DomainList' })
|
||||
this.$toast.open({
|
||||
message: msg,
|
||||
type: 'is-success',
|
||||
position: 'is-bottom'
|
||||
})
|
||||
}, this.onSaveError)
|
||||
},
|
||||
cancel () {
|
||||
this.$router.push({ name: 'DomainList' })
|
||||
this.$store.dispatch('domains/updateDomain', this.editedDomain).then(resp => {
|
||||
this.close()
|
||||
bus.$emit('notification', { msg: this.$gettext('Domain updated') })
|
||||
})
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
domain: {
|
||||
handler: function (val) {
|
||||
if (val) {
|
||||
this.editedDomain = JSON.parse(JSON.stringify(val))
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<validation-observer ref="observer">
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="required"
|
||||
>
|
||||
<v-text-field
|
||||
:label="'Domain name (ex: domain.tld)' | translate"
|
||||
v-model="domain.name"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
/>
|
||||
</validation-provider>
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="required"
|
||||
>
|
||||
<choice-field v-model="domain.type"
|
||||
:label="'Type' | translate"
|
||||
:choices="domainTypes"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</validation-provider>
|
||||
<v-switch
|
||||
:label="'Enabled' | translate"
|
||||
v-model="domain.enabled"
|
||||
:hint="'Control if this domain will be allowed to send and receive messages' | translate"
|
||||
persistent-hint
|
||||
/>
|
||||
</validation-observer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ChoiceField from '@/components/tools/ChoiceField'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChoiceField
|
||||
},
|
||||
props: ['domain'],
|
||||
data () {
|
||||
return {
|
||||
domainTypes: [
|
||||
{
|
||||
label: 'Domain',
|
||||
icon: 'mdi-earth',
|
||||
value: 'domain'
|
||||
},
|
||||
{
|
||||
label: 'Relay domain',
|
||||
icon: 'mdi-earth',
|
||||
value: 'relaydomain'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<validation-observer ref="observer">
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
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. Leave empty for no limit.' | translate"
|
||||
persistent-hint
|
||||
v-model="domain.message_sending_limit"
|
||||
:error-messages="errors"
|
||||
outlined
|
||||
/>
|
||||
</validation-provider>
|
||||
</validation-observer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['domain']
|
||||
}
|
||||
</script>
|
||||
@@ -75,7 +75,7 @@
|
||||
</v-btn>
|
||||
</template>
|
||||
<v-list dense>
|
||||
<v-list-item :to="{ name: 'DomainEdit', params: { domainPk: item.pk }}">
|
||||
<v-list-item @click="editDomain(item)">
|
||||
<v-list-item-icon>
|
||||
<v-icon>mdi-circle-edit-outline</v-icon>
|
||||
</v-list-item-icon>
|
||||
@@ -117,6 +117,12 @@
|
||||
max-width="800px">
|
||||
<dns-detail @close="showDNSdetail = false" :domain="selectedDomain" />
|
||||
</v-dialog>
|
||||
<v-dialog v-model="showDomainForm"
|
||||
persistent
|
||||
max-width="800px"
|
||||
>
|
||||
<domain-form :domain="selectedDomain" @close="showDomainForm = false" />
|
||||
</v-dialog>
|
||||
<v-dialog v-model="showAliasForm"
|
||||
persistent
|
||||
max-width="800px">
|
||||
@@ -131,16 +137,19 @@
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { bus } from '@/main'
|
||||
import domainApi from '@/api/domains'
|
||||
import ConfirmDialog from '@/components/layout/ConfirmDialog'
|
||||
import DNSDetail from '@/components/domains/DNSDetail'
|
||||
import DomainAliasForm from '@/components/domains/DomainAliasForm'
|
||||
import DomainForm from '@/components/domains/DomainForm'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ConfirmDialog,
|
||||
'dns-detail': DNSDetail,
|
||||
DomainAliasForm
|
||||
DomainAliasForm,
|
||||
DomainForm
|
||||
},
|
||||
computed: mapGetters({
|
||||
domains: 'domains/domains'
|
||||
@@ -160,6 +169,7 @@ export default {
|
||||
showConfirmDialog: false,
|
||||
showAliasForm: false,
|
||||
showDNSdetail: false,
|
||||
showDomainForm: false,
|
||||
search: '',
|
||||
selected: [],
|
||||
expanded: [],
|
||||
@@ -175,12 +185,8 @@ export default {
|
||||
this.selectedDomain = null
|
||||
this.selectedDomainAlias = null
|
||||
},
|
||||
confirmDelete (domain) {
|
||||
this.selectedDomain = domain
|
||||
this.showConfirmDialog = true
|
||||
},
|
||||
async deleteDomain (domain) {
|
||||
await this.$refs.confirm.open(
|
||||
const confirm = await this.$refs.confirm.open(
|
||||
this.$gettext('Warning'),
|
||||
this.$gettext(`Do you really want to delete the domain ${domain.name}?`),
|
||||
{
|
||||
@@ -189,6 +195,12 @@ export default {
|
||||
agreeLabel: this.$gettext('Yes')
|
||||
}
|
||||
)
|
||||
if (!confirm) {
|
||||
return
|
||||
}
|
||||
this.$store.dispatch('domains/deleteDomain', { id: domain.pk }).then(resp => {
|
||||
bus.$emit('notification', { msg: this.$gettext('Domain delete') })
|
||||
})
|
||||
},
|
||||
domainAliasDeleted () {
|
||||
const newList = this.aliases[this.selectedDomain.name].filter(alias => {
|
||||
@@ -197,6 +209,10 @@ export default {
|
||||
this.$set(this.aliases, this.selectedDomain.name, newList)
|
||||
this.closeDomainAliasForm()
|
||||
},
|
||||
editDomain (domain) {
|
||||
this.selectedDomain = domain
|
||||
this.showDomainForm = true
|
||||
},
|
||||
editDomainAlias (domain, alias) {
|
||||
this.selectedDomain = domain
|
||||
this.selectedDomainAlias = alias
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<validation-observer ref="observer">
|
||||
<v-switch v-model="createAdmin"
|
||||
:label="'Create a domain administrator' | translate"
|
||||
@change="update"
|
||||
/>
|
||||
<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.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.domain_admin.with_aliases"
|
||||
:label="'Create aliases' | translate"
|
||||
:disabled="!createAdmin"
|
||||
:hint="'Create standard aliases for the domain.' | translate"
|
||||
persistent-hint
|
||||
/>
|
||||
</validation-observer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: ['domain'],
|
||||
data () {
|
||||
return {
|
||||
createAdmin: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update (val) {
|
||||
this.$emit('createAdmin', val)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -5,6 +5,7 @@ import domainApi from '@/api/domains'
|
||||
const SET_DOMAINS = 'SET_DOMAINS'
|
||||
const ADD_DOMAIN = 'ADD_DOMAIN'
|
||||
const UPDATE_DOMAIN = 'UPDATE_DOMAIN'
|
||||
const DELETE_DOMAIN = 'DELETE_DOMAIN'
|
||||
const SET_DOMAIN_ALIASES = 'SET_DOMAIN_ALIASES'
|
||||
const ADD_DOMAIN_ALIAS = 'ADD_DOMAIN_ALIAS'
|
||||
const UPDATE_DOMAIN_ALIAS = 'UPDATE_DOMAIN_ALIAS'
|
||||
@@ -48,6 +49,11 @@ const actions = {
|
||||
commit(UPDATE_DOMAIN, { domain: response.data })
|
||||
})
|
||||
},
|
||||
deleteDomain ({ commit }, { id, data }) {
|
||||
return domainApi.deleteDomain(id, data).then(resp => {
|
||||
commit(DELETE_DOMAIN, id)
|
||||
})
|
||||
},
|
||||
getDomainAliases ({ commit }) {
|
||||
return Vue.prototype.$axios.get('/domainaliases/?expand=target').then(response => {
|
||||
commit(SET_DOMAIN_ALIASES, response.data)
|
||||
@@ -86,6 +92,9 @@ const mutations = {
|
||||
}
|
||||
})
|
||||
},
|
||||
[DELETE_DOMAIN] (state, domainId) {
|
||||
state.domains = state.domains.filter(item => item.pk !== domainId)
|
||||
},
|
||||
[SET_DOMAIN_ALIASES] (state, domainAliases) {
|
||||
state.domainAliases = domainAliases
|
||||
},
|
||||
|
||||
@@ -24,7 +24,7 @@ from modoboa.lib import (
|
||||
)
|
||||
from modoboa.parameters import tools as param_tools
|
||||
|
||||
from . import constants, lib, models
|
||||
from ... import lib, models
|
||||
|
||||
|
||||
class DomainSerializer(serializers.ModelSerializer):
|
||||
@@ -110,85 +110,6 @@ 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."""
|
||||
|
||||
@@ -571,28 +492,6 @@ class SenderAddressSerializer(serializers.ModelSerializer):
|
||||
return value
|
||||
|
||||
|
||||
class AdminGlobalParametersSerializer(serializers.Serializer):
|
||||
"""A serializer for global parameters."""
|
||||
|
||||
# Domain settings
|
||||
enable_mx_checks = serializers.BooleanField(default=True)
|
||||
valid_mxs = serializers.CharField(allow_blank=True)
|
||||
domains_must_have_authorized_mx = serializers.BooleanField(default=False)
|
||||
enable_dnsbl_checks = serializers.BooleanField(default=True)
|
||||
dkim_keys_storage_dir = serializers.CharField(allow_blank=True)
|
||||
dkim_default_key_length = serializers.ChoiceField(
|
||||
default=2048, choices=constants.DKIM_KEY_LENGTHS)
|
||||
|
||||
# Mailboxes settings
|
||||
handle_mailboxes = serializers.BooleanField(default=False)
|
||||
mailboxes_owner = serializers.CharField(default="vmail")
|
||||
default_domain_quota = serializers.IntegerField(default=0)
|
||||
default_mailbox_quota = serializers.IntegerField(default=0)
|
||||
auto_account_removal = serializers.BooleanField(default=False)
|
||||
auto_create_domain_and_mailbox = serializers.BooleanField(default=True)
|
||||
create_alias_on_mbox_rename = serializers.BooleanField(default=False)
|
||||
|
||||
|
||||
class ResetPasswordSerializer(serializers.Serializer):
|
||||
"""Serializer by the reset password endpoint."""
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
"""Admin API urls."""
|
||||
|
||||
from rest_framework import routers
|
||||
|
||||
from . import viewsets
|
||||
|
||||
router = routers.SimpleRouter()
|
||||
router.register(r"domains", viewsets.DomainViewSet, basename="domain")
|
||||
router.register(
|
||||
r"domainaliases", viewsets.DomainAliasViewSet, basename="domain_alias")
|
||||
router.register(r"accounts", viewsets.AccountViewSet, basename="account")
|
||||
router.register(r"aliases", viewsets.AliasViewSet, basename="alias")
|
||||
router.register(
|
||||
r"senderaddresses", viewsets.SenderAddressViewSet, basename="sender_address")
|
||||
|
||||
urlpatterns = router.urls
|
||||
@@ -17,7 +17,8 @@ from modoboa.core import sms_backends
|
||||
from modoboa.lib import renderers as lib_renderers
|
||||
from modoboa.lib import viewsets as lib_viewsets
|
||||
|
||||
from . import lib, models, serializers
|
||||
from ... import lib, models
|
||||
from . import serializers
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
@@ -38,16 +39,12 @@ class DomainViewSet(lib_viewsets.RevisionModelMixin, 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)
|
||||
@@ -0,0 +1,118 @@
|
||||
"""Admin API v2 serializers."""
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from modoboa.admin.api.v1 import serializers as v1_serializers
|
||||
from modoboa.core import models as core_models, signals as core_signals
|
||||
from modoboa.lib import exceptions as lib_exceptions
|
||||
from modoboa.parameters import tools as param_tools
|
||||
|
||||
from ... import constants, lib, models
|
||||
|
||||
|
||||
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 DomainSerializer(v1_serializers.DomainSerializer):
|
||||
"""Domain serializer for v2 API."""
|
||||
|
||||
domain_admin = CreateDomainAdminSerializer(required=False)
|
||||
|
||||
class Meta(v1_serializers.DomainSerializer.Meta):
|
||||
fields = v1_serializers.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 DeleteDomainSerializer(serializers.Serializer):
|
||||
"""Serializer used with delete operation."""
|
||||
|
||||
keep_folder = serializers.BooleanField(default=False)
|
||||
|
||||
|
||||
class AdminGlobalParametersSerializer(serializers.Serializer):
|
||||
"""A serializer for global parameters."""
|
||||
|
||||
# Domain settings
|
||||
enable_mx_checks = serializers.BooleanField(default=True)
|
||||
valid_mxs = serializers.CharField(allow_blank=True)
|
||||
domains_must_have_authorized_mx = serializers.BooleanField(default=False)
|
||||
enable_dnsbl_checks = serializers.BooleanField(default=True)
|
||||
dkim_keys_storage_dir = serializers.CharField(allow_blank=True)
|
||||
dkim_default_key_length = serializers.ChoiceField(
|
||||
default=2048, choices=constants.DKIM_KEY_LENGTHS)
|
||||
|
||||
# Mailboxes settings
|
||||
handle_mailboxes = serializers.BooleanField(default=False)
|
||||
default_domain_quota = serializers.IntegerField(default=0)
|
||||
default_mailbox_quota = serializers.IntegerField(default=0)
|
||||
auto_account_removal = serializers.BooleanField(default=False)
|
||||
auto_create_domain_and_mailbox = serializers.BooleanField(default=True)
|
||||
create_alias_on_mbox_rename = serializers.BooleanField(default=False)
|
||||
@@ -0,0 +1,19 @@
|
||||
"""Admin API v2 urls."""
|
||||
|
||||
from rest_framework import routers
|
||||
|
||||
from modoboa.admin.api.v1 import viewsets as v1_viewsets
|
||||
|
||||
from . import viewsets
|
||||
|
||||
router = routers.SimpleRouter()
|
||||
router.register(r"domains", viewsets.DomainViewSet, basename="domain")
|
||||
router.register(
|
||||
r"domainaliases", v1_viewsets.DomainAliasViewSet, basename="domain_alias")
|
||||
router.register(r"accounts", v1_viewsets.AccountViewSet, basename="account")
|
||||
router.register(r"aliases", v1_viewsets.AliasViewSet, basename="alias")
|
||||
router.register(
|
||||
r"senderaddresses", v1_viewsets.SenderAddressViewSet,
|
||||
basename="sender_address")
|
||||
|
||||
urlpatterns = router.urls
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Admin API v2 viewsets."""
|
||||
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||
from rest_framework import mixins, permissions, response, status, viewsets
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.exceptions import PermissionDenied
|
||||
|
||||
from modoboa.admin.api.v1 import serializers as v1_serializers
|
||||
from modoboa.lib import viewsets as lib_viewsets
|
||||
|
||||
from ... import models
|
||||
from . import serializers
|
||||
|
||||
|
||||
@extend_schema_view(
|
||||
retrieve=extend_schema(
|
||||
description="Retrieve a particular domain",
|
||||
summary="Retrieve a particular domain"
|
||||
),
|
||||
list=extend_schema(
|
||||
description="Retrieve a list of domains",
|
||||
summary="Retrieve a list of domains"
|
||||
),
|
||||
create=extend_schema(
|
||||
description="Create a new domain",
|
||||
summary="Create a new domain"
|
||||
),
|
||||
delete=extend_schema(
|
||||
description="Delete a particular domain",
|
||||
summary="Delete a particular domain"
|
||||
)
|
||||
)
|
||||
class DomainViewSet(lib_viewsets.RevisionModelMixin,
|
||||
mixins.ListModelMixin,
|
||||
mixins.RetrieveModelMixin,
|
||||
mixins.CreateModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
viewsets.GenericViewSet):
|
||||
"""V2 viewset."""
|
||||
|
||||
permission_classes = (
|
||||
permissions.IsAuthenticated, permissions.DjangoModelPermissions,
|
||||
)
|
||||
|
||||
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.action == "create":
|
||||
return serializers.DomainSerializer
|
||||
if self.action == "delete":
|
||||
return serializers.DeleteDomainSerializer
|
||||
return v1_serializers.DomainSerializer
|
||||
|
||||
@action(methods=["post"], detail=True)
|
||||
def delete(self, request, **kwargs):
|
||||
"""Custom delete method that accepts body arguments."""
|
||||
domain = self.get_object()
|
||||
if not request.user.can_access(domain):
|
||||
raise PermissionDenied(_("You don't have access to this domain"))
|
||||
mb = getattr(request.user, "mailbox", None)
|
||||
if mb and mb.domain == domain:
|
||||
raise PermissionDenied(_("You can't delete your own domain"))
|
||||
serializer = self.get_serializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
domain.delete(request.user, serializer.validated_data["keep_folder"])
|
||||
return response.Response(status=status.HTTP_204_NO_CONTENT)
|
||||
@@ -385,7 +385,7 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([
|
||||
def load_admin_settings():
|
||||
"""Load admin settings."""
|
||||
from modoboa.parameters import tools as param_tools
|
||||
from . import serializers
|
||||
from .api.v2 import serializers
|
||||
|
||||
param_tools.registry.add(
|
||||
"global", AdminParametersForm, ugettext_lazy("Administration"))
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
"""Admin API urls."""
|
||||
|
||||
from rest_framework import routers
|
||||
|
||||
from . import api
|
||||
|
||||
router = routers.SimpleRouter()
|
||||
router.register(r"domains", api.DomainViewSet, basename="domain")
|
||||
router.register(
|
||||
r"domainaliases", api.DomainAliasViewSet, basename="domain_alias")
|
||||
router.register(r"accounts", api.AccountViewSet, basename="account")
|
||||
router.register(r"aliases", api.AliasViewSet, basename="alias")
|
||||
router.register(
|
||||
r"senderaddresses", api.SenderAddressViewSet, basename="sender_address")
|
||||
|
||||
urlpatterns = router.urls
|
||||
@@ -3,7 +3,7 @@
|
||||
from rest_framework import permissions, response, viewsets
|
||||
from rest_framework.decorators import action
|
||||
|
||||
from modoboa.admin import serializers as admin_serializers
|
||||
from modoboa.admin.api.v1 import serializers as admin_v1_serializers
|
||||
from modoboa.core.api.v1 import viewsets as core_v1_viewsets
|
||||
|
||||
from ... import models
|
||||
@@ -16,7 +16,7 @@ class AccountViewSet(core_v1_viewsets.AccountViewSet):
|
||||
@action(methods=["get"], detail=False)
|
||||
def me(self, request):
|
||||
"""Return information about connected user."""
|
||||
serializer = admin_serializers.AccountSerializer(request.user)
|
||||
serializer = admin_v1_serializers.AccountSerializer(request.user)
|
||||
return response.Response(serializer.data)
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ app_name = "api"
|
||||
|
||||
urlpatterns = [
|
||||
path('', include("modoboa.core.api.v1.urls")),
|
||||
path('', include("modoboa.admin.urls_api")),
|
||||
path('', include("modoboa.admin.api.v1.urls")),
|
||||
path('', include("modoboa.limits.urls_api")),
|
||||
path('', include("modoboa.relaydomains.urls_api"))
|
||||
]
|
||||
|
||||
@@ -16,7 +16,7 @@ urlpatterns = [
|
||||
path('token/refresh/', TokenRefreshView.as_view(),
|
||||
name='token_refresh'),
|
||||
path('', include("modoboa.core.api.v2.urls")),
|
||||
path('', include("modoboa.admin.urls_api")),
|
||||
path('', include("modoboa.admin.api.v2.urls")),
|
||||
path('', include("modoboa.parameters.api.v2.urls")),
|
||||
path('', include("modoboa.limits.urls_api")),
|
||||
path('', include("modoboa.relaydomains.urls_api")),
|
||||
|
||||
Reference in New Issue
Block a user