From 2bf3a4d5cb0a6dc5f26dcabcc29391271ffea5e0 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Sun, 24 Apr 2016 15:18:14 +0200 Subject: [PATCH] Unit tests and fixes. see #799 --- modoboa/admin/callbacks.py | 7 +- modoboa/admin/lib.py | 5 + modoboa/admin/models/alias.py | 5 + modoboa/limits/tests/__init__.py | 0 modoboa/limits/tests/test_api.py | 237 ++++++++++++ modoboa/limits/tests/test_domain_limits.py | 135 +++++++ modoboa/limits/tests/test_import.py | 104 +++++ modoboa/limits/tests/test_user_limits.py | 422 +++++++++++++++++++++ 8 files changed, 914 insertions(+), 1 deletion(-) create mode 100644 modoboa/limits/tests/__init__.py create mode 100644 modoboa/limits/tests/test_api.py create mode 100644 modoboa/limits/tests/test_domain_limits.py create mode 100644 modoboa/limits/tests/test_import.py create mode 100644 modoboa/limits/tests/test_user_limits.py diff --git a/modoboa/admin/callbacks.py b/modoboa/admin/callbacks.py index b894673c0..163bf49aa 100644 --- a/modoboa/admin/callbacks.py +++ b/modoboa/admin/callbacks.py @@ -3,6 +3,7 @@ from django.core.urlresolvers import reverse from django.utils.translation import ugettext as _, ugettext_lazy +from modoboa.core import signals as core_signals from modoboa.lib import parameters, events from modoboa.lib.email_utils import split_mailbox from modoboa.lib.exceptions import PermDeniedException, BadRequest, Conflict @@ -103,7 +104,6 @@ def import_account_mailbox(user, account, row): """ account.email = row[0].strip() if account.email: - account.save() mailbox, domname = split_mailbox(account.email) try: domain = Domain.objects.get(name=domname) @@ -114,6 +114,11 @@ def import_account_mailbox(user, account, row): ) if not user.can_access(domain): raise PermDeniedException + core_signals.can_create_object.send( + sender="import", context=user, object_type="mailboxes") + core_signals.can_create_object.send( + sender="import", context=domain, object_type="mailboxes") + account.save() if Mailbox.objects.filter(address=mailbox, domain=domain).exists(): raise Conflict( _("Mailbox {} already exists").format(account.email)) diff --git a/modoboa/admin/lib.py b/modoboa/admin/lib.py index 547d487ca..075663131 100644 --- a/modoboa/admin/lib.py +++ b/modoboa/admin/lib.py @@ -10,6 +10,7 @@ from django.db.models import Q from django.utils.translation import ugettext as _ from modoboa.core.models import User +from modoboa.core import signals as core_signals from modoboa.lib import events from modoboa.lib.exceptions import PermDeniedException @@ -118,6 +119,8 @@ def import_domain(user, row, formopts): """Specific code for domains import""" if not user.has_perm("admin.add_domain"): raise PermDeniedException(_("You are not allowed to import domains")) + core_signals.can_create_object.send( + sender="import", context=user, object_type="domains") dom = Domain() dom.from_csv(user, row) @@ -127,6 +130,8 @@ def import_domainalias(user, row, formopts): if not user.has_perm("admin.add_domainalias"): raise PermDeniedException( _("You are not allowed to import domain aliases.")) + core_signals.can_create_object.send( + sender="import", context=user, object_type="domain_aliases") domalias = DomainAlias() domalias.from_csv(user, row) diff --git a/modoboa/admin/models/alias.py b/modoboa/admin/models/alias.py index 3948966b7..c8626267c 100644 --- a/modoboa/admin/models/alias.py +++ b/modoboa/admin/models/alias.py @@ -6,6 +6,7 @@ from django.utils.translation import ugettext as _, ugettext_lazy import reversion +from modoboa.core import signals as core_signals from modoboa.lib.email_utils import split_mailbox from modoboa.lib.exceptions import ( PermDeniedException, BadRequest, Conflict, NotFound @@ -171,6 +172,10 @@ class Alias(AdminObject): raise BadRequest(_("Domain '%s' does not exist" % domname)) if not user.can_access(domain): raise PermDeniedException + core_signals.can_create_object.send( + sender="import", context=user, object_type="mailbox_aliases") + core_signals.can_create_object.send( + sender="import", context=domain, object_type="mailbox_aliases") if Alias.objects.filter(address=address).exists(): raise Conflict self.address = address diff --git a/modoboa/limits/tests/__init__.py b/modoboa/limits/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/modoboa/limits/tests/test_api.py b/modoboa/limits/tests/test_api.py new file mode 100644 index 000000000..5d7c99a7d --- /dev/null +++ b/modoboa/limits/tests/test_api.py @@ -0,0 +1,237 @@ +# coding: utf-8 +"""Test cases for the limits extension.""" + +from django.core.urlresolvers import reverse + +from rest_framework.authtoken.models import Token + +from modoboa.admin.factories import populate_database +from modoboa.admin.models import Domain +from modoboa.core import factories as core_factories +from modoboa.core.models import User +from modoboa.lib import parameters +from modoboa.lib import tests as lib_tests + +from .. import utils + + +class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase): + """Check that limits are used also by the API.""" + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(APIAdminLimitsTestCase, cls).setUpTestData() + for name, tpl in utils.get_user_limit_templates(): + parameters.save_admin( + "DEFLT_USER_{}_LIMIT".format(name.upper()), 2) + populate_database() + cls.user = User.objects.get(username="admin@test.com") + cls.da_token = Token.objects.create(user=cls.user) + cls.reseller = core_factories.UserFactory( + username="reseller", groups=("Resellers", ), + ) + cls.r_token = Token.objects.create(user=cls.reseller) + + def test_domadmins_limit(self): + """Check domain admins limit.""" + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.r_token.key) + + limit = self.reseller.userobjectlimit_set.get(name="domain_admins") + url = reverse("external_api:account-list") + data = { + "username": "fromapi@test.com", + "role": "DomainAdmins", + "password": "Toto1234", + } + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertFalse(limit.is_exceeded()) + + data["username"] = "fromapi2@test.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertTrue(limit.is_exceeded()) + + data["username"] = "fromapi3@test.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) + + user = User.objects.get(username="user@test.com") + domain = Domain.objects.get(name="test.com") + domain.add_admin(self.reseller) + url = reverse("external_api:account-detail", args=[user.pk]) + data = { + "username": user.username, + "role": "DomainAdmins", + "password": "Toto1234", + "mailbox": { + "full_address": user.username, + "quota": user.mailbox.quota + } + } + response = self.client.put(url, data, format="json") + self.assertEqual(response.status_code, 400) + + def test_domains_limit(self): + """Check domains limit.""" + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.r_token.key) + limit = self.reseller.userobjectlimit_set.get(name="domains") + url = reverse("external_api:domain-list") + data = {"name": "test3.com", "quota": 10} + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertFalse(limit.is_exceeded()) + + data["name"] = "test4.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertTrue(limit.is_exceeded()) + + data["username"] = "test5.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) + + def test_domain_aliases_limit(self): + """Check domain aliases limit.""" + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.r_token.key) + domain = Domain.objects.get(name="test.com") + domain.add_admin(self.reseller) + limit = self.reseller.userobjectlimit_set.get(name="domain_aliases") + url = reverse("external_api:domain_alias-list") + data = {"name": "dalias1.com", "target": domain.pk} + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertFalse(limit.is_exceeded()) + + data["name"] = "dalias2.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertTrue(limit.is_exceeded()) + + data["username"] = "dalias3.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) + + def test_mailboxes_limit(self): + """Check mailboxes limit.""" + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.da_token.key) + + limit = self.user.userobjectlimit_set.get(name="mailboxes") + url = reverse("external_api:account-list") + data = { + "username": "fromapi@test.com", + "role": "SimpleUsers", + "password": "Toto1234", + "mailbox": { + "full_address": "fromapi@test.com", + "quota": 10 + } + } + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertFalse(limit.is_exceeded()) + + data["username"] = "fromapi2@test.com" + data["mailbox"]["full_address"] = "fromapi2@test.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertTrue(limit.is_exceeded()) + + data["username"] = "fromapi3@test.com" + data["mailbox"]["full_address"] = "fromapi3@test.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) + + def test_aliases_limit(self): + """Check mailbox aliases limit.""" + self.client.credentials( + HTTP_AUTHORIZATION='Token ' + self.da_token.key) + + limit = self.user.userobjectlimit_set.get(name="mailbox_aliases") + url = reverse("external_api:alias-list") + data = { + "address": "alias_fromapi@test.com", + "recipients": [ + "user@test.com", "postmaster@test.com", "user_éé@nonlocal.com" + ] + } + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertFalse(limit.is_exceeded()) + + data["address"] = "alias_fromapi2@test.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertTrue(limit.is_exceeded()) + + data["address"] = "alias_fromapi3@test.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) + + +class APIDomainLimitsTestCase(lib_tests.ModoAPITestCase): + """Check that limits are used also by the API.""" + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(APIDomainLimitsTestCase, cls).setUpTestData() + parameters.save_admin("ENABLE_DOMAIN_LIMITS", "yes") + for name, tpl in utils.get_domain_limit_templates(): + parameters.save_admin( + "DEFLT_DOMAIN_{}_LIMIT".format(name.upper()), 2) + populate_database() + + def test_mailboxes_limit(self): + """Check mailboxes limit.""" + domain = Domain.objects.get(name="test.com") + limit = domain.domainobjectlimit_set.get(name="mailboxes") + self.assertTrue(limit.is_exceeded()) + url = reverse("external_api:account-list") + data = { + "username": "fromapi@test.com", + "role": "SimpleUsers", + "password": "Toto1234", + "mailbox": { + "full_address": "fromapi@test.com", + "quota": 10 + } + } + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) + + def test_domain_aliases_limit(self): + """Check domain_aliases limit.""" + domain = Domain.objects.get(name="test.com") + limit = domain.domainobjectlimit_set.get(name="domain_aliases") + url = reverse("external_api:domain_alias-list") + data = {"name": "dalias1.com", "target": domain.pk} + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + data["name"] = "dalias2.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 201) + self.assertTrue(limit.is_exceeded()) + data["name"] = "dalias3.com" + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) + + def test_mailbox_aliases_limit(self): + """Check mailbox_aliases limit.""" + domain = Domain.objects.get(name="test.com") + limit = domain.domainobjectlimit_set.get(name="mailbox_aliases") + self.assertTrue(limit.is_exceeded()) + url = reverse("external_api:alias-list") + data = { + "address": "alias_fromapi@test.com", + "recipients": [ + "user@test.com", "postmaster@test.com", "user_éé@nonlocal.com" + ] + } + response = self.client.post(url, data, format="json") + self.assertEqual(response.status_code, 400) diff --git a/modoboa/limits/tests/test_domain_limits.py b/modoboa/limits/tests/test_domain_limits.py new file mode 100644 index 000000000..be539ef25 --- /dev/null +++ b/modoboa/limits/tests/test_domain_limits.py @@ -0,0 +1,135 @@ +# coding: utf-8 +"""Test cases for the limits extension.""" + +from django.core.urlresolvers import reverse + +from modoboa.admin.factories import populate_database +from modoboa.admin.models import Domain +from modoboa.core.models import User +from modoboa.lib import parameters +from modoboa.lib import tests as lib_tests + +from .. import utils + + +class DomainLimitsTestCase(lib_tests.ModoTestCase): + """Per-domain limits tests.""" + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(DomainLimitsTestCase, cls).setUpTestData() + parameters.save_admin("ENABLE_DOMAIN_LIMITS", "yes") + for name, tpl in utils.get_domain_limit_templates(): + parameters.save_admin( + "DEFLT_DOMAIN_{}_LIMIT".format(name.upper()), 2) + populate_database() + + def test_set_limits(self): + """Try to set limits for a given domain.""" + domain = Domain.objects.get(name="test.com") + values = { + "name": domain.name, "quota": domain.quota, + "enabled": domain.enabled, "type": "domain", + "mailboxes_limit": 3, "mailbox_aliases_limit": 3, + "domain_aliases_limit": 3 + } + self.ajax_post( + reverse("admin:domain_change", args=[domain.id]), + values + ) + domain.refresh_from_db() + self.assertEqual( + domain.domainobjectlimit_set.get(name="mailboxes").max_value, 3) + self.assertEqual( + domain.domainobjectlimit_set.get( + name="mailbox_aliases").max_value, 3) + self.assertEqual( + domain.domainobjectlimit_set.get( + name="domain_aliases").max_value, 3) + + def test_domain_aliases_limit(self): + """Try to exceed defined limit.""" + # Import + domain = Domain.objects.get(name="test.com") + limit = domain.domainobjectlimit_set.get(name="domain_aliases") + self.assertFalse(limit.is_exceeded()) + values = { + "name": domain.name, "quota": domain.quota, + "enabled": domain.enabled, "type": "domain", + "mailboxes_limit": 2, "mailbox_aliases_limit": 2, + "domain_aliases_limit": 2, + "aliases": "alias1.com", "aliases_1": "alias2.com" + } + self.ajax_post( + reverse("admin:domain_change", args=[domain.id]), + values + ) + self.assertTrue(limit.is_exceeded()) + values["aliases_2"] = "alias3.com" + self.ajax_post( + reverse("admin:domain_change", args=[domain.id]), + values, 403 + ) + + def test_mailboxes_limit(self): + """Try to exceed defined limits.""" + # Import + # LDAP ? + domain = Domain.objects.get(name="test.com") + domain.domainobjectlimit_set.filter(name="mailboxes").update( + max_value=3) + limit = domain.domainobjectlimit_set.get(name="mailboxes") + self.assertFalse(limit.is_exceeded()) + username = "toto@test.com" + values = { + "username": username, + "first_name": "Tester", "last_name": "Toto", + "password1": "Toto1234", "password2": "Toto1234", + "role": "SimpleUsers", "quota_act": True, + "is_active": True, "email": username, "stepid": "step2", + } + self.ajax_post(reverse("admin:account_add"), values, 200) + self.assertTrue(limit.is_exceeded()) + + username = "titi@test.com" + self.ajax_post(reverse("admin:account_add"), values, 400) + + def test_mailbox_aliases_limit(self): + """Try to exceed defined limits.""" + # Import + domain = Domain.objects.get(name="test.com") + user = User.objects.get(username="user@test.com") + limit = domain.domainobjectlimit_set.get(name="mailbox_aliases") + limit.max_value = 4 + limit.save() + self.assertFalse(limit.is_exceeded()) + values = { + "username": user.username, "role": user.group, + "is_active": user.is_active, "email": user.email, + "quota_act": True, + "aliases": "alias@test.com", "aliases_1": "alias1@test.com" + } + self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values + ) + self.assertTrue(limit.is_exceeded()) + + values["aliases_2"] = "alias2@test.com" + self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values, 403 + ) + + limit.max_value = 5 + limit.save() + values = { + "address": "forward2@test.com", "recipients": "user@test.com", + "enabled": True + } + self.ajax_post(reverse("admin:alias_add"), values) + self.assertTrue(limit.is_exceeded()) + + values["address"] = "forward3@test.com" + self.ajax_post(reverse("admin:alias_add"), values, 400) diff --git a/modoboa/limits/tests/test_import.py b/modoboa/limits/tests/test_import.py new file mode 100644 index 000000000..a36114d58 --- /dev/null +++ b/modoboa/limits/tests/test_import.py @@ -0,0 +1,104 @@ +# coding: utf-8 +from django.core.files.base import ContentFile +from django.core.urlresolvers import reverse + +from modoboa.admin import factories as admin_factories +from modoboa.core import factories as core_factories +from modoboa.core import models as core_models +from modoboa.lib import parameters +from modoboa.lib.tests import ModoTestCase + +from .. import utils + + +class UserLimitImportTestCase(ModoTestCase): + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(UserLimitImportTestCase, cls).setUpTestData() + for name, tpl in utils.get_user_limit_templates(): + parameters.save_admin( + "DEFLT_USER_{}_LIMIT".format(name.upper()), 2) + admin_factories.populate_database() + cls.reseller = core_factories.UserFactory( + username="reseller", groups=("Resellers", )) + cls.dadmin = core_models.User.objects.get(username="admin@test.com") + + def test_domains_import(self): + """Check domains limit.""" + self.client.login( + username=self.reseller.username, password="toto") + limit = self.reseller.userobjectlimit_set.get(name="domains") + self.assertFalse(limit.is_exceeded()) + f = ContentFile(b"""domain; domain1.com; 100; True +domain; domain2.com; 200; False +""", name="domains.csv") + self.client.post( + reverse("admin:domain_import"), { + "sourcefile": f + } + ) + self.assertTrue(limit.is_exceeded()) + + f = ContentFile(b"""domain; domain3.com; 100; True +""", name="domains.csv") + response = self.client.post( + reverse("admin:domain_import"), { + "sourcefile": f + } + ) + self.assertContains(response, "Domains: limit reached") + + def test_domain_alias_import(self): + """Check domain aliases limit.""" + self.client.login( + username=self.reseller.username, password="toto") + limit = self.reseller.userobjectlimit_set.get(name="domain_aliases") + self.assertFalse(limit.is_exceeded()) + f = ContentFile(b"""domainalias; domalias1.com; test.com; True +domainalias; domalias2.com; test.com; True +""", name="domains.csv") + self.client.post( + reverse("admin:domain_import"), { + "sourcefile": f + } + ) + self.assertTrue(limit.is_exceeded()) + + f = ContentFile( + "domainalias; domalias3.com; test.com; True", name="domains.csv") + response = self.client.post( + reverse("admin:domain_import"), { + "sourcefile": f + } + ) + self.assertContains(response, "Domain aliases: limit reached") + + def test_mailboxes_import(self): + """Check mailboxes limit.""" + self.client.login( + username=self.dadmin.username, password="toto") + limit = self.dadmin.userobjectlimit_set.get(name="mailboxes") + self.assertFalse(limit.is_exceeded()) + f = ContentFile(b"""account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com; 5 +account; truc@test.com; toto; René; Truc; True; SimpleUsers; truc@test.com; 5 +""", name="domains.csv") + self.client.post( + reverse("admin:identity_import"), { + "sourcefile": f + } + ) + self.assertTrue(limit.is_exceeded()) + + f = ContentFile(""" +account; user3@test.com; toto; User; One; True; SimpleUsers; user3@test.com; 5 +""", name="domains.csv") + response = self.client.post( + reverse("admin:identity_import"), { + "sourcefile": f + } + ) + self.assertContains(response, "Mailboxes: limit reached") + + # FIXME: aliases, domain admins diff --git a/modoboa/limits/tests/test_user_limits.py b/modoboa/limits/tests/test_user_limits.py new file mode 100644 index 000000000..b00ace977 --- /dev/null +++ b/modoboa/limits/tests/test_user_limits.py @@ -0,0 +1,422 @@ +# coding: utf-8 +"""Test cases for the limits extension.""" + +from django.core.urlresolvers import reverse + +from modoboa.admin.factories import populate_database +from modoboa.admin.models import Alias, Domain +from modoboa.core.factories import UserFactory +from modoboa.core.models import User +from modoboa.lib import parameters +from modoboa.lib import tests as lib_tests + +from .. import utils + + +class PermissionsTestCase(lib_tests.ModoTestCase): + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(PermissionsTestCase, cls).setUpTestData() + populate_database() + + def test_domainadmin_deletes_reseller(self): + """Check if a domain admin can delete a reseller. + + Expected result: no. + """ + values = dict( + username="reseller@test.com", first_name="Reseller", last_name="", + password1="Toto1234", password2="Toto1234", role="Resellers", + is_active=True, email="reseller@test.com", stepid='step2' + ) + self.ajax_post(reverse("admin:account_add"), values) + account = User.objects.get(username="reseller@test.com") + self.client.logout() + self.client.login(username="admin@test.com", password="toto") + resp = self.ajax_post( + reverse("admin:account_delete", args=[account.id]), + {}, status=403 + ) + self.assertEqual(resp, "Permission denied") + + +class ResourceTestCase(lib_tests.ModoTestCase): + + @classmethod + def setUpTestData(cls): + """Custom setUpTestData method.""" + super(ResourceTestCase, cls).setUpTestData() + for name, tpl in utils.get_user_limit_templates(): + parameters.save_admin( + "DEFLT_USER_{0}_LIMIT".format(name.upper()), 2, + app="limits" + ) + populate_database() + + def _create_account(self, username, role='SimpleUsers', status=200): + values = dict( + username=username, first_name="Tester", last_name="Toto", + password1="Toto1234", password2="Toto1234", role=role, + quota_act=True, + is_active=True, email=username, stepid='step2', + ) + return self.ajax_post( + reverse("admin:account_add"), values, status + ) + + def _create_alias(self, email, rcpt='user@test.com', status=200): + values = dict( + address=email, recipients=rcpt, enabled=True + ) + return self.ajax_post( + reverse("admin:alias_add"), values, status + ) + + def _create_domain(self, name, status=200, withtpl=False): + values = { + "name": name, "quota": 100, "create_dom_admin": "no", + "create_aliases": "no", "stepid": 'step3', "type": "domain" + } + if withtpl: + values['create_dom_admin'] = 'yes' + values['dom_admin_username'] = 'admin' + values['create_aliases'] = 'yes' + response = self.ajax_post( + reverse("admin:domain_add"), values, status + ) + return response + + def _domain_alias_operation(self, optype, domain, name, status=200): + dom = Domain.objects.get(name=domain) + values = { + 'name': dom.name, 'quota': dom.quota, 'enabled': dom.enabled, + "type": "domain" + } + aliases = [alias.name for alias in dom.domainalias_set.all()] + if optype == 'add': + aliases.append(name) + else: + aliases.remove(name) + for cpt, alias in enumerate(aliases): + fname = 'aliases' if not cpt else 'aliases_%d' % cpt + values[fname] = alias + self.ajax_post( + reverse("admin:domain_change", args=[dom.id]), + values, status + ) + + def _check_limit(self, name, curvalue, maxvalue): + l = self.user.userobjectlimit_set.get(name=name) + self.assertEqual(l.current_value, curvalue) + self.assertEqual(l.max_value, maxvalue) + + +class DomainAdminTestCase(ResourceTestCase): + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(DomainAdminTestCase, cls).setUpTestData() + cls.user = User.objects.get(username='admin@test.com') + cls.user.userobjectlimit_set.filter( + name__in=["mailboxes", "mailbox_aliases"]).update(max_value=2) + + def setUp(self): + """Test initialization.""" + super(DomainAdminTestCase, self).setUp() + self.client.logout() + self.client.login(username='admin@test.com', password='toto') + + def test_mailboxes_limit(self): + self._create_account('tester1@test.com') + self._check_limit('mailboxes', 1, 2) + self._create_account('tester2@test.com') + self._check_limit('mailboxes', 2, 2) + self._create_account('tester3@test.com', status=403) + self._check_limit('mailboxes', 2, 2) + self.ajax_post( + reverse('admin:account_delete', + args=[User.objects.get(username='tester2@test.com').id]), + {} + ) + self._check_limit('mailboxes', 1, 2) + + def test_aliases_limit(self): + self._create_alias('alias1@test.com') + self._check_limit('mailbox_aliases', 1, 2) + self._create_alias('alias2@test.com') + self._check_limit('mailbox_aliases', 2, 2) + self._create_alias('alias3@test.com', status=403) + self._check_limit('mailbox_aliases', 2, 2) + self.ajax_post( + reverse('admin:alias_delete') + '?selection=%d' + % Alias.objects.get(address='alias2@test.com').id, + {} + ) + self._check_limit('mailbox_aliases', 1, 2) + + def test_aliases_limit_through_account_form(self): + user = User.objects.get(username='user@test.com') + values = dict( + username=user.username, role=user.group, + is_active=user.is_active, email=user.email, quota_act=True, + aliases="alias1@test.com", aliases_1="alias2@test.com" + ) + self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values + ) + Alias.objects.get(address='alias1@test.com') + self._check_limit('mailbox_aliases', 2, 2) + + +class ResellerTestCase(ResourceTestCase): + + @classmethod + def setUpTestData(cls): + """Create test data.""" + super(ResellerTestCase, cls).setUpTestData() + cls.user = UserFactory( + username='reseller', groups=('Resellers',) + ) + + def setUp(self): + """Test initialization.""" + super(ResellerTestCase, self).setUp() + self.client.logout() + self.client.login(username='reseller', password='toto') + + def test_domains_limit(self): + response = self.client.get(reverse("admin:domain_list")) + self.assertContains(response, "Domains (0%)") + self.assertContains(response, "Domain aliases (0%)") + self._create_domain('domain1.tld') + self._check_limit('domains', 1, 2) + self._create_domain('domain2.tld') + self._check_limit('domains', 2, 2) + self._create_domain('domain3.tld', 403) + self._check_limit('domains', 2, 2) + self.ajax_post( + reverse('admin:domain_delete', + args=[Domain.objects.get(name='domain2.tld').id]), + {} + ) + self._check_limit('domains', 1, 2) + + def test_domain_aliases_limit(self): + self._create_domain('pouet.com') + self._domain_alias_operation('add', 'pouet.com', 'domain-alias1.tld') + self._check_limit('domain_aliases', 1, 2) + self._domain_alias_operation('add', 'pouet.com', 'domain-alias2.tld') + self._check_limit('domain_aliases', 2, 2) + self._domain_alias_operation( + 'add', 'pouet.com', 'domain-alias3.tld', 403 + ) + self._check_limit('domain_aliases', 2, 2) + self._domain_alias_operation( + 'delete', 'pouet.com', 'domain-alias2.tld') + self._check_limit('domain_aliases', 1, 2) + + def test_domain_admins_limit(self): + response = self.client.get(reverse("admin:identity_list")) + self.assertContains(response, "Domain admins (0%)") + self.assertContains(response, "Mailboxes (0%)") + self.assertContains(response, "Mailbox aliases (0%)") + + self._create_domain('domain.tld') + self._create_account('admin1@domain.tld', role='DomainAdmins') + self._check_limit('domain_admins', 1, 2) + self._create_account('admin2@domain.tld', role='DomainAdmins') + self._check_limit('domain_admins', 2, 2) + resp = self._create_account( + 'admin3@domain.tld', + role='DomainAdmins', + status=400) + self.assertEqual( + resp['form_errors']['role'][0], + 'Select a valid choice. DomainAdmins is not one of the available ' + 'choices.' + ) + self._check_limit('domain_admins', 2, 2) + + self.user.userobjectlimit_set.filter( + name="mailboxes").update(max_value=3) + self._create_account('user1@domain.tld') + user = User.objects.get(username='user1@domain.tld') + values = { + 'username': user.username, 'role': 'DomainAdmins', + 'quota_act': True, 'is_active': user.is_active, + 'email': user.email + } + resp = self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values, status=400 + ) + self.assertEqual( + resp['form_errors']['role'][0], + 'Select a valid choice. DomainAdmins is not one of the available ' + 'choices.' + ) + self._check_limit('domain_admins', 2, 2) + + def test_domain_admin_resource_are_empty(self): + self._create_domain('domain.tld') + self._create_account('admin1@domain.tld', role='DomainAdmins') + domadmin = User.objects.get(username='admin1@domain.tld') + for l in ['mailboxes', 'mailbox_aliases']: + self.assertEqual( + domadmin.userobjectlimit_set.get(name=l).max_value, 0 + ) + + def test_domain_admins_limit_from_domain_tpl(self): + self.user.userobjectlimit_set.filter( + name="domains").update(max_value=3) + self._create_domain('domain1.tld', withtpl=True) + self._create_domain('domain2.tld', withtpl=True) + self._check_limit('domain_admins', 2, 2) + self._check_limit('domains', 2, 3) + self._create_domain('domain3.tld', status=200, withtpl=True) + self._check_limit('domain_admins', 2, 2) + self._check_limit('domains', 3, 3) + + def test_reseller_deletes_domain(self): + """Check if all resources are restored after the deletion. + """ + self._create_domain('domain.tld', withtpl=True) + dom = Domain.objects.get(name="domain.tld") + self.ajax_post( + reverse("admin:domain_delete", args=[dom.id]), + {} + ) + self._check_limit('domains', 0, 2) + self._check_limit('domain_admins', 1, 2) + self._check_limit('mailboxes', 0, 2) + self._check_limit('mailbox_aliases', 0, 2) + + def test_sadmin_removes_ownership(self): + self._create_domain('domain.tld', withtpl=True) + dom = Domain.objects.get(name="domain.tld") + self.client.logout() + self.client.login(username='admin', password='password') + self.ajax_get( + "{0}?domid={1}&daid={2}".format( + reverse('admin:permission_remove'), + dom.id, self.user.id + ), {} + ) + self._check_limit('domains', 0, 2) + self._check_limit('domain_admins', 0, 2) + self._check_limit('mailboxes', 0, 2) + self._check_limit('mailbox_aliases', 0, 2) + + def test_allocate_from_pool(self): + self._create_domain('domain.tld') + self._create_account('admin1@domain.tld', role='DomainAdmins') + user = User.objects.get(username='admin1@domain.tld') + + # Give 1 mailbox and 2 aliases to the admin -> should work + values = { + 'username': user.username, 'role': user.group, 'quota_act': True, + 'is_active': user.is_active, 'email': user.email, + 'mailboxes_limit': 1, 'mailbox_aliases_limit': 2 + } + self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values + ) + self._check_limit('mailboxes', 1, 1) + self._check_limit('mailbox_aliases', 0, 0) + + # Delete the admin -> resources should go back to the + # reseller's pool + self.ajax_post( + reverse("admin:account_delete", args=[user.id]), + {} + ) + self._check_limit('mailboxes', 0, 2) + self._check_limit('mailbox_aliases', 0, 2) + + def test_restore_resources(self): + """Give resource to a domain admin and restore them.""" + self._create_domain('domain.tld') + dom = Domain.objects.get(name='domain.tld') + self._create_account('admin1@domain.tld', role='DomainAdmins') + user = User.objects.get(username='admin1@domain.tld') + values = { + 'username': user.username, 'role': user.group, 'quota_act': True, + 'is_active': user.is_active, 'email': user.email, + 'mailboxes_limit': 1, 'mailbox_aliases_limit': 2 + } + self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values + ) + dom.add_admin(user) + self.client.logout() + self.client.login(username='admin1@domain.tld', password='Toto1234') + self._create_account('user1@domain.tld') + self._create_alias('alias1@domain.tld', 'user1@domain.tld') + self._create_alias('alias2@domain.tld', 'user1@domain.tld') + self.client.logout() + self.client.login(username='reseller', password='toto') + # Delete the admin -> resources should go back to the + # reseller's pool + self.ajax_post( + reverse("admin:account_delete", args=[user.id]), + {} + ) + self._check_limit('mailboxes', 1, 2) + self._check_limit('mailbox_aliases', 2, 2) + + def test_change_role(self): + self._create_domain('domain.tld') + self._create_account('admin1@domain.tld', role='DomainAdmins') + user = User.objects.get(username='admin1@domain.tld') + + # Give 1 mailbox and 2 aliases to the admin -> should work + values = { + 'username': user.username, 'role': user.group, 'quota_act': True, + 'is_active': user.is_active, 'email': user.email, + 'mailboxes_limit': 1, 'mailbox_aliases_limit': 2 + } + self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values + ) + self._check_limit('mailboxes', 1, 1) + self._check_limit('mailbox_aliases', 0, 0) + + # Change admin role to SimpleUser -> resources should go back + # to the reseller. + values = { + 'username': user.username, 'role': 'SimpleUsers', + 'quota_act': True, + 'is_active': user.is_active, 'email': user.email, + } + self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values + ) + self._check_limit('mailboxes', 1, 2) + self._check_limit('mailbox_aliases', 0, 2) + + def test_allocate_too_much(self): + self._create_domain('domain.tld') + self._create_account('admin1@domain.tld', role='DomainAdmins') + user = User.objects.get(username='admin1@domain.tld') + + # Give 2 mailboxes and 3 aliases to the admin -> should fail. + values = { + 'username': user.username, 'role': user.group, 'quota_act': True, + 'is_active': user.is_active, 'email': user.email, + 'mailboxes_limit': 2, 'mailbox_aliases_limit': 3 + } + resp = self.ajax_post( + reverse("admin:account_change", args=[user.id]), + values, 424 + ) + self.assertEqual(resp, 'Not enough resources') + self._check_limit('mailboxes', 1, 2) + self._check_limit('mailbox_aliases', 0, 2)