diff --git a/modoboa/admin/api.py b/modoboa/admin/api.py index d72e082b9..1bbca82ae 100644 --- a/modoboa/admin/api.py +++ b/modoboa/admin/api.py @@ -29,6 +29,17 @@ class DomainViewSet(viewsets.ModelViewSet): instance.delete(self.request.user) +class DomainAliasViewSet(viewsets.ModelViewSet): + """ViewSet for DomainAlias.""" + + permission_classes = [DjangoModelPermissions, ] + serializer_class = serializers.DomainAliasSerializer + + def get_queryset(self): + """Filter queryset based on current user.""" + return models.DomainAlias.objects.get_for_admin(self.request.user) + + class AccountViewSet(viewsets.ModelViewSet): """ViewSet for User/Mailbox.""" diff --git a/modoboa/admin/models/domain_alias.py b/modoboa/admin/models/domain_alias.py index 6a5cedf32..52bed916d 100644 --- a/modoboa/admin/models/domain_alias.py +++ b/modoboa/admin/models/domain_alias.py @@ -4,13 +4,29 @@ from django.db import models from django.utils.encoding import python_2_unicode_compatible, smart_text from django.utils.translation import ugettext as _, ugettext_lazy +from django.contrib.contenttypes import generic + import reversion from .base import AdminObject from .domain import Domain +from modoboa.core import models as core_models from modoboa.lib.exceptions import BadRequest, Conflict +class DomainAliasManager(models.Manager): + + def get_for_admin(self, admin): + """Return the domain aliases belonging to this admin. + + The result is a ``QuerySet`` object, so this function can be used + to fill ``ModelChoiceField`` objects. + """ + if admin.is_superuser: + return self.get_queryset() + return self.get_queryset().filter(owners__user=admin) + + @python_2_unicode_compatible class DomainAlias(AdminObject): @@ -28,6 +44,10 @@ class DomainAlias(AdminObject): default=True ) + owners = generic.GenericRelation(core_models.ObjectAccess) + + objects = DomainAliasManager() + class Meta: permissions = ( ("view_domaliases", "View domain aliases"), diff --git a/modoboa/admin/serializers.py b/modoboa/admin/serializers.py index 970010113..6d4c0c50d 100644 --- a/modoboa/admin/serializers.py +++ b/modoboa/admin/serializers.py @@ -29,6 +29,20 @@ class DomainSerializer(serializers.ModelSerializer): return domain +class DomainAliasSerializer(serializers.ModelSerializer): + """Base DomainAlias serializer.""" + + class Meta: + model = admin_models.DomainAlias + fields = ("pk", "name", "target", "enabled", ) + + def validate_target(self, value): + """Check target domain.""" + if not self.context["request"].user.can_access(value): + raise serializers.ValidationError(_("Permission denied.")) + return value + + class MailboxSerializer(serializers.ModelSerializer): """Base mailbox serializer.""" diff --git a/modoboa/admin/tests/__init__.py b/modoboa/admin/tests/__init__.py index d25bbe957..e69de29bb 100644 --- a/modoboa/admin/tests/__init__.py +++ b/modoboa/admin/tests/__init__.py @@ -1,28 +0,0 @@ -"""modoboa-admin unit tests.""" - -from .account import AccountTestCase, PermissionsTestCase -from .alias import AliasTestCase -from .api import DomainAPITestCase, AccountAPITestCase, AliasAPITestCase -from .domain import DomainTestCase -from .domain_alias import DomainAliasTestCase -from .export import ExportTestCase -from .import_ import ImportTestCase -from .mapfiles import MapFilesTestCase -from .password_schemes import PasswordSchemesTestCase -from .user import ForwardTestCase - -__all__ = [ - 'AccountAPITestCase', - 'AccountTestCase', - 'AliasAPITestCase', - 'AliasTestCase', - 'DomainAPITestCase', - 'DomainTestCase', - 'DomainAliasTestCase', - 'ExportTestCase', - 'ForwardTestCase', - 'ImportTestCase', - 'MapFilesTestCase', - 'PasswordSchemesTestCase', - 'PermissionsTestCase', -] diff --git a/modoboa/admin/tests/account.py b/modoboa/admin/tests/test_account.py similarity index 100% rename from modoboa/admin/tests/account.py rename to modoboa/admin/tests/test_account.py diff --git a/modoboa/admin/tests/alias.py b/modoboa/admin/tests/test_alias.py similarity index 100% rename from modoboa/admin/tests/alias.py rename to modoboa/admin/tests/test_alias.py diff --git a/modoboa/admin/tests/api.py b/modoboa/admin/tests/test_api.py similarity index 83% rename from modoboa/admin/tests/api.py rename to modoboa/admin/tests/test_api.py index ebd1a3cf5..19fe1b9ff 100644 --- a/modoboa/admin/tests/api.py +++ b/modoboa/admin/tests/test_api.py @@ -86,6 +86,85 @@ class DomainAPITestCase(ModoAPITestCase): self.assertFalse(models.Domain.objects.filter(pk=domain.pk).exists()) +class DomainAliasAPITestCase(ModoAPITestCase): + """Check DomainAlias API.""" + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(DomainAliasAPITestCase, cls).setUpTestData() + factories.populate_database() + cls.dom_alias1 = factories.DomainAliasFactory( + name="dalias1.com", target__name="test.com") + cls.dom_alias2 = factories.DomainAliasFactory( + name="dalias2.com", target__name="test2.com") + cls.da_token = Token.objects.create( + user=core_models.User.objects.get(username="admin@test.com")) + + def test_get(self): + """Retrieve a list of domain aliases.""" + url = reverse("external_api:domain_alias-list") + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.data), 2) + url = reverse( + "external_api:domain_alias-detail", args=[response.data[0]["pk"]]) + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.data["name"], "dalias1.com") + + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.da_token.key) + response = self.client.get(reverse("external_api:domain_alias-list")) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(response.data), 0) + + def test_post(self): + """Try to create a new domain alias.""" + url = reverse("external_api:domain_alias-list") + target = models.Domain.objects.get(name="test.com") + data = { + "name": "dalias3.com", + "target": target.pk + } + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + + dalias = json.loads(response.content) + dalias = models.DomainAlias.objects.filter( + pk=dalias["pk"]).first() + self.assertEqual(dalias.target, target) + + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.da_token.key) + response = self.client.post( + url, {"name": "dalias4.com", "target": target.pk}, format="json") + self.assertEqual(response.status_code, 403) + + def test_put(self): + """Try to update a domain alias.""" + dalias = models.DomainAlias.objects.get(name="dalias1.com") + url = reverse("external_api:domain_alias-detail", args=[dalias.pk]) + data = { + "name": "dalias3.com", "target": dalias.target.pk + } + response = self.client.put(url, data, format="json") + self.assertEqual(response.status_code, 200) + + dalias.refresh_from_db() + self.assertEqual(dalias.name, "dalias3.com") + self.assertTrue(dalias.enabled) + + def test_delete(self): + """Try to delete an existing domain alias.""" + dalias = models.DomainAlias.objects.get(name="dalias1.com") + url = reverse("external_api:domain_alias-detail", args=[dalias.pk]) + response = self.client.delete(url) + self.assertEqual(response.status_code, 204) + self.assertFalse( + models.DomainAlias.objects.filter(pk=dalias.pk).exists()) + + class AccountAPITestCase(ModoAPITestCase): """Check Account API.""" diff --git a/modoboa/admin/tests/domain.py b/modoboa/admin/tests/test_domain.py similarity index 100% rename from modoboa/admin/tests/domain.py rename to modoboa/admin/tests/test_domain.py diff --git a/modoboa/admin/tests/domain_alias.py b/modoboa/admin/tests/test_domain_alias.py similarity index 100% rename from modoboa/admin/tests/domain_alias.py rename to modoboa/admin/tests/test_domain_alias.py diff --git a/modoboa/admin/tests/export.py b/modoboa/admin/tests/test_export.py similarity index 100% rename from modoboa/admin/tests/export.py rename to modoboa/admin/tests/test_export.py diff --git a/modoboa/admin/tests/import_.py b/modoboa/admin/tests/test_import_.py similarity index 100% rename from modoboa/admin/tests/import_.py rename to modoboa/admin/tests/test_import_.py diff --git a/modoboa/admin/tests/mapfiles.py b/modoboa/admin/tests/test_mapfiles.py similarity index 100% rename from modoboa/admin/tests/mapfiles.py rename to modoboa/admin/tests/test_mapfiles.py diff --git a/modoboa/admin/tests/password_schemes.py b/modoboa/admin/tests/test_password_schemes.py similarity index 100% rename from modoboa/admin/tests/password_schemes.py rename to modoboa/admin/tests/test_password_schemes.py diff --git a/modoboa/admin/tests/user.py b/modoboa/admin/tests/test_user.py similarity index 100% rename from modoboa/admin/tests/user.py rename to modoboa/admin/tests/test_user.py diff --git a/modoboa/admin/urls_api.py b/modoboa/admin/urls_api.py index c5e0df79a..3c1051aed 100644 --- a/modoboa/admin/urls_api.py +++ b/modoboa/admin/urls_api.py @@ -7,6 +7,8 @@ from . import api router = routers.SimpleRouter() router.register(r"domains", api.DomainViewSet, base_name="domain") +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")