mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-19 05:58:34 +02:00
WIP: relaydomain CRUD in new admin
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import repository from './repository'
|
||||
|
||||
const resource = 'transports'
|
||||
|
||||
export default {
|
||||
getAll () {
|
||||
return repository.get(`/${resource}/`)
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,9 @@
|
||||
<template v-slot:form.options="{ step }">
|
||||
<domain-options-form :ref="`form_${step}`" :domain="domain" @createAdmin="updateCreateAdmin" />
|
||||
</template>
|
||||
<template v-slot:form.transport="{ step }">
|
||||
<domain-transport-form :ref="`form_${step}`" :domain="domain" />
|
||||
</template>
|
||||
<template v-slot:item.with_random_password="{ item }">
|
||||
<template v-if="item.value">
|
||||
<v-col cols="12" class="highligth white--text">
|
||||
@@ -52,6 +55,7 @@ import DomainDNSForm from './DomainDNSForm'
|
||||
import DomainGeneralForm from './DomainGeneralForm'
|
||||
import DomainLimitationsForm from './DomainLimitationsForm'
|
||||
import DomainOptionsForm from './DomainOptionsForm'
|
||||
import DomainTransportForm from './DomainTransportForm'
|
||||
|
||||
export default {
|
||||
props: ['value'],
|
||||
@@ -60,7 +64,8 @@ export default {
|
||||
'domain-dns-form': DomainDNSForm,
|
||||
DomainGeneralForm,
|
||||
DomainLimitationsForm,
|
||||
DomainOptionsForm
|
||||
DomainOptionsForm,
|
||||
DomainTransportForm
|
||||
},
|
||||
computed: {
|
||||
summarySections () {
|
||||
@@ -87,12 +92,6 @@ export default {
|
||||
{ key: this.$gettext('Default mailbox quota'), value: this.domain.default_mailbox_quota },
|
||||
{ key: this.$gettext('Message sending limit'), value: this.domain.message_sending_limit }
|
||||
]
|
||||
},
|
||||
{
|
||||
title: this.$gettext('Options'),
|
||||
items: [
|
||||
{ key: this.$gettext('Create a domain administrator'), value: this.createAdmin, type: 'yesno' }
|
||||
]
|
||||
}
|
||||
]
|
||||
if (this.domain.enable_dkim) {
|
||||
@@ -100,25 +99,53 @@ export default {
|
||||
result[1].items.push({ key: this.$gettext('DKIM key length'), value: this.domain.dkim_key_length })
|
||||
}
|
||||
if (this.createAdmin) {
|
||||
result[3].items.push({ key: this.$gettext('Administrator name'), value: this.domain.domain_admin.username })
|
||||
result[3].items.push({
|
||||
name: 'with_random_password',
|
||||
key: this.$gettext('Random password'),
|
||||
value: this.domain.domain_admin.with_random_password,
|
||||
type: 'yesno'
|
||||
})
|
||||
result[3].items.push({
|
||||
key: this.$gettext('With mailbox'),
|
||||
value: this.domain.domain_admin.with_mailbox,
|
||||
type: 'yesno'
|
||||
})
|
||||
result[3].items.push({
|
||||
key: this.$gettext('Create aliases'),
|
||||
value: this.domain.domain_admin.with_aliases,
|
||||
type: 'yesno'
|
||||
result.push({
|
||||
title: this.$gettext('Options'),
|
||||
items: [
|
||||
{ key: this.$gettext('Create a domain administrator'), value: this.createAdmin, type: 'yesno' },
|
||||
{ key: this.$gettext('Administrator name'), value: this.domain.domain_admin.username },
|
||||
{
|
||||
name: 'with_random_password',
|
||||
key: this.$gettext('Random password'),
|
||||
value: this.domain.domain_admin.with_random_password,
|
||||
type: 'yesno'
|
||||
},
|
||||
{
|
||||
key: this.$gettext('With mailbox'),
|
||||
value: this.domain.domain_admin.with_mailbox,
|
||||
type: 'yesno'
|
||||
},
|
||||
{
|
||||
key: this.$gettext('Create aliases'),
|
||||
value: this.domain.domain_admin.with_aliases,
|
||||
type: 'yesno'
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
if (this.domain.type === 'relaydomain') {
|
||||
const relayEntry = {
|
||||
title: this.$gettext('Transport'),
|
||||
items: [
|
||||
{ key: this.$gettext('Service'), value: this.domain.transport.service }
|
||||
]
|
||||
}
|
||||
if (this.$refs.form_4.service) {
|
||||
const service = this.$refs.form_4.service
|
||||
for (const setting of service.settings) {
|
||||
const item = { key: setting.label, value: this.domain.transport.settings[`${service.name}_${setting.name}`] }
|
||||
if (setting.type === 'boolean') {
|
||||
item.type = 'yesno'
|
||||
}
|
||||
relayEntry.items.push(item)
|
||||
}
|
||||
}
|
||||
result.push(relayEntry)
|
||||
}
|
||||
return result
|
||||
},
|
||||
steps () {
|
||||
return this.domain.type === 'domain' ? this.domainSteps : this.relaySteps
|
||||
}
|
||||
},
|
||||
data () {
|
||||
@@ -128,11 +155,17 @@ export default {
|
||||
domain_admin: {}
|
||||
},
|
||||
formErrors: {},
|
||||
steps: [
|
||||
domainSteps: [
|
||||
{ name: 'general', title: this.$gettext('General') },
|
||||
{ name: 'dns', title: this.$gettext('DNS') },
|
||||
{ name: 'limitations', title: this.$gettext('Limitations') },
|
||||
{ name: 'options', title: this.$gettext('Options') }
|
||||
],
|
||||
relaySteps: [
|
||||
{ name: 'general', title: this.$gettext('General') },
|
||||
{ name: 'dns', title: this.$gettext('DNS') },
|
||||
{ name: 'limitations', title: this.$gettext('Limitations') },
|
||||
{ name: 'transport', title: this.$gettext('Transport') }
|
||||
]
|
||||
}
|
||||
},
|
||||
@@ -160,7 +193,8 @@ export default {
|
||||
with_random_password: false,
|
||||
with_mailbox: false,
|
||||
with_aliases: false
|
||||
}
|
||||
},
|
||||
transport: {}
|
||||
}
|
||||
},
|
||||
close () {
|
||||
|
||||
@@ -42,6 +42,14 @@
|
||||
<router-link :to="{ name: 'DomainDetail', params: { id: item.pk } }">
|
||||
{{ item.name }}
|
||||
</router-link>
|
||||
<v-chip
|
||||
v-if="item.type === 'relaydomain'"
|
||||
small
|
||||
color="primary"
|
||||
class="ml-2"
|
||||
>
|
||||
<translate>Relay</translate>
|
||||
</v-chip>
|
||||
<translate v-if="!item.enabled" class="ml-2 grey--text">(disabled)</translate>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div>
|
||||
<validation-observer ref="observer">
|
||||
<label class="m-label"><translate>Service</translate></label>
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
rules="required"
|
||||
>
|
||||
<v-autocomplete
|
||||
v-model="service"
|
||||
:items="backends"
|
||||
item-text="name"
|
||||
return-object
|
||||
outlined
|
||||
@change="resetForm"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</validation-provider>
|
||||
<template v-if="service">
|
||||
<template v-for="setting in service.settings">
|
||||
<div :key="setting.name">
|
||||
<validation-provider
|
||||
v-slot="{ errors }"
|
||||
:rules="setting.required ? 'required' : ''"
|
||||
>
|
||||
<template
|
||||
v-if="setting.type === 'str' || setting.type === 'int'"
|
||||
>
|
||||
<label class="m-label">{{ setting.label }}</label>
|
||||
<v-text-field
|
||||
v-model="domain.transport.settings[`${service.name}_${setting.name}`]"
|
||||
outlined
|
||||
:error-messages="errors"
|
||||
:type="setting.type === 'int' ? 'number' : 'text'"
|
||||
/>
|
||||
</template>
|
||||
<v-checkbox
|
||||
v-else-if="setting.type === 'boolean'"
|
||||
v-model="domain.transport.settings[`${service.name}_${setting.name}`]"
|
||||
:label="setting.label"
|
||||
:error-messages="errors"
|
||||
/>
|
||||
</validation-provider>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</validation-observer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import transports from '@/api/transports'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
domain: Object
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
backends: [],
|
||||
service: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
resetForm (value) {
|
||||
this.$set(this.domain, 'transport', { service: value.name, settings: {} })
|
||||
for (const setting of value.settings) {
|
||||
if (setting.default) {
|
||||
let defaultValue = setting.default
|
||||
if (setting.type === 'int') {
|
||||
defaultValue = parseInt(defaultValue)
|
||||
} else if (setting.type === 'boolean') {
|
||||
if (defaultValue === 'False') {
|
||||
defaultValue = false
|
||||
} else {
|
||||
defaultValue = true
|
||||
}
|
||||
}
|
||||
this.$set(this.domain.transport.settings, `${value.name}_${setting.name}`, defaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
transports.getAll().then(resp => {
|
||||
this.backends = resp.data
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -18,6 +18,8 @@ from modoboa.lib import fields as lib_fields
|
||||
from modoboa.lib import validators, web_utils
|
||||
from modoboa.lib.sysutils import exec_cmd
|
||||
from modoboa.parameters import tools as param_tools
|
||||
from modoboa.transport import models as transport_models
|
||||
from modoboa.transport.api.v2 import serializers as transport_serializers
|
||||
|
||||
from ... import constants, models
|
||||
|
||||
@@ -35,16 +37,31 @@ class DomainSerializer(v1_serializers.DomainSerializer):
|
||||
"""Domain serializer for v2 API."""
|
||||
|
||||
domain_admin = CreateDomainAdminSerializer(required=False)
|
||||
transport = transport_serializers.TransportSerializer(required=False)
|
||||
|
||||
class Meta(v1_serializers.DomainSerializer.Meta):
|
||||
fields = v1_serializers.DomainSerializer.Meta.fields + (
|
||||
"domain_admin",
|
||||
"domain_admin", "transport"
|
||||
)
|
||||
|
||||
def validate(self, data):
|
||||
result = super().validate(data)
|
||||
if data["type"] == "relaydomain" and not data.get("transport"):
|
||||
raise serializers.ValidationError({"transport": _("This field is required")})
|
||||
return result
|
||||
|
||||
def create(self, validated_data):
|
||||
"""Create administrator and other stuff if needed."""
|
||||
domain_admin = validated_data.pop("domain_admin", None)
|
||||
transport_def = validated_data.pop("transport", None)
|
||||
domain = super().create(validated_data)
|
||||
if transport_def:
|
||||
transport = transport_models.Transport(**transport_def)
|
||||
transport.pattern = domain.name
|
||||
transport.save()
|
||||
domain.transport = transport
|
||||
domain.save()
|
||||
|
||||
if not domain_admin:
|
||||
return domain
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Transport related serializers."""
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from ... import backends
|
||||
from ... import models
|
||||
|
||||
|
||||
class TransportBackendSettingSerializer(serializers.Serializer):
|
||||
"""Serializer for transport backend setting."""
|
||||
|
||||
name = serializers.CharField()
|
||||
label = serializers.CharField()
|
||||
type = serializers.CharField(default="str")
|
||||
required = serializers.BooleanField(default=True)
|
||||
default = serializers.CharField(default=None)
|
||||
|
||||
|
||||
class TransportBackendSerializer(serializers.Serializer):
|
||||
"""Serializer for transport backend."""
|
||||
|
||||
name = serializers.CharField()
|
||||
settings = TransportBackendSettingSerializer(many=True)
|
||||
|
||||
|
||||
class TransportSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for Transport model."""
|
||||
|
||||
settings = serializers.DictField(source="_settings")
|
||||
|
||||
class Meta:
|
||||
fields = ("service", "settings")
|
||||
model = models.Transport
|
||||
|
||||
def validate(self, data):
|
||||
self.backend = backends.manager.get_backend(data["service"])
|
||||
errors = {}
|
||||
for field, error in self.backend.clean_fields(data["_settings"]):
|
||||
errors[field] = error
|
||||
if errors:
|
||||
raise serializers.ValidationError(errors)
|
||||
return data
|
||||
@@ -0,0 +1,12 @@
|
||||
"""App related urls."""
|
||||
|
||||
from rest_framework import routers
|
||||
|
||||
from . import viewsets
|
||||
|
||||
|
||||
router = routers.SimpleRouter()
|
||||
router.register(
|
||||
r"transports", viewsets.TransportViewSet, basename="transport")
|
||||
|
||||
urlpatterns = router.urls
|
||||
@@ -0,0 +1,25 @@
|
||||
"""Transport related viewsets."""
|
||||
|
||||
from drf_spectacular.utils import extend_schema
|
||||
from rest_framework import permissions, response, viewsets
|
||||
|
||||
from . import serializers
|
||||
from ... import backends
|
||||
|
||||
|
||||
class TransportViewSet(viewsets.ViewSet):
|
||||
"""Viewset for Transport."""
|
||||
|
||||
permissions = (permissions.IsAuthenticated, )
|
||||
|
||||
@extend_schema(
|
||||
responses={200: serializers.TransportBackendSerializer}
|
||||
)
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""Return the list of all defined transport backends."""
|
||||
all_settings = backends.manager.get_all_backend_settings()
|
||||
result = []
|
||||
for name, settings in all_settings.items():
|
||||
serializer = serializers.TransportBackendSerializer({"name": name, "settings": settings})
|
||||
result.append(serializer.data)
|
||||
return response.Response(result)
|
||||
@@ -14,6 +14,7 @@ urlpatterns = [
|
||||
path('', include("modoboa.relaydomains.api.v1.urls")),
|
||||
path('', include("modoboa.dnstools.api.v2.urls")),
|
||||
path('', include("modoboa.maillog.api.v2.urls")),
|
||||
path('', include("modoboa.transport.api.v2.urls")),
|
||||
]
|
||||
|
||||
urlpatterns += exts_pool.get_urls(category="api")
|
||||
|
||||
Reference in New Issue
Block a user