From 39034859700902339d8c0fd05d30cc1d34afeee8 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Tue, 19 Dec 2017 11:25:02 +0100 Subject: [PATCH] New sender address API. see #1331 --- modoboa/admin/api.py | 17 +++++++ modoboa/admin/factories.py | 9 ++++ modoboa/admin/serializers.py | 30 ++++++++++- modoboa/admin/tests/test_api.py | 89 +++++++++++++++++++++++++++++++++ modoboa/admin/urls_api.py | 2 + modoboa/core/constants.py | 10 +++- 6 files changed, 154 insertions(+), 3 deletions(-) diff --git a/modoboa/admin/api.py b/modoboa/admin/api.py index 9e493ae43..a0e91e439 100644 --- a/modoboa/admin/api.py +++ b/modoboa/admin/api.py @@ -146,3 +146,20 @@ class AliasViewSet(viewsets.ModelViewSet): if domain: queryset = queryset.filter(domain__name=domain) return queryset + + +class SenderAddressViewSet(viewsets.ModelViewSet): + """View set for SenderAddress model.""" + + permission_classes = [IsAuthenticated, DjangoModelPermissions, ] + serializer_class = serializers.SenderAddressSerializer + + def get_queryset(self): + """Filter queryset based on current user.""" + user = self.request.user + mb_ids = ( + user.objectaccess_set.filter( + content_type=ContentType.objects.get_for_model(models.Mailbox)) + .values_list("object_id", flat=True) + ) + return models.SenderAddress.objects.filter(mailbox__pk__in=mb_ids) diff --git a/modoboa/admin/factories.py b/modoboa/admin/factories.py index 2aa5112c9..b62ba877a 100644 --- a/modoboa/admin/factories.py +++ b/modoboa/admin/factories.py @@ -63,6 +63,15 @@ class AliasFactory(PermissionFactory): enabled = True +class SenderAddressFactory(factory.django.DjangoModelFactory): + """Factory for SenderAddress model.""" + + mailbox = factory.SubFactory(MailboxFactory) + + class Meta: + model = models.SenderAddress + + def populate_database(): """Create test data. diff --git a/modoboa/admin/serializers.py b/modoboa/admin/serializers.py index e73892155..2759f0a18 100644 --- a/modoboa/admin/serializers.py +++ b/modoboa/admin/serializers.py @@ -105,7 +105,7 @@ class MailboxSerializer(serializers.ModelSerializer): class Meta: model = models.Mailbox - fields = ("full_address", "use_domain_quota", "quota", ) + fields = ("pk", "full_address", "use_domain_quota", "quota", ) class AccountSerializer(serializers.ModelSerializer): @@ -386,3 +386,31 @@ class AliasSerializer(serializers.ModelSerializer): instance.save() instance.set_recipients(recipients) return instance + + +class SenderAddressSerializer(serializers.ModelSerializer): + """Base Alias serializer.""" + + address = lib_fields.DRFEmailFieldUTF8AndEmptyUser() + + class Meta: + model = admin_models.SenderAddress + fields = ("pk", "address", "mailbox") + + def validate_address(self, value): + """Check domain.""" + local_part, domain = email_utils.split_mailbox(value) + domain = admin_models.Domain.objects.filter(name=domain).first() + user = self.context["request"].user + if domain and not user.can_access(domain): + raise serializers.ValidationError( + _("You don't have access to this domain.")) + return value + + def validate_mailbox(self, value): + """Check permission.""" + user = self.context["request"].user + if not user.can_access(value): + raise serializers.ValidationError( + _("You don't have access to this mailbox.")) + return value diff --git a/modoboa/admin/tests/test_api.py b/modoboa/admin/tests/test_api.py index 3e897ce18..6b0c0fbca 100644 --- a/modoboa/admin/tests/test_api.py +++ b/modoboa/admin/tests/test_api.py @@ -281,6 +281,7 @@ class AccountAPITestCase(ModoAPITestCase): self.assertIsNot(user.mailbox, None) domadmin = core_models.User.objects.get(username="admin@test.com") self.assertTrue(domadmin.can_access(user)) + self.assertIn("pk", account["mailbox"]) data = copy.deepcopy(self.ACCOUNT_DATA) data["username"] = "fromapi_ééé@test.com" @@ -660,3 +661,91 @@ class AliasAPITestCase(ModoAPITestCase): address="user@test.com", alias__address="alias@test.com") .exists() ) + + +class SenderAddressAPITestCase(ModoAPITestCase): + """Check SenderAddress API.""" + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(SenderAddressAPITestCase, cls).setUpTestData() + cls.localconfig.parameters.set_value( + "enable_admin_limits", False, app="limits") + cls.localconfig.save() + factories.populate_database() + cls.sa1 = factories.SenderAddressFactory( + address="test@domain.ext", + mailbox__user__username="user@test.com", + mailbox__address="user", + mailbox__domain__name="test.com" + ) + cls.da_token = Token.objects.create( + user=core_models.User.objects.get(username="admin@test.com")) + + def test_list(self): + """Retrieve a list of sender addresses.""" + url = reverse("api:sender_address-list") + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + response = response.json() + self.assertEqual(len(response), 1) + + def test_create(self): + """Create a new sender addresses.""" + url = reverse("api:sender_address-list") + mbox = models.Mailbox.objects.get( + address="admin", domain__name="test.com") + data = {"address": "@extdomain.test", "mailbox": mbox.pk} + response = self.client.post(url, data) + self.assertEqual(response.status_code, 201) + + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.da_token.key) + data = {"address": "user@test2.com", "mailbox": mbox.pk} + response = self.client.post(url, data) + self.assertEqual(response.status_code, 400) + self.assertEqual( + response.json()["address"][0], + "You don't have access to this domain.") + + mbox = models.Mailbox.objects.get( + address="admin", domain__name="test2.com") + data = {"address": "toto@titi.com", "mailbox": mbox.pk} + response = self.client.post(url, data) + self.assertEqual(response.status_code, 400) + self.assertEqual( + response.json()["mailbox"][0], + "You don't have access to this mailbox.") + + def test_patch(self): + """Patch an existing sender address.""" + url = reverse("api:sender_address-detail", args=[self.sa1.pk]) + mbox = models.Mailbox.objects.get( + address="user", domain__name="test.com") + data = {"address": "@extdomain.test"} + response = self.client.patch(url, data) + self.assertEqual(response.status_code, 200) + self.sa1.refresh_from_db() + self.assertEqual(self.sa1.mailbox, mbox) + self.assertEqual(self.sa1.address, data["address"]) + + def test_update(self): + """Update an existing sender address.""" + url = reverse("api:sender_address-detail", args=[self.sa1.pk]) + mbox = models.Mailbox.objects.get( + address="user", domain__name="test.com") + data = {"address": "@extdomain.test", "mailbox": mbox.pk} + response = self.client.put(url, data) + self.assertEqual(response.status_code, 200) + self.sa1.refresh_from_db() + self.assertEqual(self.sa1.mailbox, mbox) + self.assertEqual(self.sa1.address, data["address"]) + + def test_delete(self): + """Delete an existing sender address.""" + url = reverse("api:sender_address-detail", args=[self.sa1.pk]) + response = self.client.delete(url) + self.assertEqual(response.status_code, 204) + with self.assertRaises(models.SenderAddress.DoesNotExist): + self.sa1.refresh_from_db() diff --git a/modoboa/admin/urls_api.py b/modoboa/admin/urls_api.py index 1f0f9f0d4..92e41b86c 100644 --- a/modoboa/admin/urls_api.py +++ b/modoboa/admin/urls_api.py @@ -13,5 +13,7 @@ router.register( r"domainaliases", api.DomainAliasViewSet, base_name="domain_alias") router.register(r"accounts", api.AccountViewSet, base_name="account") router.register(r"aliases", api.AliasViewSet, base_name="alias") +router.register( + r"senderaddresses", api.SenderAddressViewSet, base_name="sender_address") urlpatterns = router.urls diff --git a/modoboa/core/constants.py b/modoboa/core/constants.py index e791768e0..ae8587aa3 100644 --- a/modoboa/core/constants.py +++ b/modoboa/core/constants.py @@ -64,11 +64,14 @@ PERMISSIONS = { ["admin", "mailbox", "add_mailbox"], ["admin", "mailbox", "change_mailbox"], ["admin", "mailbox", "delete_mailbox"], + ["admin", "mailbox", "view_mailboxes"], ["admin", "alias", "add_alias"], ["admin", "alias", "change_alias"], ["admin", "alias", "delete_alias"], - ["admin", "mailbox", "view_mailboxes"], ["admin", "alias", "view_aliases"], + ["admin", "senderaddress", "add_senderaddress"], + ["admin", "senderaddress", "change_senderaddress"], + ["admin", "senderaddress", "delete_senderaddress"], ], "Resellers": [ ["core", "user", "add_user"], @@ -79,11 +82,14 @@ PERMISSIONS = { ["admin", "mailbox", "add_mailbox"], ["admin", "mailbox", "change_mailbox"], ["admin", "mailbox", "delete_mailbox"], + ["admin", "mailbox", "view_mailboxes"], ["admin", "alias", "add_alias"], ["admin", "alias", "change_alias"], ["admin", "alias", "delete_alias"], - ["admin", "mailbox", "view_mailboxes"], ["admin", "alias", "view_aliases"], + ["admin", "senderaddress", "add_senderaddress"], + ["admin", "senderaddress", "change_senderaddress"], + ["admin", "senderaddress", "delete_senderaddress"], ["admin", "domain", "view_domains"], ["admin", "domain", "add_domain"], ["admin", "domain", "change_domain"],