From 4f2cbffd0b3cca2e440905c66b17de0c50911054 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Fri, 25 Mar 2022 09:55:06 +0100 Subject: [PATCH] Fixed transport update --- .../components/domains/DomainCreationForm.vue | 3 ++ .../src/components/domains/DomainForm.vue | 41 ++++++++++++++++++- .../domains/DomainTransportForm.vue | 11 +++++ modoboa/admin/api/v2/serializers.py | 26 +++++++++++- modoboa/admin/api/v2/tests.py | 27 ++++++++++++ modoboa/admin/api/v2/viewsets.py | 4 +- 6 files changed, 106 insertions(+), 6 deletions(-) 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):