diff --git a/frontend/src/components/domains/DomainCreationForm.vue b/frontend/src/components/domains/DomainCreationForm.vue
index d2291240c..f64c0f007 100644
--- a/frontend/src/components/domains/DomainCreationForm.vue
+++ b/frontend/src/components/domains/DomainCreationForm.vue
@@ -215,6 +215,9 @@ export default {
if (!this.createAdmin) {
delete data.domain_admin
}
+ if (data.type === 'relaydomain') {
+ this.$refs.form_4.checkSettingTypes(data)
+ }
this.$store.dispatch('domains/createDomain', data).then(resp => {
this.$router.push({ name: 'DomainDetail', params: { id: resp.data.pk } })
bus.$emit('notification', { msg: this.$gettext('Domain created') })
diff --git a/frontend/src/components/domains/DomainForm.vue b/frontend/src/components/domains/DomainForm.vue
index 91d59b351..35eb84811 100644
--- a/frontend/src/components/domains/DomainForm.vue
+++ b/frontend/src/components/domains/DomainForm.vue
@@ -104,6 +104,35 @@
+
+
+
+
+ Transport
+
+
+
+
+
+
+ Service: {{ editedDomain.transport.service }}
+
+
+
+
+
+
+
+
+
+
@@ -121,12 +150,14 @@ import { bus } from '@/main'
import DomainDNSForm from './DomainDNSForm'
import DomainGeneralForm from './DomainGeneralForm'
import DomainLimitationsForm from './DomainLimitationsForm'
+import DomainTransportForm from './DomainTransportForm'
export default {
components: {
'domain-dns-form': DomainDNSForm,
DomainGeneralForm,
- DomainLimitationsForm
+ DomainLimitationsForm,
+ DomainTransportForm
},
props: ['domain'],
data () {
@@ -143,6 +174,9 @@ export default {
return
}
}
+ if (this.editedDomain.type === 'relaydomain') {
+ this.$refs.transportForm.checkSettingTypes(this.editedDomain)
+ }
this.$store.dispatch('domains/updateDomain', this.editedDomain).then(resp => {
bus.$emit('notification', { msg: this.$gettext('Domain updated') })
})
@@ -156,6 +190,11 @@ export default {
}
},
immediate: true
+ },
+ 'editedDomain.type' (val) {
+ if (val === 'relaydomain' && this.editedDomain.transport === null) {
+ this.$set(this.editedDomain, 'transport', {})
+ }
}
}
}
diff --git a/frontend/src/components/domains/DomainTransportForm.vue b/frontend/src/components/domains/DomainTransportForm.vue
index a6839368c..7557996ac 100644
--- a/frontend/src/components/domains/DomainTransportForm.vue
+++ b/frontend/src/components/domains/DomainTransportForm.vue
@@ -79,11 +79,22 @@ export default {
this.$set(this.domain.transport.settings, `${value.name}_${setting.name}`, defaultValue)
}
}
+ },
+ checkSettingTypes (data) {
+ for (const setting of this.service.settings) {
+ if (setting.type === 'int') {
+ const fullName = `${this.service.name}_${setting.name}`
+ data.transport.settings[fullName] = parseInt(data.transport.settings[fullName])
+ }
+ }
}
},
mounted () {
transports.getAll().then(resp => {
this.backends = resp.data
+ if (this.domain) {
+ this.service = this.backends.find(backend => backend.name === this.domain.transport.service)
+ }
})
},
watch: {
diff --git a/modoboa/admin/api/v2/serializers.py b/modoboa/admin/api/v2/serializers.py
index ca08ecb11..3e15e5151 100644
--- a/modoboa/admin/api/v2/serializers.py
+++ b/modoboa/admin/api/v2/serializers.py
@@ -36,7 +36,7 @@ class CreateDomainAdminSerializer(serializers.Serializer):
class DomainSerializer(v1_serializers.DomainSerializer):
"""Domain serializer for v2 API."""
- domain_admin = CreateDomainAdminSerializer(required=False)
+ domain_admin = CreateDomainAdminSerializer(required=False, write_only=True)
transport = transport_serializers.TransportSerializer(required=False)
class Meta(v1_serializers.DomainSerializer.Meta):
@@ -46,7 +46,8 @@ class DomainSerializer(v1_serializers.DomainSerializer):
def validate(self, data):
result = super().validate(data)
- if data["type"] == "relaydomain" and not data.get("transport"):
+ dtype = data.get("type", "domain")
+ if dtype == "relaydomain" and not data.get("transport"):
raise serializers.ValidationError({"transport": _("This field is required")})
return result
@@ -116,6 +117,27 @@ class DomainSerializer(v1_serializers.DomainSerializer):
domain.add_admin(da)
return domain
+ def update(self, instance, validated_data):
+ """Update domain and create/update transport."""
+ transport_def = validated_data.pop("transport", None)
+ super().update(instance, validated_data)
+ if transport_def and instance.type == "relaydomain":
+ transport = getattr(instance, "transport", None)
+ created = False
+ if transport:
+ for key, value in transport_def.items():
+ setattr(instance, key, value)
+ transport._settings = transport_def["_settings"]
+ else:
+ transport = transport_models.Transport(**transport_def)
+ created = True
+ transport.pattern = instance.name
+ transport.save()
+ if created:
+ instance.transport = transport
+ instance.save()
+ return instance
+
class DeleteDomainSerializer(serializers.Serializer):
"""Serializer used with delete operation."""
diff --git a/modoboa/admin/api/v2/tests.py b/modoboa/admin/api/v2/tests.py
index 09b83a756..82c87bdd7 100644
--- a/modoboa/admin/api/v2/tests.py
+++ b/modoboa/admin/api/v2/tests.py
@@ -41,6 +41,33 @@ class DomainViewSetTestCase(ModoAPITestCase):
address="postmaster@domain.tld").exists()
)
+ def test_update(self):
+ domain = models.Domain.objects.get(name="test2.com")
+ data = {
+ "name": "test2.com",
+ "type": "relaydomain",
+ "transport": {
+ "service": "relay",
+ "settings": {
+ "relay_target_port": 25,
+ "relay_target_host": "localhost"
+ }
+ }
+ }
+ url = reverse("v2:domain-detail", args=[domain.pk])
+ resp = self.client.put(url, data, format="json")
+ self.assertEqual(resp.status_code, 200)
+ domain.refresh_from_db()
+ self.assertEqual(domain.transport.service, data["transport"]["service"])
+ self.assertEqual(
+ domain.transport._settings["relay_target_host"],
+ data["transport"]["settings"]["relay_target_host"]
+ )
+
+ data["transport"]["relay_verify_recipients"] = True
+ resp = self.client.put(url, data, format="json")
+ self.assertEqual(resp.status_code, 200)
+
def test_delete(self):
self.client.credentials(
HTTP_AUTHORIZATION="Token " + self.da_token.key)
diff --git a/modoboa/admin/api/v2/viewsets.py b/modoboa/admin/api/v2/viewsets.py
index bacdcf5b5..7527d7d27 100644
--- a/modoboa/admin/api/v2/viewsets.py
+++ b/modoboa/admin/api/v2/viewsets.py
@@ -58,15 +58,13 @@ class DomainViewSet(lib_viewsets.RevisionModelMixin,
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
if self.action == "administrators":
return serializers.DomainAdminSerializer
if self.action in ["add_administrator", "remove_administrator"]:
return serializers.SimpleDomainAdminSerializer
- return v1_serializers.DomainSerializer
+ return serializers.DomainSerializer
@action(methods=["post"], detail=True)
def delete(self, request, **kwargs):