Add possibility to set domain permissions using the API.

This commit is contained in:
Antoine Nguyen
2016-04-27 15:51:06 +02:00
parent 83f20ee738
commit 6bc0eb6a09
2 changed files with 83 additions and 1 deletions
+44 -1
View File
@@ -77,13 +77,17 @@ class AccountSerializer(serializers.ModelSerializer):
role = serializers.SerializerMethodField()
mailbox = MailboxSerializer(required=False)
domains = serializers.SerializerMethodField(
help_text=_(
"List of administered domains (resellers and domain "
"administrators only)."))
class Meta:
model = core_models.User
fields = (
"pk", "username", "first_name", "last_name", "is_active",
"master_user", "mailbox", "role", "language", "phone_number",
"secondary_email",
"secondary_email", "domains",
)
def __init__(self, *args, **kwargs):
@@ -100,6 +104,13 @@ class AccountSerializer(serializers.ModelSerializer):
"""Return role."""
return account.group
def get_domains(self, account):
"""Return domains administered by this account."""
if account.role not in ["DomainAdmins", "Resellers"]:
return []
return admin_models.Domain.objects.get_for_admin(account).values_list(
"name", flat=True)
class AccountExistsSerializer(serializers.Serializer):
"""Simple serializer used with existence checks."""
@@ -156,6 +167,8 @@ class WritableAccountSerializer(AccountSerializer):
user = self.context["request"].user
self.fields["role"] = serializers.ChoiceField(
choices=permissions.get_account_roles(user))
self.fields["domains"] = serializers.ListField(
child=serializers.CharField(), allow_empty=False, required=False)
def validate_password(self, value):
"""Check password constraints."""
@@ -183,6 +196,19 @@ class WritableAccountSerializer(AccountSerializer):
raise serializers.ValidationError({
"username": _("Must be equal to mailbox full_address")
})
domain_names = data.get("domains")
if not domain_names:
return data
domains = []
for name in domain_names:
domain = admin_models.Domain.objects.filter(name=name).first()
if domain:
domains.append(domain)
continue
raise serializers.ValidationError({
"domains": _("Local domain {} does not exist").format(name)
})
data["domains"] = domains
return data
def _create_mailbox(self, creator, account, data):
@@ -213,23 +239,39 @@ class WritableAccountSerializer(AccountSerializer):
account.email = full_address
return mb
def set_permissions(self, account, domains):
"""Assign permissions on domain(s)."""
if account.role not in ["DomainAdmins", "Resellers"]:
return
current_domains = admin_models.Domain.objects.get_for_admin(account)
for domain in current_domains:
if domain not in domains:
domain.remove_admin(account)
else:
domains.remove(domain)
for domain in domains:
domain.add_admin(account)
def create(self, validated_data):
"""Create appropriate objects."""
creator = self.context["request"].user
mailbox_data = validated_data.pop("mailbox", None)
role = validated_data.pop("role")
domains = validated_data.pop("domains", [])
user = core_models.User(**validated_data)
user.set_password(validated_data["password"])
user.save(creator=creator)
if mailbox_data:
self._create_mailbox(creator, user, mailbox_data)
user.role = role
self.set_permissions(user, domains)
return user
def update(self, instance, validated_data):
"""Update account and associated objects."""
mailbox_data = validated_data.pop("mailbox")
password = validated_data.pop("password")
domains = validated_data.pop("domains", [])
for key, value in validated_data.items():
setattr(instance, key, value)
instance.set_password(password)
@@ -242,6 +284,7 @@ class WritableAccountSerializer(AccountSerializer):
instance.mailbox.update_from_dict(creator, mailbox_data)
else:
self._create_mailbox(creator, instance, mailbox_data)
self.set_permissions(instance, domains)
return instance
+39
View File
@@ -8,6 +8,7 @@ from django.core.urlresolvers import reverse
from rest_framework.authtoken.models import Token
from modoboa.admin import models as admin_models
from modoboa.core import models as core_models
from modoboa.lib import parameters
from modoboa.lib.tests import ModoAPITestCase
@@ -192,6 +193,12 @@ class AccountAPITestCase(ModoAPITestCase):
cls.da_token = Token.objects.create(
user=core_models.User.objects.get(username="admin@test.com"))
def setUp(self):
"""Test setup."""
super(AccountAPITestCase, self).setUp()
parameters.save_admin("ENABLE_ADMIN_LIMITS", "no", app="limits")
parameters.save_admin("ENABLE_DOMAIN_LIMITS", "no", app="limits")
def test_get_accounts(self):
"""Retrieve a list of accounts."""
url = reverse("external_api:account-list")
@@ -233,10 +240,15 @@ class AccountAPITestCase(ModoAPITestCase):
def test_create_domainadmin_account(self):
"""Try to create a domain admin."""
data = copy.deepcopy(self.ACCOUNT_DATA)
data["domains"] = ["test.com"]
data["role"] = "DomainAdmins"
url = reverse("external_api:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
domain = admin_models.Domain.objects.get(name="test.com")
admin = core_models.User.objects.get(
pk=json.loads(response.content)["pk"])
self.assertIn(admin, domain.admins)
data["username"] = "domain_admin"
del data["mailbox"]
@@ -325,6 +337,33 @@ class AccountAPITestCase(ModoAPITestCase):
account.refresh_from_db()
self.assertEqual(account.email, account.mailbox.full_address)
def test_update_domain_admin_account(self):
"""Try to change administered domains."""
account = core_models.User.objects.get(username="admin@test.com")
url = reverse("external_api:account-detail", args=[account.pk])
data = {
"username": account.username,
"role": account.role,
"password": "Toto1234",
"mailbox": {
"full_address": account.mailbox.full_address,
"quota": account.mailbox.quota
},
"domains": ["test.com", "test2.com"]
}
response = self.client.put(url, data, format="json")
self.assertEqual(response.status_code, 200)
domains = admin_models.Domain.objects.get_for_admin(account)
self.assertEqual(domains.count(), 2)
self.assertTrue(domains.filter(name="test2.com").exists())
data["domains"] = ["test2.com"]
response = self.client.put(url, data, format="json")
self.assertEqual(response.status_code, 200)
domains = admin_models.Domain.objects.get_for_admin(account)
self.assertEqual(domains.count(), 1)
self.assertTrue(domains.filter(name="test2.com").exists())
def test_update_account_wrong_address(self):
"""Try to update an account."""
account = core_models.User.objects.get(username="user@test.com")