From abae9bb7c3fb59077e0a22ae501b8f4c8aed44d2 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Thu, 29 May 2025 14:28:08 +0200 Subject: [PATCH] More tests updated --- modoboa/admin/api/v1/tests.py | 18 + modoboa/admin/api/v2/serializers.py | 11 +- modoboa/admin/api/v2/tests.py | 155 +++- modoboa/admin/models/mxrecord.py | 3 +- modoboa/admin/tests/test_account.py | 704 +++--------------- modoboa/admin/tests/test_alias.py | 224 ++---- modoboa/admin/tests/test_domain.py | 420 ++--------- modoboa/admin/tests/test_domain_alias.py | 20 - modoboa/admin/tests/test_export.py | 121 ++- modoboa/admin/tests/test_import_.py | 167 +---- .../admin/tests/test_mailbox_operations.py | 21 +- modoboa/admin/tests/test_mx.py | 9 - modoboa/admin/tests/test_password_schemes.py | 13 +- modoboa/admin/tests/test_user.py | 49 -- modoboa/core/tests/test_ldap.py | 18 +- modoboa/dnstools/tests.py | 51 -- modoboa/lib/tests/__init__.py | 116 +++ modoboa/maillog/api/v2/tests.py | 23 +- modoboa/parameters/tools.py | 2 +- modoboa/policyd/tests.py | 23 +- 20 files changed, 640 insertions(+), 1528 deletions(-) delete mode 100644 modoboa/admin/tests/test_user.py diff --git a/modoboa/admin/api/v1/tests.py b/modoboa/admin/api/v1/tests.py index d443116de..c2f916e5a 100644 --- a/modoboa/admin/api/v1/tests.py +++ b/modoboa/admin/api/v1/tests.py @@ -72,6 +72,24 @@ class DomainAPITestCase(ModoAPITestCase): ) self.assertEqual(response.status_code, 403) + def test_create_utf8(self): + """Test the creation of a domain with non-ASCII characters.""" + url = reverse("v1:domain-list") + values = { + "name": "pouét.com", + "quota": 1000, + "default_mailbox_quota": 100, + "type": "domain", + } + response = self.client.post(url, values, format="json") + self.assertEqual(response.status_code, 201) + dom = models.Domain.objects.get(name="pouét.com") + self.assertEqual(dom.name, "pouét.com") + self.assertEqual(dom.quota, 1000) + self.assertEqual(dom.default_mailbox_quota, 100) + self.assertEqual(dom.enabled, False) + self.assertFalse(dom.admins) + @mock.patch.object(dns.resolver.Resolver, "resolve") @mock.patch("socket.getaddrinfo") def test_create_domain_with_mx_check(self, mock_getaddrinfo, mock_query): diff --git a/modoboa/admin/api/v2/serializers.py b/modoboa/admin/api/v2/serializers.py index 1ec7e6fa0..573533569 100644 --- a/modoboa/admin/api/v2/serializers.py +++ b/modoboa/admin/api/v2/serializers.py @@ -71,6 +71,15 @@ class DomainSerializer(v1_serializers.DomainSerializer): many=True, source="domainobjectlimit_set", required=False ) + def validate_enable_dkim(self, value): + """Check prerequisites.""" + if not value: + return value + storage_dir = param_tools.get_global_parameter("dkim_keys_storage_dir") + if not storage_dir: + raise ValidationError(_("DKIM keys storage directory not configured")) + return value + def validate(self, data): result = super().validate(data) dtype = data.get("type", "domain") @@ -205,7 +214,7 @@ class AdminGlobalParametersSerializer(serializers.Serializer): # Domain settings enable_mx_checks = serializers.BooleanField(default=True) - valid_mxs = serializers.CharField(allow_blank=True) + valid_mxs = serializers.CharField(default="", allow_blank=True) domains_must_have_authorized_mx = serializers.BooleanField(default=False) enable_ipv6_mx_checks = serializers.BooleanField(default=True) enable_spf_checks = serializers.BooleanField(default=True) diff --git a/modoboa/admin/api/v2/tests.py b/modoboa/admin/api/v2/tests.py index 006b49dc5..bd194c21e 100644 --- a/modoboa/admin/api/v2/tests.py +++ b/modoboa/admin/api/v2/tests.py @@ -7,7 +7,7 @@ from django.utils.encoding import force_str from rest_framework.authtoken.models import Token from modoboa.admin import factories, models, constants -from modoboa.core import models as core_models +from modoboa.core import factories as core_factories, models as core_models from modoboa.lib.tests import ModoAPITestCase @@ -98,6 +98,18 @@ class DomainViewSetTestCase(ModoAPITestCase): resp = self.client.post(url) self.assertEqual(resp.status_code, 204) + def test_delete_auto_account_removal(self): + self.set_global_parameter("auto_account_removal", True) + dom = models.Domain.objects.get(name="test2.com") + url = reverse("v2:domain-delete", args=[dom.pk]) + response = self.client.post(url, {}, format="json") + self.assertEqual(response.status_code, 204) + with self.assertRaises(models.Domain.DoesNotExist): + dom.refresh_from_db() + self.assertFalse( + core_models.User.objects.filter(username="admin@test2.com").exists() + ) + def test_administrators(self): domain = models.Domain.objects.get(name="test.com") url = reverse("v2:domain-administrators", args=[domain.pk]) @@ -169,8 +181,9 @@ class AccountViewSetTestCase(ModoAPITestCase): def test_create(self): url = reverse("v2:account-list") + username = "toto@test.com" data = { - "username": "toto@test.com", + "username": username, "role": "SimpleUsers", "mailbox": {"use_domain_quota": True}, "password": "Toto12345", @@ -180,6 +193,30 @@ class AccountViewSetTestCase(ModoAPITestCase): resp = self.client.post(url, data, format="json") self.assertEqual(resp.status_code, 201) self.assertTrue(models.Alias.objects.filter(address="alias3@test.com").exists()) + # Check if self alias has been created + self.assertTrue( + models.AliasRecipient.objects.select_related("alias") + .filter( + alias__address=username, + address=username, + alias__internal=True, + ) + .exists() + ) + + def test_create_with_existing_alias(self): + alias = models.Alias.objects.get(address="alias@test.com") + alias.set_recipients(["user@external.com"]) + values = { + "username": "tester@test.com", + "role": "SimpleUsers", + "mailbox": {"use_domain_quota": True}, + "is_active": True, + "aliases": ["alias@test.com"], + } + response = self.client.post(reverse("v2:account-list"), values, format="json") + self.assertTrue(response.status_code, 201) + self.assertTrue(alias.aliasrecipient_set.count() == 2) def test_create_admin(self): url = reverse("v2:account-list") @@ -241,12 +278,43 @@ class AccountViewSetTestCase(ModoAPITestCase): self.assertIn("password", resp.json()) def test_delete(self): - account = core_models.User.objects.get(username="user@test.com") + username = "user@test.com" + account = core_models.User.objects.get(username=username) url = reverse("v2:account-delete", args=[account.pk]) resp = self.client.post(url) self.assertEqual(resp.status_code, 204) with self.assertRaises(core_models.User.DoesNotExist): account.refresh_from_db() + # Check if self alias has been deleted + self.assertFalse( + models.AliasRecipient.objects.select_related("alias") + .filter( + alias__address=username, + address=username, + alias__internal=True, + ) + .exists() + ) + + def test_delete_default_superadmin(self): + """Delete default superadmin.""" + sadmin2 = core_factories.UserFactory(username="admin2", is_superuser=True) + sadmin = core_models.User.objects.get(username="admin") + self.authenticate_user(sadmin2) + response = self.client.post(reverse("v2:account-delete", args=[sadmin.pk]), {}) + self.assertEqual(response.status_code, 204) + values = { + "username": "user@test.com", + "role": "DomainAdmins", + "is_active": True, + "language": "en", + "mailbox": {"use_domain_quota": True}, + } + account = core_models.User.objects.get(username="user@test.com") + response = self.client.put( + reverse("v2:account-detail", args=[account.pk]), values, format="json" + ) + self.assertEqual(response.status_code, 200) def test_update(self): account = core_models.User.objects.get(username="user@test.com") @@ -261,6 +329,30 @@ class AccountViewSetTestCase(ModoAPITestCase): resp = self.client.patch(url, data, format="json") self.assertEqual(resp.status_code, 200) + def test_rename(self): + account = core_models.User.objects.get(username="user@test.com") + url = reverse("v2:account-detail", args=[account.pk]) + new_username = "user_updated@test.com" + data = { + "username": new_username, + "role": "SimpleUsers", + "password": "Toto12345", + "mailbox": {"quota": 10}, + "aliases": ["aliasupdate1@test.com"], + } + response = self.client.put(url, data, format="json") + self.assertEqual(response.status_code, 200) + # Check if self alias has been updated + self.assertTrue( + models.AliasRecipient.objects.select_related("alias") + .filter( + alias__address=new_username, + address=new_username, + alias__internal=True, + ) + .exists() + ) + def test_mailbox_options_update(self): account = core_models.User.objects.get(username="user@test.com") url = reverse("v2:account-detail", args=[account.pk]) @@ -408,6 +500,49 @@ class AccountViewSetTestCase(ModoAPITestCase): self.assertEqual(resp.status_code, 200) self.assertEqual(len(resp.json()["resources"]), 2) + def _set_quota(self, email, value, expected_status=200): + account = core_models.User.objects.get(username=email) + values = { + "username": email, + "role": "SimpleUsers", + "mailbox": {"use_domain_quota": False, "quota": value}, + "is_active": True, + "language": "en", + } + response = self.client.put( + reverse("v2:account-detail", args=[account.id]), values, format="json" + ) + self.assertEqual(response.status_code, expected_status) + + def test_set_nul_quota_as_superadmin(self): + self._set_quota("user@test.com", 0) + + def test_set_nul_quota_as_domainadmin(self): + """Check cases where a domain admin set unlimited quota.""" + dadmin = core_models.User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) + # Fails because domain has a quota + self._set_quota("user@test.com", 0, 400) + + dadmin = core_models.User.objects.get(username="admin@test2.com") + self.authenticate_user(dadmin) + # Ok because domain has no quota + self._set_quota("user@test2.com", 0) + + def test_domain_quota(self): + """Check domain quota.""" + dom = models.Domain.objects.get(name="test.com") + dom.quota = 100 + dom.save(update_fields=["quota"]) + # 2 x 10MB + self.assertEqual(dom.allocated_quota, 20) + self._set_quota("user@test.com", 80) + del dom.allocated_quota + # 10 + 80 < 100 => ok + self.assertEqual(dom.allocated_quota, 90) + # 30 + 80 > 100 => failure + self._set_quota("admin@test.com", 30, 400) + class IdentityViewSetTestCase(ModoAPITestCase): @classmethod @@ -525,6 +660,20 @@ class AliasViewSetTestCase(ModoAPITestCase): self.assertEqual(resp.status_code, 200) self.assertIn("address", resp.json()) + def test_create_on_existing_account(self): + values = { + "address": "user@test.com", + "recipients": ["ext@doman.test"], + "enabled": True, + } + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) + # Check that internal alias has not been updated + alias = models.Alias.objects.get(address="user@test.com", internal=True) + self.assertTrue(alias.aliasrecipient_set.count() == 1) + alias = models.Alias.objects.get(address="user@test.com", internal=False) + self.assertTrue(alias.aliasrecipient_set.count() == 1) + class UserAccountViewSetTestCase(ModoAPITestCase): @classmethod diff --git a/modoboa/admin/models/mxrecord.py b/modoboa/admin/models/mxrecord.py index 1eae36025..da6ae5f7e 100644 --- a/modoboa/admin/models/mxrecord.py +++ b/modoboa/admin/models/mxrecord.py @@ -13,7 +13,8 @@ class MXRecordQuerySet(models.QuerySet): def has_valids(self): """Return managed results.""" - if param_tools.get_global_parameter("valid_mxs").strip(): + valid_mxs = param_tools.get_global_parameter("valid_mxs") + if valid_mxs and valid_mxs.strip(): return self.filter(managed=True).exists() return self.exists() diff --git a/modoboa/admin/tests/test_account.py b/modoboa/admin/tests/test_account.py index 79d44a694..56f4299b8 100644 --- a/modoboa/admin/tests/test_account.py +++ b/modoboa/admin/tests/test_account.py @@ -6,12 +6,12 @@ from django.urls import reverse from modoboa.core import factories as core_factories from modoboa.core.models import User from modoboa.core.tests import test_ldap -from modoboa.lib.tests import NO_LDAP, ModoTestCase +from modoboa.lib.tests import NO_LDAP, ModoAPITestCase from modoboa.limits import utils as limits_utils from .. import factories, models -class AuthenticationTestCase(ModoTestCase): +class AuthenticationTestCase(ModoAPITestCase): """Check authentication.""" @classmethod @@ -34,10 +34,10 @@ class AuthenticationTestCase(ModoTestCase): data = {"username": self.mb.full_address, "password": password} response = self.client.post(reverse("core:login"), data) self.assertEqual(response.status_code, 302) - self.assertTrue(response.url.endswith(reverse("core:user_index"))) + self.assertEqual(response.url, "/") -class AccountTestCase(ModoTestCase): +class AccountTestCase(ModoAPITestCase): @classmethod def setUpTestData(cls): # NOQA:N802 @@ -45,154 +45,6 @@ class AccountTestCase(ModoTestCase): super().setUpTestData() factories.populate_database() - def test_crud(self): - values = { - "username": "tester@test.com", - "first_name": "Tester", - "last_name": "Toto", - "password1": "Toto1234", - "password2": "Toto1234", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "tester@test.com", - "stepid": "step2", - } - self.ajax_post(reverse("admin:account_add"), values) - - account = User.objects.get(username="tester@test.com") - mb = account.mailbox - self.assertEqual(mb.full_address, "tester@test.com") - self.assertEqual(mb.quota, 10) - self.assertTrue(mb.enabled) - self.assertEqual(mb.quota_value.username, "tester@test.com") - self.assertEqual(account.username, mb.full_address) - self.assertTrue(account.check_password("Toto1234")) - self.assertEqual(account.first_name, "Tester") - self.assertEqual(account.last_name, "Toto") - self.assertEqual(mb.domain.mailbox_count, 3) - # Check if self alias has been created - self.assertTrue( - models.AliasRecipient.objects.select_related("alias") - .filter( - alias__address=mb.full_address, - address=mb.full_address, - alias__internal=True, - ) - .exists() - ) - - values.update( - { - "username": "pouet@test.com", - "language": "en", - "secondary_email": "homer@simpson.com", - "phone_number": "+33612345678", - "subject": "subject", - "content": "content", - } - ) - self.ajax_post(reverse("admin:account_change", args=[account.id]), values) - account.refresh_from_db() - self.assertEqual(account.secondary_email, values["secondary_email"]) - mb = models.Mailbox.objects.get(pk=mb.pk) - self.assertEqual(mb.full_address, "pouet@test.com") - self.assertEqual(mb.quota_value.username, "pouet@test.com") - # Check if self alias has been updated - self.assertTrue( - models.AliasRecipient.objects.select_related("alias") - .filter( - alias__address=mb.full_address, - address=mb.full_address, - alias__internal=True, - ) - .exists() - ) - self.ajax_post(reverse("admin:account_delete", args=[account.id]), {}) - # Check if self alias has been deleted - self.assertFalse( - models.AliasRecipient.objects.select_related("alias") - .filter( - alias__address=mb.full_address, - address=mb.full_address, - alias__internal=True, - ) - .exists() - ) - - @override_settings(LANGUAGE_CODE="fr") - def test_create_account_default_lang(self): - """Check if default language is applied.""" - values = { - "username": "tester@test.com", - "first_name": "Tester", - "last_name": "Toto", - "password1": "Toto1234", - "password2": "Toto1234", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "tester@test.com", - "stepid": "step2", - } - self.ajax_post(reverse("admin:account_add"), values) - account = User.objects.get(username=values["username"]) - self.assertEqual(account.language, "fr") - - def test_create_account_with_existing_alias(self): - alias = models.Alias.objects.get(address="alias@test.com") - alias.set_recipients(["user@external.com"]) - values = { - "email": "tester@test.com", - "username": "tester@test.com", - "role": "SimpleUsers", - "random_password": "on", - "quota_act": True, - "is_active": True, - "stepid": "step2", - "aliases": "alias@test.com", - } - self.ajax_post(reverse("admin:account_add"), values) - self.assertTrue(alias.aliasrecipient_set.count() == 2) - - def test_create_alias_on_existing_account(self): - values = { - "email": "tester@test.com", - "username": "tester@test.com", - "role": "SimpleUsers", - "random_password": "on", - "quota_act": True, - "is_active": True, - "stepid": "step2", - "aliases": "user@test.com", - } - self.ajax_post(reverse("admin:account_add"), values) - # Check that internal alias has not been updated - alias = models.Alias.objects.get(address="user@test.com", internal=True) - self.assertTrue(alias.aliasrecipient_set.count() == 1) - alias = models.Alias.objects.get(address="user@test.com", internal=False) - self.assertTrue(alias.aliasrecipient_set.count() == 1) - - def test_create_disabled_account(self): - """Check if account and alias are disabled.""" - values = { - "username": "tester@test.com", - "first_name": "Tester", - "last_name": "Toto", - "password1": "Toto1234", - "password2": "Toto1234", - "role": "SimpleUsers", - "quota_act": True, - "is_active": False, - "email": "tester@test.com", - "stepid": "step2", - } - self.ajax_post(reverse("admin:account_add"), values) - account = User.objects.get(username=values["username"]) - self.assertEqual(account.enabled, False) - alias = models.Alias.objects.get(address=account.email) - self.assertEqual(alias.enabled, False) - def test_aliases_update_on_disable(self): """Check if aliases are updated when account is disabled.""" account = User.objects.get(username="user@test.com") @@ -220,371 +72,6 @@ class AccountTestCase(ModoTestCase): forward.refresh_from_db() self.assertTrue(forward.enabled) - def test_aliases_update_on_rename(self): - """Check if aliases are updated on mailbox rename.""" - account = User.objects.get(username="user@test.com") - values = { - "username": "new_user@test.com", - "first_name": account.first_name, - "last_name": account.last_name, - "role": account.role, - "quota_act": True, - "is_active": account.is_active, - "email": "new_user@test.com", - "language": "en", - "subject": "subject", - "content": "content", - "create_alias_with_old_address": False, - "aliases_1": "alias@test.com", - } - url = reverse("admin:account_change", args=[account.pk]) - self.ajax_post(url, values) - qset = account.mailbox.aliasrecipient_set.filter(alias__internal=False) - for alr in qset: - self.assertEqual(alr.address, values["email"]) - - def test_create_alias_on_rename(self): - """Check if alias is automatically created.""" - account = User.objects.get(username="user@test.com") - values = { - "username": "new_user@test.com", - "first_name": account.first_name, - "last_name": account.last_name, - "role": account.role, - "quota_act": True, - "is_active": account.is_active, - "email": "new_user@test.com", - "language": "en", - "subject": "subject", - "content": "content", - "create_alias_with_old_address": False, - } - url = reverse("admin:account_change", args=[account.pk]) - # Rename while option is set to False -> no alias created - self.ajax_post(url, values) - self.assertFalse( - models.AliasRecipient.objects.filter( - address="new_user@test.com", - alias__address="user@test.com", - alias__internal=False, - ).exists() - ) - # Now rename while option set to True -> alias created - values.update( - { - "username": "user@test.com", - "email": "user@test.com", - "create_alias_with_old_address": True, - } - ) - self.ajax_post(url, values) - self.assertTrue( - models.AliasRecipient.objects.filter( - address="user@test.com", - alias__address="new_user@test.com", - alias__internal=False, - ).exists() - ) - # Change domain while option set to True -> alias created - values.update( - { - "username": "new_user@test2.com", - "email": "new_user@test2.com", - } - ) - self.ajax_post(url, values) - self.assertTrue( - models.AliasRecipient.objects.filter( - address="new_user@test2.com", - alias__address="user@test.com", - alias__domain__name="test.com", - alias__internal=False, - ).exists() - ) - - def test_password_constraints(self): - """Check password constraints.""" - values = { - "username": "tester@test.com", - "first_name": "Tester", - "last_name": "Toto", - "password1": "", - "password2": "", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "tester@test.com", - "stepid": "step2", - } - resp = self.ajax_post(reverse("admin:account_add"), values, 400) - self.assertEqual(resp["form_errors"]["password1"][0], "This field is required.") - values["password1"] = "Toto1234" - values["password2"] = "Toto12345" - resp = self.ajax_post(reverse("admin:account_add"), values, 400) - self.assertEqual( - resp["form_errors"]["password2"][0], "The two password fields didn't match." - ) - - values["password1"] = "toto1234" - values["password2"] = "toto1234" - resp = self.ajax_post(reverse("admin:account_add"), values, 400) - self.assertEqual( - resp["form_errors"]["password2"][0], - "Password must contain at least 1 uppercase letter.", - ) - - def test_random_password(self): - """Try to create an account with a random password.""" - values = { - "username": "tester@test.com", - "first_name": "Tester", - "last_name": "Toto", - "random_password": True, - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "tester@test.com", - "stepid": "step2", - } - self.ajax_post(reverse("admin:account_add"), values) - - account = User.objects.get(username=values["username"]) - password = account.password - values["language"] = "en" - values["subject"] = "subject" - values["content"] = "content" - # Since 'random_password' is still True, a new password should - # be generated - self.ajax_post(reverse("admin:account_change", args=[account.pk]), values) - account.refresh_from_db() - self.assertNotEqual(password, account.password) - password = account.password - - values["random_password"] = False - self.ajax_post(reverse("admin:account_change", args=[account.pk]), values) - account.refresh_from_db() - self.assertEqual(password, account.password) - - def test_delete_default_superadmin(self): - """Delete default superadmin.""" - sadmin2 = core_factories.UserFactory(username="admin2", is_superuser=True) - sadmin = User.objects.get(username="admin") - self.client.force_login(sadmin2) - self.ajax_post(reverse("admin:account_delete", args=[sadmin.pk]), {}) - values = { - "username": "user@test.com", - "role": "DomainAdmins", - "is_active": True, - "email": "user@test.com", - "language": "en", - "subject": "subject", - "content": "content", - } - account = User.objects.get(username="user@test.com") - self.ajax_post(reverse("admin:account_change", args=[account.pk]), values) - - def test_sender_address(self): - """Check if sender addresses are saved.""" - account = User.objects.get(username="user@test.com") - values = { - "username": "user@test.com", - "first_name": "Tester", - "last_name": "Toto", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "user@test.com", - "senderaddress": "test@titi.com", - "senderaddress_1": "toto@go.com", - "language": "en", - "subject": "subject", - "content": "content", - } - self.ajax_post(reverse("admin:account_change", args=[account.pk]), values) - self.assertEqual( - models.SenderAddress.objects.filter(mailbox__address="user").count(), 2 - ) - del values["senderaddress_1"] - self.ajax_post(reverse("admin:account_change", args=[account.pk]), values) - self.assertEqual( - models.SenderAddress.objects.filter(mailbox__address="user").count(), 1 - ) - - def test_sender_address_as_domainadmin(self): - """Check that restrictions are applied.""" - admin = User.objects.get(username="admin@test.com") - self.client.force_login(admin) - account = User.objects.get(username="user@test.com") - values = { - "username": "user@test.com", - "first_name": "Tester", - "last_name": "Toto", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "user@test.com", - "senderaddress": "test@titi.com", - "senderaddress_1": "toto@test2.com", - } - response = self.ajax_post( - reverse("admin:account_change", args=[account.pk]), values, 400 - ) - self.assertEqual( - response["form_errors"]["senderaddress_1"][0], - "You don't have access to this domain", - ) - - def test_conflicts(self): - """Check if unicity constraints are respected.""" - values = { - "username": "user@test.com", - "password1": "Toto1234", - "password2": "Toto1234", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "user@test.com", - "stepid": "step2", - } - self.ajax_post(reverse("admin:account_add"), values, status=400) - - values.update({"username": "fakeuser@test.com", "email": "fakeuser@test.com"}) - self.ajax_post(reverse("admin:account_add"), values) - account = User.objects.get(username="fakeuser@test.com") - values = { - "username": "user@test.com", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "user@test.com", - } - self.ajax_post( - reverse("admin:account_change", args=[account.pk]), values, status=400 - ) - - def test_utf8_username(self): - """Create an account with non-ASCII characters.""" - values = { - "username": "téster@test.com", - "first_name": "Tester", - "last_name": "Toto", - "password1": "Toto1234", - "password2": "Toto1234", - "role": "SimpleUsers", - "quota_act": True, - "is_active": True, - "email": "téster@test.com", - "stepid": "step2", - } - self.ajax_post(reverse("admin:account_add"), values) - - def _set_quota(self, email, value, expected_status=200): - account = User.objects.get(username=email) - values = { - "username": email, - "role": "SimpleUsers", - "quota_act": False, - "is_active": True, - "quota": value, - "email": email, - "language": "en", - "subject": "subject", - "content": "content", - } - self.ajax_post( - reverse("admin:account_change", args=[account.id]), - values, - status=expected_status, - ) - - def test_set_nul_quota_as_superadmin(self): - self._set_quota("user@test.com", 0) - - def test_set_nul_quota_as_domainadmin(self): - """Check cases where a domain admin set unlimited quota.""" - self.client.logout() - self.assertTrue(self.client.login(username="admin@test.com", password="toto")) - # Fails because domain has a quota - self._set_quota("user@test.com", 0, 400) - self.client.logout() - self.assertTrue(self.client.login(username="admin@test2.com", password="toto")) - # Ok because domain has no quota - self._set_quota("user@test2.com", 0) - - def test_domain_quota(self): - """Check domain quota.""" - dom = models.Domain.objects.get(name="test.com") - dom.quota = 100 - dom.save(update_fields=["quota"]) - # 2 x 10MB - self.assertEqual(dom.allocated_quota, 20) - self._set_quota("user@test.com", 80) - del dom.allocated_quota - # 10 + 80 < 100 => ok - self.assertEqual(dom.allocated_quota, 90) - # 30 + 80 > 100 => failure - self._set_quota("admin@test.com", 30, 400) - - def test_master_user(self): - """Validate the master user mode.""" - values = { - "username": "masteruser", - "role": "SuperAdmins", - "quota_act": False, - "is_active": True, - "master_user": True, - "stepid": "step2", - "password1": "Toto1234", - "password2": "Toto1234", - } - self.ajax_post(reverse("admin:account_add"), values) - self.assertTrue(User.objects.get(username="masteruser").master_user) - - values = { - "username": "testuser", - "role": "DomainAdmins", - "quota_act": False, - "is_active": True, - "master_user": True, - "stepid": "step2", - "password1": "Toto1234", - "password2": "Toto1234", - } - self.ajax_post(reverse("admin:account_add"), values, status=400) - - def test_account_detail_view(self): - """Test account detail view.""" - self.set_global_parameter("enable_admin_limits", False, app="limits") - account = User.objects.get(username="admin@test.com") - url = reverse("admin:account_detail", args=[account.pk]) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertIn("Summary", response.content.decode()) - self.assertIn("Administered domains", response.content.decode()) - self.assertNotIn("Resources usage", response.content.decode()) - self.set_global_parameter("enable_admin_limits", True, app="limits") - response = self.client.get(url) - self.assertIn("Resources usage", response.content.decode()) - - def test_quota_list_view(self): - """Test quota list view.""" - models.Quota.objects.filter(username="user@test.com").update(bytes=5 * 1048576) - url = reverse("admin:identity_quota_list") - response = self.ajax_get(url) - self.assertIn("5M", response["rows"]) - self.assertIn('title="50%"', response["rows"]) - self.assertIn("user@test.com", response["rows"]) - old_rows = response["rows"] - - response = self.ajax_get(f"{url}?sort_order=-quota_value__bytes") - self.assertNotEqual(old_rows, response["rows"]) - old_rows = response["rows"] - - response = self.ajax_get(f"{url}?sort_order=-quota_usage") - self.assertEqual(old_rows, response["rows"]) - - response = self.ajax_get(f"{url}?sort_order=-unknown", status=400) - @skipIf(NO_LDAP, "No ldap module installed") @override_settings( @@ -593,7 +80,7 @@ class AccountTestCase(ModoTestCase): "django.contrib.auth.backends.ModelBackend", ) ) -class LDAPAccountTestCase(test_ldap.LDAPTestCaseMixin, ModoTestCase): +class LDAPAccountTestCase(test_ldap.LDAPTestCaseMixin, ModoAPITestCase): """Check LDAP related code.""" def test_autocreate_disabled(self): @@ -607,7 +94,7 @@ class LDAPAccountTestCase(test_ldap.LDAPTestCaseMixin, ModoTestCase): self.assertFalse(models.Mailbox.objects.filter(address="testuser").exists()) -class PermissionsTestCase(ModoTestCase): +class PermissionsTestCase(ModoAPITestCase): @classmethod def setUpTestData(cls): # NOQA:N802 @@ -630,32 +117,34 @@ class PermissionsTestCase(ModoTestCase): "username": self.user.username, "role": "DomainAdmins", "is_active": self.user.is_active, - "email": "user@test.com", - "quota_act": True, + "mailbox": { + "use_domain_quota": True, + }, "language": "en", - "subject": "subject", - "content": "content", } - def tearDown(self): - self.client.logout() - def test_domain_admins(self): factories.DomainFactory(name="test2.com") - self.ajax_post( - reverse("admin:account_change", args=[self.user.id]), self.values + response = self.client.put( + reverse("v2:account-detail", args=[self.user.id]), + self.values, + format="json", ) + self.assertEqual(response.status_code, 200) self.assertEqual(self.user.role, "DomainAdmins") - self.values["mailboxes_limit"] = "0" - self.values["mailbox_aliases_limit"] = "0" - self.values["domains"] = "" - self.values["domains_1"] = "test.com" - self.values["domains_2"] = "test2.com" - self.ajax_post( - reverse("admin:account_change", args=[self.user.id]), self.values + self.values["resources"] = [ + {"name": "mailboxes", "max_value": 0}, + {"name": "mailbox_aliases", "max_value": 0}, + ] + self.values["domains"] = ["test.com", "test2.com"] + response = self.client.put( + reverse("v2:account-detail", args=[self.user.id]), + self.values, + format="json", ) + self.assertEqual(response.status_code, 200) self.assertIn( self.user, models.Domain.objects.get(name="test.com").admins.all() ) @@ -663,10 +152,13 @@ class PermissionsTestCase(ModoTestCase): self.user, models.Domain.objects.get(name="test2.com").admins.all() ) - del self.values["domains_2"] - self.ajax_post( - reverse("admin:account_change", args=[self.user.id]), self.values + self.values["domains"].remove("test2.com") + response = self.client.put( + reverse("v2:account-detail", args=[self.user.id]), + self.values, + format="json", ) + self.assertEqual(response.status_code, 200) self.assertIn( self.user, models.Domain.objects.get(name="test.com").admins.all() ) @@ -675,9 +167,12 @@ class PermissionsTestCase(ModoTestCase): ) self.values["role"] = "SimpleUsers" - self.ajax_post( - reverse("admin:account_change", args=[self.user.id]), self.values + response = self.client.put( + reverse("v2:account-detail", args=[self.user.id]), + self.values, + format="json", ) + self.assertEqual(response.status_code, 200) self.assertFalse(self.user.groups.filter(name="DomainAdmins").exists()) self.assertNotIn( self.user, models.Domain.objects.get(name="test.com").admins.all() @@ -685,74 +180,72 @@ class PermissionsTestCase(ModoTestCase): def test_superusers(self): self.values["role"] = "SuperAdmins" - self.ajax_post( - reverse("admin:account_change", args=[self.user.id]), self.values + response = self.client.put( + reverse("v2:account-detail", args=[self.user.id]), + self.values, + format="json", ) + self.assertEqual(response.status_code, 200) self.assertEqual(User.objects.get(username="user@test.com").is_superuser, True) self.values["role"] = "SimpleUsers" - self.ajax_post( - reverse("admin:account_change", args=[self.user.id]), self.values + response = self.client.put( + reverse("v2:account-detail", args=[self.user.id]), + self.values, + format="json", ) + self.assertEqual(response.status_code, 200) self.assertEqual(User.objects.get(username="user@test.com").is_superuser, False) def test_self_modif(self): - self.client.logout() - self.assertTrue(self.client.login(username="admin@test.com", password="toto")) - admin = User.objects.get(username="admin@test.com") + dadmin = User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) + values = { "username": "admin@test.com", "first_name": "Admin", - "password1": "", - "password2": "", - "quota": 10, + "role": "DomainAdmins", + "mailbox": { + "quota": 10, + }, "is_active": True, - "email": "admin@test.com", "language": "en", - "subject": "subject", - "content": "content", } - self.ajax_post(reverse("admin:account_change", args=[admin.id]), values) - self.assertEqual(admin.role, "DomainAdmins") - self.assertTrue(admin.can_access(models.Domain.objects.get(name="test.com"))) + response = self.client.put( + reverse("v2:account-detail", args=[dadmin.id]), values, format="json" + ) + print(response.json()) + self.assertEqual(response.status_code, 200) + self.assertEqual(dadmin.role, "DomainAdmins") + self.assertTrue(dadmin.can_access(models.Domain.objects.get(name="test.com"))) values["role"] = "SuperAdmins" - self.ajax_post(reverse("admin:account_change", args=[admin.id]), values) - admin.refresh_from_db() - self.assertEqual(admin.role, "DomainAdmins") + response = self.client.put( + reverse("v2:account-detail", args=[dadmin.id]), values, format="json" + ) + self.assertEqual(response.status_code, 200) + dadmin.refresh_from_db() + self.assertEqual(dadmin.role, "DomainAdmins") - self.client.logout() - self.client.login(username=self.reseller.username, password="toto") + self.authenticate_user(self.reseller) self.assertTrue(self.reseller.can_access(self.reseller)) values = { "username": self.reseller.username, "first_name": "Reseller", - "password1": "", - "password2": "", "is_active": True, "language": "en", - "subject": "subject", - "content": "content", } - self.ajax_post(reverse("admin:account_change", args=[self.reseller.pk]), values) + response = self.client.put( + reverse("v2:account-detail", args=[self.reseller.id]), values, format="json" + ) + self.assertEqual(response.status_code, 200) self.assertEqual(self.reseller.role, "Resellers") values["role"] = "SuperAdmins" - self.ajax_post(reverse("admin:account_change", args=[self.reseller.pk]), values) - self.assertEqual(self.reseller.role, "Resellers") - - def test_domadmin_access(self): - self.client.logout() - self.assertEqual( - self.client.login(username="admin@test.com", password="toto"), True + response = self.client.put( + reverse("v2:account-detail", args=[self.reseller.id]), values, format="json" ) - response = self.client.get(reverse("admin:domain_list")) self.assertEqual(response.status_code, 200) - - response = self.client.get( - reverse("admin:account_change", args=[self.user.id]), - HTTP_X_REQUESTED_WITH="XMLHttpRequest", - ) - self.assertNotEqual(response["Content-Type"], "application/json") + self.assertEqual(self.reseller.role, "Resellers") def test_domainadmin_deletes_superadmin(self): """Check domain admins restrictions about super admins @@ -765,45 +258,51 @@ class PermissionsTestCase(ModoTestCase): "username": "superadmin2@test.com", "first_name": "Super", "last_name": "Admin", - "password1": "Toto1234", - "password2": "Toto1234", + "password": "Toto1234", "role": "SuperAdmins", "is_active": True, - "email": "superadmin2@test.com", - "stepid": "step2", } - self.ajax_post(reverse("admin:account_add"), values) + response = self.client.post(reverse("v2:account-list"), values, format="json") + self.assertEqual(response.status_code, 201) + account = User.objects.get(username="superadmin2@test.com") - self.client.logout() - self.client.login(username="admin@test.com", password="toto") - self.ajax_post(reverse("admin:account_delete", args=[account.id]), {}, 403) + dadmin = User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) + response = self.client.post( + reverse("v2:account-delete", args=[account.id]), {}, format="json" + ) + self.assertEqual(response.status_code, 404) def test_domainadmin_dlist_local_domain_not_owned(self): """Check if a domain admin can use a local mailbox he can't access as a recipient in a distribution list""" + dadmin = User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) values = { "address": "all@test.com", - "recipients": "user@test.com", - "recipients_1": "user@test2.com", + "recipients": ["user@test.com", "user@test2.com"], "enabled": True, } - self.ajax_post(reverse("admin:alias_add"), values) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) def test_domainadmin_master_user(self): """Check domain administrator is not allowed to access this feature.""" + dadmin = User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) values = { "username": "user10@test.com", "first_name": "Test", "last_name": "Test", - "password1": "Toto1234", - "password2": "Toto1234", + "password": "Toto1234", "role": "SimpleUsers", "is_active": True, "master_user": True, - "email": "user10@test.com", - "stepid": "step2", } - self.ajax_post(reverse("admin:account_add"), values, status=400) + response = self.client.post(reverse("v2:account-list"), values, format="json") + self.assertEqual(response.status_code, 201) + user = User.objects.get(username="user10@test.com") + self.assertFalse(user.master_user) def test_domadmins_permissions(self): """ @@ -819,19 +318,16 @@ class PermissionsTestCase(ModoTestCase): user__password="{PLAIN}toto", ) dom.add_admin(mb.user) - self.client.logout() - self.assertTrue(self.client.login(username="admin@test.com", password="toto")) + dadmin = User.objects.get(username="admin@test.com") + self.authenticate_user(dadmin) values = { "username": "new@test.com", - "password1": "Toto1234", - "password2": "Toto1234", + "password": "Toto1234", "role": "SimpleUsers", - "quota_act": True, + "mailbox": {"use_domain_quota": True}, "is_active": True, - "email": "new@test.com", - "stepid": "step2", } - self.ajax_post(reverse("admin:account_add"), values) + self.client.post(reverse("v2:account-list"), values, format="json") new_mb = models.Mailbox.objects.get(user__username="new@test.com") self.assertTrue(mb.user.can_access(new_mb)) diff --git a/modoboa/admin/tests/test_alias.py b/modoboa/admin/tests/test_alias.py index f2984bdd1..ff5318551 100644 --- a/modoboa/admin/tests/test_alias.py +++ b/modoboa/admin/tests/test_alias.py @@ -3,12 +3,12 @@ from django.urls import reverse from modoboa.core.models import User -from modoboa.lib.tests import ModoTestCase +from modoboa.lib.tests import ModoAPITestCase from .. import factories -from ..models import Alias, AliasRecipient, Domain +from ..models import Alias, AliasRecipient -class AliasTestCase(ModoTestCase): +class AliasTestCase(ModoAPITestCase): @classmethod def setUpTestData(cls): # NOQA:N802 @@ -16,44 +16,15 @@ class AliasTestCase(ModoTestCase): super().setUpTestData() factories.populate_database() - def test_alias(self): - user = User.objects.get(username="user@test.com") - values = { - "username": "user@test.com", - "role": user.role, - "is_active": user.is_active, - "email": "user@test.com", - "aliases": "toto@test.com", - "aliases_1": "titi@test.com", - "language": "en", - "subject": "subject", - "content": "content", - } - self.ajax_post(reverse("admin:account_change", args=[user.id]), values) - self.assertEqual( - AliasRecipient.objects.filter( - alias__internal=False, r_mailbox=user.mailbox - ).count(), - 2, - ) - del values["aliases_1"] - self.ajax_post(reverse("admin:account_change", args=[user.id]), values) - self.assertEqual( - AliasRecipient.objects.filter( - alias__internal=False, r_mailbox=user.mailbox - ).count(), - 1, - ) - def test_alias_with_duplicated_recipient(self): """Check for duplicates.""" values = { "address": "badalias@test.com", - "recipients": "user@test.com", - "recipients_1": "user@test.com", + "recipients": ["user@test.com", "user@test.com"], "enabled": True, } - self.ajax_post(reverse("admin:alias_add"), values) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) alias = Alias.objects.get(address="badalias@test.com") self.assertEqual(alias.recipients_count, 1) @@ -61,56 +32,32 @@ class AliasTestCase(ModoTestCase): """Try to create an upper case alias.""" user = User.objects.get(username="user@test.com") values = { - "username": "user@test.com", - "role": user.role, - "is_active": user.is_active, - "email": "user@test.com", - "aliases": "Toto@test.com", - "language": "en", - "subject": "subject", - "content": "content", + "address": "Toto@test.com", + "recipients": ["user@test.com"], + "enabled": True, } - self.ajax_post(reverse("admin:account_change", args=[user.id]), values) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) mb = user.mailbox self.assertEqual( AliasRecipient.objects.filter(alias__internal=False, r_mailbox=mb).count(), - 1, + 2, ) - self.assertEqual( - AliasRecipient.objects.get( - alias__internal=False, r_mailbox=mb - ).alias.address, - "toto@test.com", + self.assertTrue( + AliasRecipient.objects.filter( + alias__internal=False, r_mailbox=mb, alias__address="toto@test.com" + ).exists() ) - values = { - "address": "Titi@test.com", - "recipients": "user@test.com", - "enabled": True, - } - self.ajax_post(reverse("admin:alias_add"), values) - self.assertTrue(Alias.objects.filter(address="titi@test.com").exists()) - def test_append_alias_with_tag(self): """Try to create a alias with tag in recipient address""" - user = User.objects.get(username="user@test.com") - values = { - "username": "user@test.com", - "role": user.role, - "is_active": user.is_active, - "email": "user@test.com", - "language": "en", - "subject": "subject", - "content": "content", - } - self.ajax_post(reverse("admin:account_change", args=[user.id]), values) - values = { "address": "foobar@test.com", - "recipients": "user+spam@test.com", + "recipients": ["user+spam@test.com"], "enabled": True, } - self.ajax_post(reverse("admin:alias_add"), values) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) alias = Alias.objects.get(address="foobar@test.com") self.assertTrue( alias.aliasrecipient_set.filter( @@ -124,22 +71,20 @@ class AliasTestCase(ModoTestCase): """Test alias with non-ASCII characters.""" values = { "address": "testé@test.com", - "recipients": "user@test.com", - "recipients_1": "admin@test.com", - "recipients_2": "ext@titi.com", + "recipients": ["user@test.com", "admin@test.com", "ext@titi.com"], "enabled": True, } - self.ajax_post(reverse("admin:alias_add"), values) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertTrue(response.status_code, 201) def test_dlist(self): values = { "address": "all@test.com", - "recipients": "user@test.com", - "recipients_1": "admin@test.com", - "recipients_2": "ext@titi.com", + "recipients": ["user@test.com", "admin@test.com", "ext@titi.com"], "enabled": True, } - self.ajax_post(reverse("admin:alias_add"), values) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) user = User.objects.get(username="user@test.com") mb = user.mailbox self.assertEqual( @@ -154,39 +99,29 @@ class AliasTestCase(ModoTestCase): ) dlist = Alias.objects.get(address="all@test.com") self.assertEqual(dlist.recipients_count, 3) - del values["recipients_1"] - self.ajax_post(reverse("admin:alias_change", args=[dlist.id]), values) + values["recipients"].remove("admin@test.com") + response = self.client.put( + reverse("v2:alias-detail", args=[dlist.id]), values, format="json" + ) + self.assertEqual(response.status_code, 200) self.assertEqual(dlist.recipients_count, 2) - self.ajax_delete( - "{}?selection={}".format(reverse("admin:alias_delete"), dlist.id) - ) - self.assertRaises(Alias.DoesNotExist, Alias.objects.get, address="all@test.com") - - def test_forward(self): - values = {"address": "forward2@test.com", "recipients": "rcpt@dest.com"} - self.ajax_post(reverse("admin:alias_add"), values) - fwd = Alias.objects.get(address="forward2@test.com") - self.assertEqual(fwd.recipients_count, 1) - - values["recipients"] = "rcpt2@dest.com" - self.ajax_post(reverse("admin:alias_change", args=[fwd.id]), values) - self.assertEqual(fwd.recipients_count, 1) - - self.ajax_delete(reverse("admin:alias_delete") + f"?selection={fwd.id}", {}) - self.assertRaises( - Alias.DoesNotExist, Alias.objects.get, address="forward2@test.com" - ) - def test_forward_and_local_copies(self): - values = {"address": "user@test.com", "recipients": "rcpt@dest.com"} - self.ajax_post(reverse("admin:alias_add"), values) + values = { + "address": "user@test.com", + "recipients": ["rcpt@dest.com"], + "enabled": True, + } + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) fwd = Alias.objects.get(address="user@test.com", internal=False) self.assertEqual(fwd.recipients_count, 1) - values["recipients"] = "rcpt@dest.com" - values["recipients_1"] = "user@test.com" - self.ajax_post(reverse("admin:alias_change", args=[fwd.id]), values) + values["recipients"] = ["rcpt@dest.com", "user@test.com"] + response = self.client.put( + reverse("v2:alias-detail", args=[fwd.id]), values, format="json" + ) + self.assertEqual(response.status_code, 200) fwd = Alias.objects.get(pk=fwd.pk) self.assertEqual(fwd.aliasrecipient_set.count(), 2) self.assertEqual(fwd.aliasrecipient_set.filter(r_alias__isnull=True).count(), 2) @@ -195,26 +130,11 @@ class AliasTestCase(ModoTestCase): """Test creation of a wildcard alias.""" values = { "address": "@test.com", - "recipients": "user@test.com", + "recipients": ["user@test.com"], "enabled": True, } - self.ajax_post(reverse("admin:alias_add"), values) - - def test_random_alias(self): - """Test creation of a random alias.""" - alias_count = Alias.objects.count() - values = { - "random_address": True, - "domain": Domain.objects.get(name="test.com").pk, - "recipients": "user@test.com", - "enabled": True, - } - self.ajax_post(reverse("admin:alias_add"), values) - self.assertEqual(Alias.objects.count(), alias_count + 1) - - del values["domain"] - content = self.ajax_post(reverse("admin:alias_add"), values, 400) - self.assertIn("domain", content["form_errors"]) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) def test_distribution_list_deletion_on_user_update_bug(self): """This test demonstrates an issue with distribution list being @@ -224,61 +144,45 @@ class AliasTestCase(ModoTestCase): """ values = { "address": "list@test.com", - "recipients": "user@test.com", - "recipients_1": "admin@test.com", + "recipients": ["user@test.com", "admin@test.com"], "enabled": True, } - self.ajax_post(reverse("admin:alias_add"), values) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 201) user = User.objects.get(username="user@test.com") values = { "username": user.username, "first_name": "Tester", "last_name": "Toto", - "password1": "Toto1234", - "password2": "Toto1234", + "password": "Toto1234", "role": "SimpleUsers", - "quota_act": True, + "mailbox": { + "use_domain_quota": True, + }, "is_active": True, "email": user.email, "language": "en", - "subject": "subject", - "content": "content", } - self.ajax_post(reverse("admin:account_change", args=[user.id]), values) - - self.assertEqual(Alias.objects.filter(address="list@test.com").count(), 1) - - def test_alias_detail_view(self): - """Test alias detail view.""" - account = Alias.objects.get(address="postmaster@test.com") - url = reverse("admin:alias_detail", args=[account.pk]) - response = self.client.get(url) + response = self.client.put( + reverse("v2:account-detail", args=[user.id]), values, format="json" + ) self.assertEqual(response.status_code, 200) - self.assertIn("Summary", response.content.decode()) - self.assertIn("Recipients", response.content.decode()) + self.assertTrue(Alias.objects.filter(address="list@test.com").exists()) def test_domainadmin_restrictions(self): """Check that restrictions are applied.""" admin = User.objects.get(username="admin@test.com") - self.client.force_login(admin) + self.authenticate_user(admin) - user = User.objects.get(username="user@test.com") values = { - "username": "user@test.com", - "role": user.role, - "is_active": user.is_active, - "email": "user@test.com", - "aliases": "toto@test.com", - "aliases_1": "titi@test2.com", - "language": "en", - "subject": "subject", - "content": "content", + "address": "titi@test2.com", + "recipients": ["user@test.com"], + "enabled": True, } - response = self.ajax_post( - reverse("admin:account_change", args=[user.id]), values, 400 - ) + response = self.client.post(reverse("v2:alias-list"), values, format="json") + self.assertEqual(response.status_code, 400) self.assertEqual( - response["form_errors"]["aliases_1"][0], - "You don't have access to this domain", + response.json()["address"][0], + "Permission denied.", ) diff --git a/modoboa/admin/tests/test_domain.py b/modoboa/admin/tests/test_domain.py index 1b3859276..89d76226c 100644 --- a/modoboa/admin/tests/test_domain.py +++ b/modoboa/admin/tests/test_domain.py @@ -3,30 +3,21 @@ import os import shutil import tempfile -from unittest import mock -from dateutil.relativedelta import relativedelta -import dns.resolver from testfixtures import compare from django.core.management import call_command from django.urls import reverse -from django.utils import timezone -from django.utils.html import escape -from modoboa.core import factories as core_factories from modoboa.core.models import User -from modoboa.core.tests.test_views import SETTINGS_SAMPLE -from modoboa.lib.tests import ModoTestCase -from modoboa.maillog import factories as ml_factories +from modoboa.lib.tests import ModoAPITestCase, SETTINGS_SAMPLE from .. import constants -from . import utils from .. import factories from ..models import Alarm, Alias, Domain -class DomainTestCase(ModoTestCase): +class DomainTestCase(ModoAPITestCase): """Test case for Domain.""" @classmethod @@ -35,135 +26,21 @@ class DomainTestCase(ModoTestCase): super().setUpTestData() factories.populate_database() - def test_create(self): - """Test the creation of a domain.""" - values = { - "name": "pouet.com", - "quota": 1000, - "default_mailbox_quota": 100, - "create_dom_admin": False, - "type": "domain", - "stepid": "step3", - } - self.ajax_post(reverse("admin:domain_add"), values) - dom = Domain.objects.get(name="pouet.com") - self.assertEqual(dom.name, "pouet.com") - self.assertEqual(dom.quota, 1000) - self.assertEqual(dom.default_mailbox_quota, 100) - self.assertEqual(dom.enabled, False) - self.assertFalse(dom.admins) - - def test_create_utf8(self): - """Test the creation of a domain with non-ASCII characters.""" - values = { - "name": "pouét.com", - "quota": 1000, - "default_mailbox_quota": 100, - "create_dom_admin": False, - "type": "domain", - "stepid": "step3", - } - self.ajax_post(reverse("admin:domain_add"), values) - dom = Domain.objects.get(name="pouét.com") - self.assertEqual(dom.name, "pouét.com") - self.assertEqual(dom.quota, 1000) - self.assertEqual(dom.default_mailbox_quota, 100) - self.assertEqual(dom.enabled, False) - self.assertFalse(dom.admins) - - def test_create_with_template(self): - """Test the creation of a domain with a template.""" - values = { - "name": "pouet.com", - "quota": 1000, - "default_mailbox_quota": 100, - "create_dom_admin": True, - "dom_admin_username": "toto", - "with_mailbox": True, - "create_aliases": True, - "type": "domain", - "stepid": "step3", - } - self.ajax_post(reverse("admin:domain_add"), values) - dom = Domain.objects.get(name="pouet.com") - da = User.objects.get(username="toto@pouet.com") - self.assertIn(da, dom.admins) - al = Alias.objects.get(address="postmaster@pouet.com") - self.assertTrue(al.aliasrecipient_set.filter(r_mailbox=da.mailbox).exists()) - self.assertTrue(da.can_access(al)) - - values = { - "name": "pouet2.com", - "quota": 1000, - "default_mailbox_quota": 100, - "create_dom_admin": True, - "dom_admin_username": "postmaster", - "create_aliases": True, - "type": "domain", - "stepid": "step3", - "with_mailbox": True, - } - self.ajax_post(reverse("admin:domain_add"), values) - self.assertTrue(User.objects.filter(username="postmaster@pouet2.com").exists()) - self.assertFalse( - Alias.objects.filter( - address="postmaster@pouet2.com", internal=False - ).exists() - ) - - def test_create_with_template_and_random_password(self): - """Test domain creation with administrator and random password.""" - values = { - "name": "pouet.com", - "quota": 1000, - "default_mailbox_quota": 100, - "create_dom_admin": True, - "dom_admin_username": "toto", - "with_mailbox": True, - "create_aliases": True, - "type": "domain", - "stepid": "step3", - "random_password": True, - } - self.ajax_post(reverse("admin:domain_add"), values) - self.assertFalse( - self.client.login(username="admin@pouet.com", password="password") - ) - - def test_create_with_template_and_no_mailbox(self): - """Test domain creation with administrator but no mailbox.""" - values = { - "name": "pouet.com", - "quota": 1000, - "default_mailbox_quota": 100, - "create_dom_admin": True, - "dom_admin_username": "toto", - "with_mailbox": False, - "create_aliases": True, - "type": "domain", - "stepid": "step3", - } - self.ajax_post(reverse("admin:domain_add"), values) - dom = Domain.objects.get(name="pouet.com") - da = User.objects.get(username="toto@pouet.com") - self.assertIn(da, dom.admins) - self.assertFalse(hasattr(da, "mailbox")) - self.assertFalse(Alias.objects.filter(address="postmaster@pouet.com").exists()) - def test_create_with_template_and_empty_quota(self): """Test the creation of a domain with a template and no quota""" values = { "name": "pouet.com", "quota": 0, "default_mailbox_quota": 0, - "create_dom_admin": True, - "dom_admin_username": "toto", - "create_aliases": True, + "domain_admin": { + "username": "toto", + "with_mailbox": True, + "with_aliases": True, + }, "type": "domain", - "stepid": "step3", - "with_mailbox": True, } - self.ajax_post(reverse("admin:domain_add"), values) + response = self.client.post(reverse("v2:domain-list"), values, format="json") + self.assertEqual(response.status_code, 201) dom = Domain.objects.get(name="pouet.com") da = User.objects.get(username="toto@pouet.com") self.assertIn(da, dom.admins) @@ -171,45 +48,23 @@ class DomainTestCase(ModoTestCase): self.assertTrue(al.aliasrecipient_set.filter(r_mailbox=da.mailbox).exists()) self.assertTrue(da.can_access(al)) - def test_create_with_template_and_custom_password(self): - """Test creation of a domain with a template and custom password.""" - password = "Toto1000" - self.set_global_parameter("default_password", password, app="core") - values = { - "name": "pouet.com", - "quota": 0, - "default_mailbox_quota": 0, - "create_dom_admin": True, - "dom_admin_username": "toto", - "create_aliases": True, - "type": "domain", - "stepid": "step3", - "with_mailbox": True, - } - self.ajax_post(reverse("admin:domain_add"), values) - dom = Domain.objects.get(name="pouet.com") - da = User.objects.get(username="toto@pouet.com") - self.assertIn(da, dom.admins) - al = Alias.objects.get(address="postmaster@pouet.com") - self.assertTrue(al.aliasrecipient_set.filter(r_mailbox=da.mailbox).exists()) - self.assertTrue(da.can_access(al)) - self.assertTrue(self.client.login(username="toto@pouet.com", password=password)) - def test_quota_constraints(self): """Check quota constraints.""" values = { "name": "pouet.com", "quota": 10, "default_mailbox_quota": 100, - "create_dom_admin": True, - "dom_admin_username": "toto", - "create_aliases": True, + "domain_admin": { + "username": "toto", + "with_mailbox": True, + "with_aliases": True, + }, "type": "domain", - "stepid": "step3", } - response = self.ajax_post(reverse("admin:domain_add"), values, status=400) + response = self.client.post(reverse("v2:domain-list"), values, format="json") + self.assertEqual(response.status_code, 400) self.assertEqual( - response["form_errors"]["default_mailbox_quota"][0], + response.json()["default_mailbox_quota"][0], "Cannot be greater than domain quota", ) @@ -217,91 +72,15 @@ class DomainTestCase(ModoTestCase): values["name"] = dom.name values["quota"] = 10 values["default_mailbox_quota"] = 100 - response = self.ajax_post( - reverse("admin:domain_change", args=[dom.pk]), values, status=400 + response = self.client.put( + reverse("v2:domain-detail", args=[dom.pk]), values, format="json" ) + self.assertEqual(response.status_code, 400) self.assertEqual( - response["form_errors"]["default_mailbox_quota"][0], + response.json()["default_mailbox_quota"][0], "Cannot be greater than domain quota", ) - def test_create_using_default_quota(self): - """Check that default value is used for creation.""" - self.set_global_parameter("default_domain_quota", 500) - self.set_global_parameter("default_mailbox_quota", 50) - response = self.client.get(reverse("admin:domain_add")) - self.assertContains(response, 'value="500"') - self.assertContains(response, 'value="50"') - - @mock.patch.object(dns.resolver.Resolver, "resolve") - @mock.patch("socket.getaddrinfo") - def test_create_and_check_mx(self, mock_getaddrinfo, mock_query): - """Check for authorized MX record.""" - mock_query.side_effect = utils.mock_dns_query_result - mock_getaddrinfo.side_effect = utils.mock_ip_query_result - - reseller = core_factories.UserFactory( - username="reseller", groups=("Resellers",) - ) - self.client.force_login(reseller) - - self.set_global_parameter("enable_admin_limits", False, app="limits") - self.set_global_parameter("valid_mxs", "192.0.2.1 2001:db8::1") - self.set_global_parameter("domains_must_have_authorized_mx", True) - - values = { - "name": "no-mx.example.com", - "quota": 0, - "default_mailbox_quota": 0, - "create_dom_admin": True, - "dom_admin_username": "toto", - "create_aliases": True, - "type": "domain", - "stepid": "step3", - "with_mailbox": True, - } - self.ajax_post(reverse("admin:domain_add"), values, 400) - self.assertFalse(Domain.objects.filter(name=values["name"]).exists()) - - values["name"] = "pouet.com" - mock_getaddrinfo.side_effect = utils.mock_ip_query_result - self.ajax_post(reverse("admin:domain_add"), values) - - def test_modify(self): - """Test the modification of a domain - - Rename 'test.com' domain to 'pouet.com' - """ - values = { - "name": "pouet.com", - "quota": 1000, - "default_mailbox_quota": 100, - "type": "domain", - "enabled": True, - } - dom = Domain.objects.get(name="test.com") - self.ajax_post(reverse("admin:domain_change", args=[dom.id]), values) - dom = Domain.objects.get(name="pouet.com") - self.assertEqual(dom.name, "pouet.com") - self.assertTrue(dom.enabled) - - # Check if aliases were renamed too - self.assertTrue(dom.alias_set.filter(address="postmaster@pouet.com").exists()) - - def test_delete(self): - """Test the removal of a domain.""" - dom = Domain.objects.get(name="test.com") - self.ajax_post(reverse("admin:domain_delete", args=[dom.id])) - with self.assertRaises(Domain.DoesNotExist): - Domain.objects.get(pk=1) - self.assertTrue(User.objects.filter(username="user@test.com").exists()) - self.set_global_parameter("auto_account_removal", True) - dom = Domain.objects.get(name="test2.com") - self.ajax_post(reverse("admin:domain_delete", args=[dom.id])) - with self.assertRaises(Domain.DoesNotExist): - Domain.objects.get(pk=1) - self.assertFalse(User.objects.filter(username="admin@test2.com").exists()) - def test_domain_counters(self): """Check counters at domain level.""" domain = Domain.objects.get(name="test.com") @@ -310,122 +89,8 @@ class DomainTestCase(ModoTestCase): self.assertEqual(domain.mbalias_count, 3) self.assertEqual(domain.identities_count, 5) - def test_domain_flat_list(self): - """Test the 'domain_flat_list' view.""" - response = self.client.get(reverse("admin:domain_flat_list")) - self.assertEqual(response.status_code, 200) - content = response.json() - self.assertIn("test.com", content) - self.assertIn("test2.com", content) - def test_domain_detail_view(self): - """Test Domain detail view.""" - self.set_global_parameter("enable_domain_limits", False, app="limits") - domain = Domain.objects.get(name="test.com") - url = reverse("admin:domain_detail", args=[domain.pk]) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertIn("Summary", response.content.decode()) - self.assertIn("Administrators", response.content.decode()) - self.assertIn("Usage", response.content.decode()) - self.assertNotIn("Resources usage", response.content.decode()) - self.set_global_parameter("enable_domain_limits", True, app="limits") - response = self.client.get(url) - self.assertIn("Resources usage", response.content.decode()) - - # Try a domain with no quota - domain = Domain.objects.filter(quota=0).first() - url = reverse("admin:domain_detail", args=[domain.pk]) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertNotIn("Usage", response.content.decode()) - - # Try with a fresh domain (see #1174) - domain = factories.DomainFactory(name="simpson.com", quota=100) - url = reverse("admin:domain_detail", args=[domain.pk]) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertIn("Usage", response.content.decode()) - - user = User.objects.get(username="user@test.com") - self.client.force_login(user) - domain = Domain.objects.get(name="test2.com") - url = reverse("admin:domain_detail", args=[domain.pk]) - response = self.client.get(url) - self.assertEqual(response.status_code, 403) - - def test_domain_quota_list_view(self): - """Test quota list view.""" - factories.DomainFactory(name="test3.com", quota=100) - url = reverse("admin:domain_quota_list") - response = self.ajax_get(url) - self.assertIn("50M", response["rows"]) - self.assertIn('title="40% (20 MB) allocated"', response["rows"]) - self.assertIn("test.com", response["rows"]) - - old_rows = response["rows"] - response = self.ajax_get(f"{url}?sort_order=-name") - self.assertNotEqual(old_rows, response["rows"]) - - response = self.ajax_get(f"{url}?sort_order=allocated_quota") - self.assertNotEqual(old_rows, response["rows"]) - - def test_domain_logs_list_view(self): - """Test logs list view.""" - domain = Domain.objects.get(name="test.com") - ml_factories.MaillogFactory(from_domain=domain) - ml_factories.MaillogFactory( - to_domain=domain, - status="received", - date=timezone.now() + relativedelta(days=1), - ) - ml_factories.MaillogFactory(date=timezone.now() + relativedelta(days=2)) - ml_factories.MaillogFactory(date=timezone.now() + relativedelta(days=3)) - url = reverse("admin:domain_logs_list") - response = self.ajax_get(url) - self.assertIn("ID1", response["rows"]) - - old_rows = response["rows"] - response = self.ajax_get(f"{url}?sort_order=-sender") - self.assertNotEqual(old_rows, response["rows"]) - - response = self.ajax_get(f"{url}?searchquery=ID1") - self.assertNotEqual(old_rows, response["rows"]) - - admin = User.objects.get(username="admin@test.com") - self.client.force_login(admin) - url = reverse("admin:domain_logs_list") - response = self.ajax_get(url) - self.assertNotEqual(old_rows, response["rows"]) - - def test_statitics_widget(self): - """Test statistics display in dashboard.""" - url = reverse("core:dashboard") - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - self.assertIn("Global statistics", response.content.decode("utf-8")) - - self.client.force_login(User.objects.get(username="admin@test.com")) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - content = response.content.decode("utf-8") - self.assertNotIn("Global statistics", content) - self.assertIn("Per-domain statistics", content) - - def test_page_loader(self): - """Test page loader view.""" - factories.AlarmFactory( - domain__name="test.com", mailbox=None, title="Test alarm" - ) - url = reverse("admin:domain_page") - response = self.ajax_get(url) - self.assertIn("handle_mailboxes", response) - self.assertIn("listalarms", response["rows"]) - response = self.ajax_get(f"{url}?objtype=quota") - self.assertIn("progress-bar", response["rows"]) - - -class DKIMTestCase(ModoTestCase): +class DKIMTestCase(ModoAPITestCase): """Test case for DKIM.""" @classmethod @@ -443,10 +108,10 @@ class DKIMTestCase(ModoTestCase): def test_global_settings(self): """Check validation rules.""" - url = reverse("core:parameters") + url = reverse("v2:parameter-global-detail", args=["admin"]) settings = SETTINGS_SAMPLE.copy() - settings["admin-dkim_keys_storage_dir"] = "/wrong" - response = self.client.post(url, settings, format="json") + settings["dkim_keys_storage_dir"] = "/wrong" + response = self.client.put(url, settings, format="json") self.assertEqual(response.status_code, 400) compare( response.json(), @@ -465,26 +130,27 @@ class DKIMTestCase(ModoTestCase): "name": "pouet.com", "quota": 1000, "default_mailbox_quota": 100, - "create_dom_admin": False, "type": "domain", - "stepid": "step3", "enable_dkim": True, - "dkim_key_selector": "", } - response = self.ajax_post(reverse("admin:domain_add"), values, 400) + url = reverse("v2:domain-list") + response = self.client.post(url, values, format="json") + self.assertEqual(response.status_code, 400) self.assertEqual( - response["form_errors"]["enable_dkim"][0], + response.json()["enable_dkim"][0], "DKIM keys storage directory not configured", ) self.set_global_parameter("dkim_keys_storage_dir", self.workdir) - response = self.ajax_post(reverse("admin:domain_add"), values, 400) + response = self.client.post(url, values, format="json") + self.assertEqual(response.status_code, 400) self.assertEqual( - response["form_errors"]["dkim_key_selector"][0], "This field is required." + response.json()["dkim_key_selector"][0], "This field is required." ) values["dkim_key_selector"] = "default" - self.ajax_post(reverse("admin:domain_add"), values) + response = self.client.post(url, values, format="json") + self.assertEqual(response.status_code, 201) # Try generating a key to a protected directory self.set_global_parameter("dkim_keys_storage_dir", "/I_DONT_EXIST") @@ -516,9 +182,6 @@ class DKIMTestCase(ModoTestCase): self.assertTrue(os.path.exists(key_path)) domain.refresh_from_db() - url = reverse("admin:domain_detail", args=[domain.pk]) - response = self.client.get(url) - self.assertContains(response, escape(domain.bind_format_dkim_public_key)) # Try generating DKIM key for a targetted domain domain.dkim_private_key_path = "" @@ -536,7 +199,9 @@ class DKIMTestCase(ModoTestCase): "default_mailbox_quota": 100, "type": "domain", } - self.ajax_post(reverse("admin:domain_change", args=[domain.id]), values) + response = self.client.put( + reverse("v2:domain-detail", args=[domain.id]), values, format="json" + ) domain.refresh_from_db() self.assertEqual(domain.dkim_private_key_path, "") @@ -547,19 +212,22 @@ class DKIMTestCase(ModoTestCase): "name": "pouet.com", "quota": 1000, "default_mailbox_quota": 100, - "create_dom_admin": False, "type": "domain", - "stepid": "step3", "enable_dkim": True, "dkim_key_selector": "default", } - self.ajax_post(reverse("admin:domain_add"), values) + url = reverse("v2:domain-list") + response = self.client.post(url, values, format="json") + self.assertEqual(response.status_code, 201) call_command("modo", "manage_dkim_keys") key_path = os.path.join(self.workdir, "{}.pem".format(values["name"])) self.assertTrue(os.path.exists(key_path)) dom = Domain.objects.get(name="pouet.com") values["dkim_key_length"] = 4096 - self.ajax_post(reverse("admin:domain_change", args=[dom.pk]), values) + response = self.client.put( + reverse("v2:domain-detail", args=[dom.id]), values, format="json" + ) + self.assertEqual(response.status_code, 200) dom.refresh_from_db() self.assertEqual(dom.dkim_private_key_path, "") os.unlink(key_path) diff --git a/modoboa/admin/tests/test_domain_alias.py b/modoboa/admin/tests/test_domain_alias.py index 883e0a061..adfe7621c 100644 --- a/modoboa/admin/tests/test_domain_alias.py +++ b/modoboa/admin/tests/test_domain_alias.py @@ -1,5 +1,3 @@ -from django.urls import reverse - from modoboa.lib.tests import ModoTestCase from .. import factories from ..models import Alias, Domain, DomainAlias @@ -28,21 +26,3 @@ class DomainAliasTestCase(ModoTestCase): domal.delete() self.assertFalse(Alias.objects.filter(address=f"@{domal.name}").exists()) - - def test_form(self): - dom = Domain.objects.get(name="test.com") - values = { - "name": dom.name, - "quota": dom.quota, - "default_mailbox_quota": dom.default_mailbox_quota, - "enabled": dom.enabled, - "aliases": "domalias.net", - "aliases_1": "domaliasé.com", - "type": "domain", - } - self.ajax_post(reverse("admin:domain_change", args=[dom.id]), values) - self.assertEqual(dom.domainalias_set.count(), 2) - - del values["aliases_1"] - self.ajax_post(reverse("admin:domain_change", args=[dom.id]), values) - self.assertEqual(dom.domainalias_set.count(), 1) diff --git a/modoboa/admin/tests/test_export.py b/modoboa/admin/tests/test_export.py index ae4c8df90..6cfb6d0e0 100644 --- a/modoboa/admin/tests/test_export.py +++ b/modoboa/admin/tests/test_export.py @@ -7,11 +7,11 @@ from django.core.management import call_command from django.urls import reverse from django.utils.encoding import force_str -from modoboa.lib.tests import ModoTestCase +from modoboa.lib.tests import ModoAPITestCase from .. import factories, models -class ExportTestCase(ModoTestCase): +class ExportTestCase(ModoAPITestCase): """Test case for export operations.""" @classmethod @@ -21,37 +21,20 @@ class ExportTestCase(ModoTestCase): factories.populate_database() def __export_domains(self, domfilter=""): - self.client.get( - "{}?domfilter={}".format(reverse("admin:_domain_list"), domfilter) - ) - return self.client.post( - reverse("admin:domain_export"), {"filename": "test.csv"} - ) + return self.client.get(reverse("v2:domain-export")) def __export_identities(self, idtfilter="", grpfilter=""): - self.client.get( - reverse("admin:_identity_list") - + f"?grpfilter={grpfilter}&idtfilter={idtfilter}" - ) - return self.client.post( - reverse("admin:identity_export"), {"filename": "test.csv"} - ) + return self.client.get(reverse("v2:identities-export")) - def test_export_domains(self): + def test_export_domains_management_command(self): """Check domain export.""" dom = models.Domain.objects.get(name="test.com") factories.DomainAliasFactory(name="alias.test", target=dom) - response = self.__export_domains() expected_response = [ "domain;test.com;50;10;True", "domainalias;alias.test;test.com;True", "domain;test2.com;0;0;True", ] - self.assertCountEqual( - expected_response, force_str(response.content.strip()).split("\r\n") - ) - - # Test management command too. stdout_backup, sys.stdout = sys.stdout, StringIO() call_command("modo", "export", "domains") response = sys.stdout.getvalue() @@ -60,59 +43,51 @@ class ExportTestCase(ModoTestCase): expected_response, force_str(response.strip()).split("\r\n") ) - def test_export_identities(self): - response = self.__export_identities() - expected_response = "account;admin;;;;True;SuperAdmins;;\r\naccount;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;10;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;10;test2.com\r\naccount;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com;10\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com;10\r\nalias;alias@test.com;True;user@test.com\r\nalias;forward@test.com;True;user@external.com\r\nalias;postmaster@test.com;True;test@truc.fr;toto@titi.com\r\n" # NOQA:E501 - received_content = force_str(response.content.strip()).split("\r\n") - # Empty admin password because it is hashed using SHA512-CRYPT - admin_row = received_content[0].split(";") - admin_row[2] = "" - received_content[0] = ";".join(admin_row) - self.assertCountEqual(expected_response.strip().split("\r\n"), received_content) + # FIXME: filters are not available yet in the API - def test_export_simpleusers(self): - factories.MailboxFactory( - user__username="toto@test.com", - user__first_name="Léon", - user__groups=("SimpleUsers",), - address="toto", - domain__name="test.com", - ) - response = self.__export_identities( - idtfilter="account", grpfilter="SimpleUsers" - ) - expected_response = "account;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com;10\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com;10\r\naccount;toto@test.com;{PLAIN}toto;Léon;;True;SimpleUsers;toto@test.com;10" # NOQA:E501 - self.assertCountEqual( - expected_response.split("\r\n"), - force_str(response.content.strip()).split("\r\n"), - ) + # def test_export_simpleusers(self): + # factories.MailboxFactory( + # user__username="toto@test.com", + # user__first_name="Léon", + # user__groups=("SimpleUsers",), + # address="toto", + # domain__name="test.com", + # ) + # response = self.__export_identities( + # idtfilter="account", grpfilter="SimpleUsers" + # ) + # expected_response = "account;user@test.com;{PLAIN}toto;;;True;SimpleUsers;user@test.com;10\r\naccount;user@test2.com;{PLAIN}toto;;;True;SimpleUsers;user@test2.com;10\r\naccount;toto@test.com;{PLAIN}toto;Léon;;True;SimpleUsers;toto@test.com;10" # NOQA:E501 + # self.assertCountEqual( + # expected_response.split("\r\n"), + # force_str(response.content.strip()).split("\r\n"), + # ) - def test_export_superadmins(self): - """A test to validate we only export 1 super admin. + # def test_export_superadmins(self): + # """A test to validate we only export 1 super admin. - The password is removed since it is hashed using SHA512-CRYPT. - """ - response = self.__export_identities( - idtfilter="account", grpfilter="SuperAdmins" - ) - elements = response.content.decode().strip().split(";") - self.assertEqual(len(elements), 9) - elements[2] = "" - self.assertEqual(";".join(elements), "account;admin;;;;True;SuperAdmins;;") + # The password is removed since it is hashed using SHA512-CRYPT. + # """ + # response = self.__export_identities( + # idtfilter="account", grpfilter="SuperAdmins" + # ) + # elements = response.content.decode().strip().split(";") + # self.assertEqual(len(elements), 9) + # elements[2] = "" + # self.assertEqual(";".join(elements), "account;admin;;;;True;SuperAdmins;;") - def test_export_domainadmins(self): - response = self.__export_identities( - idtfilter="account", grpfilter="DomainAdmins" - ) - expected_response = "account;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;10;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;10;test2.com" # NOQA:E501 - self.assertCountEqual( - expected_response.split("\r\n"), - force_str(response.content.strip()).split("\r\n"), - ) + # def test_export_domainadmins(self): + # response = self.__export_identities( + # idtfilter="account", grpfilter="DomainAdmins" + # ) + # expected_response = "account;admin@test.com;{PLAIN}toto;;;True;DomainAdmins;admin@test.com;10;test.com\r\naccount;admin@test2.com;{PLAIN}toto;;;True;DomainAdmins;admin@test2.com;10;test2.com" # NOQA:E501 + # self.assertCountEqual( + # expected_response.split("\r\n"), + # force_str(response.content.strip()).split("\r\n"), + # ) - def test_export_aliases(self): - response = self.__export_identities(idtfilter="alias") - self.assertEqual( - response.content.decode().strip(), - "alias;alias@test.com;True;user@test.com\r\nalias;forward@test.com;True;user@external.com\r\nalias;postmaster@test.com;True;test@truc.fr;toto@titi.com", # NOQA:E501 - ) + # def test_export_aliases(self): + # response = self.__export_identities(idtfilter="alias") + # self.assertEqual( + # response.content.decode().strip(), + # "alias;alias@test.com;True;user@test.com\r\nalias;forward@test.com;True;user@external.com\r\nalias;postmaster@test.com;True;test@truc.fr;toto@titi.com", # NOQA:E501 + # ) diff --git a/modoboa/admin/tests/test_import_.py b/modoboa/admin/tests/test_import_.py index ad09b2807..dbc29ba4e 100644 --- a/modoboa/admin/tests/test_import_.py +++ b/modoboa/admin/tests/test_import_.py @@ -10,13 +10,13 @@ from django.urls import reverse from modoboa.core import factories as core_factories from modoboa.core.models import User -from modoboa.lib.tests import ModoTestCase +from modoboa.lib.tests import ModoAPITestCase from . import utils from .. import factories -from ..models import Alias, Domain, DomainAlias +from ..models import Alias, Domain -class ImportTestCase(ModoTestCase): +class ImportTestCase(ModoAPITestCase): @classmethod def setUpTestData(cls): # NOQA:N802 @@ -26,37 +26,9 @@ class ImportTestCase(ModoTestCase): cls.localconfig.save() factories.populate_database() - def test_domains_import(self): - response = self.client.get(reverse("admin:domain_import")) - self.assertEqual(response.status_code, 200) - self.assertIn("Provide a CSV", response.content.decode()) - - f = ContentFile( - b"""domain; domain1.com; 1000; 100; True -domain; domain2.com; 1000; 200; False -domainalias; domalias1.com; domain1.com; True -""", - name="domains.csv", - ) - self.client.post(reverse("admin:domain_import"), {"sourcefile": f}) - admin = User.objects.get(username="admin") - dom = Domain.objects.get(name="domain1.com") - self.assertEqual(dom.quota, 1000) - self.assertEqual(dom.default_mailbox_quota, 100) - self.assertTrue(dom.enabled) - self.assertTrue(admin.is_owner(dom)) - domalias = DomainAlias.objects.get(name="domalias1.com") - self.assertEqual(domalias.target, dom) - self.assertTrue(dom.enabled) - self.assertTrue(admin.is_owner(domalias)) - dom = Domain.objects.get(name="domain2.com") - self.assertEqual(dom.default_mailbox_quota, 200) - self.assertFalse(dom.enabled) - self.assertTrue(admin.is_owner(dom)) - def test_domain_import_bad_syntax(self): """Check errors handling.""" - url = reverse("admin:domain_import") + url = reverse("v2:domain-import-from-csv") f = ContentFile("domain; domain1.com; 100; True", name="domains.csv") response = self.client.post(url, {"sourcefile": f}) self.assertContains(response, "Invalid line") @@ -82,17 +54,18 @@ domainalias; domalias1.com; domain1.com; True reseller = core_factories.UserFactory( username="reseller", groups=("Resellers",) ) - self.client.force_login(reseller) + self.authenticate_user(reseller) self.set_global_parameter("valid_mxs", "192.0.2.1 2001:db8::1") self.set_global_parameter("domains_must_have_authorized_mx", True) + url = reverse("v2:domain-import-from-csv") f = ContentFile(b"domain; test3.com; 100; 1; True", name="domains.csv") - resp = self.client.post(reverse("admin:domain_import"), {"sourcefile": f}) + resp = self.client.post(url, {"sourcefile": f}) self.assertContains(resp, "test3.com: no authorized MX record found for domain") mock_getaddrinfo.side_effect = utils.mock_ip_query_result f = ContentFile(b"domain; domain1.com; 100; 1; True", name="domains.csv") - resp = self.client.post(reverse("admin:domain_import"), {"sourcefile": f}) + resp = self.client.post(url, {"sourcefile": f}) self.assertTrue(Domain.objects.filter(name="domain1.com").exists()) def test_import_domains_with_conflict(self): @@ -102,76 +75,10 @@ domainalias;test.alias;test.com;True """, name="domains.csv", ) - resp = self.client.post(reverse("admin:domain_import"), {"sourcefile": f}) + url = reverse("v2:domain-import-from-csv") + resp = self.client.post(url, {"sourcefile": f}) self.assertIn("Object already exists: domainalias", resp.content.decode()) - def test_identities_import(self): - response = self.client.get(reverse("admin:identity_import")) - self.assertEqual(response.status_code, 200) - self.assertIn("Provide a CSV", response.content.decode()) - - f = ContentFile( - """ -account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com; 0 -account; Truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; 5; test.com -alias; alias1@test.com; True; user1@test.com -forward; alias2@test.com; True; user1+ext@test.com -forward; fwd1@test.com; True; user@extdomain.com -dlist; dlist@test.com; True; user1@test.com; user@extdomain.com -""", - name="identities.csv", - ) # NOQA:E501 - self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} - ) - admin = User.objects.get(username="admin") - u1 = User.objects.get(username="user1@test.com") - mb1 = u1.mailbox - self.assertTrue(admin.is_owner(u1)) - self.assertEqual(u1.email, "user1@test.com") - self.assertEqual(u1.first_name, "User") - self.assertEqual(u1.last_name, "One") - self.assertTrue(u1.is_active) - self.assertEqual(u1.role, "SimpleUsers") - self.assertTrue(mb1.use_domain_quota) - self.assertEqual(mb1.quota, 0) - self.assertTrue(admin.is_owner(mb1)) - self.assertEqual(mb1.full_address, "user1@test.com") - self.assertTrue(self.client.login(username="user1@test.com", password="toto")) - - da = User.objects.get(username="truc@test.com") - damb = da.mailbox - self.assertEqual(da.first_name, "René") - self.assertEqual(da.role, "DomainAdmins") - self.assertEqual(damb.quota, 5) - self.assertFalse(damb.use_domain_quota) - self.assertEqual(damb.full_address, "truc@test.com") - dom = Domain.objects.get(name="test.com") - self.assertIn(da, dom.admins) - u = User.objects.get(username="user@test.com") - self.assertTrue(da.can_access(u)) - - al = Alias.objects.get(address="alias1@test.com") - self.assertTrue(al.aliasrecipient_set.filter(r_mailbox=u1.mailbox).exists()) - self.assertTrue(admin.is_owner(al)) - - fwd = Alias.objects.get(address="fwd1@test.com") - self.assertTrue( - fwd.aliasrecipient_set.filter( - address="user@extdomain.com", - r_mailbox__isnull=True, - r_alias__isnull=True, - ).exists() - ) - self.assertTrue(admin.is_owner(fwd)) - - dlist = Alias.objects.get(address="dlist@test.com") - self.assertTrue(dlist.aliasrecipient_set.filter(r_mailbox=u1.mailbox).exists()) - self.assertTrue( - dlist.aliasrecipient_set.filter(address="user@extdomain.com").exists() - ) - self.assertTrue(admin.is_owner(dlist)) - def test_import_for_nonlocal_domain(self): """Try to import an account for nonlocal domain.""" f = ContentFile( @@ -180,9 +87,8 @@ account; user1@nonlocal.com; toto; User; One; True; SimpleUsers; user1@nonlocal. """, name="identities.csv", ) # NOQA:E501 - self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} - ) + url = reverse("v2:identities-import-from-csv") + self.client.post(url, {"sourcefile": f, "crypt_password": True}) self.assertFalse(User.objects.filter(username="user1@nonlocal.com").exists()) def test_import_invalid_quota(self): @@ -192,24 +98,23 @@ account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com; ; t """, name="identities.csv", ) # NOQA:E501 - resp = self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} - ) + url = reverse("v2:identities-import-from-csv") + resp = self.client.post(url, {"sourcefile": f, "crypt_password": True}) self.assertIn("wrong quota value", resp.content.decode()) def test_import_domain_by_domainadmin(self): """Check if a domain admin is not allowed to import a domain.""" self.client.logout() - self.client.login(username="admin@test.com", password="toto") + admin = User.objects.get(username="admin@test.com") + self.authenticate_user(admin) f = ContentFile( b""" domain; domain2.com; 1000; 200; False """, name="identities.csv", ) - resp = self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} - ) + url = reverse("v2:identities-import-from-csv") + resp = self.client.post(url, {"sourcefile": f, "crypt_password": True}) self.assertIn("You are not allowed to import domains", resp.content.decode()) f = ContentFile( b""" @@ -217,16 +122,14 @@ domainalias; domalias1.com; test.com; True """, name="identities.csv", ) - resp = self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} - ) + resp = self.client.post(url, {"sourcefile": f, "crypt_password": True}) self.assertIn( "You are not allowed to import domain aliases", resp.content.decode() ) def test_import_quota_too_big(self): - self.client.logout() - self.client.login(username="admin@test.com", password="toto") + admin = User.objects.get(username="admin@test.com") + self.authenticate_user(admin) f = ContentFile( b""" account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com; 40 @@ -234,7 +137,8 @@ account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com; 40 name="identities.csv", ) resp = self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} + reverse("v2:identities-import-from-csv"), + {"sourcefile": f, "crypt_password": True}, ) self.assertIn("test.com: domain quota exceeded", resp.content.decode()) @@ -246,7 +150,8 @@ account; user1@test.com; toto; User; One; True; SimpleUsers; user1@test.com name="identities.csv", ) self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} + reverse("v2:identities-import-from-csv"), + {"sourcefile": f, "crypt_password": True}, ) account = User.objects.get(username="user1@test.com") self.assertEqual( @@ -262,7 +167,7 @@ account; truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; 0; name="identities.csv", ) # NOQA:E501 self.client.post( - reverse("admin:identity_import"), + reverse("v2:identities-import-from-csv"), {"sourcefile": f, "crypt_password": True, "continue_if_exists": True}, ) admin = User.objects.get(username="admin") @@ -274,8 +179,8 @@ account; truc@test.com; toto; René; Truc; True; DomainAdmins; truc@test.com; 0; Expected result: no """ - self.client.logout() - self.assertTrue(self.client.login(username="admin@test.com", password="toto")) + admin = User.objects.get(username="admin@test.com") + self.authenticate_user(admin) f = ContentFile( b""" account; sa@test.com; toto; Super; Admin; True; SuperAdmins; superadmin@test.com; 50 @@ -283,7 +188,7 @@ account; sa@test.com; toto; Super; Admin; True; SuperAdmins; superadmin@test.com name="identities.csv", ) # NOQA:E501 self.client.post( - reverse("admin:identity_import"), + reverse("v2:identities-import-from-csv"), {"sourcefile": f, "crypt_password": True, "continue_if_exists": True}, ) with self.assertRaises(User.DoesNotExist): @@ -297,7 +202,7 @@ alias;user.alias@test.com;True;user@test.com;;;;;;;;;;;;;;;; name="identities.csv", ) self.client.post( - reverse("admin:identity_import"), + reverse("v2:identities-import-from-csv"), {"sourcefile": f, "crypt_password": True, "continue_if_exists": True}, ) alias = Alias.objects.get(address="user.alias@test.com") @@ -312,24 +217,21 @@ alias;user@test.com;True;admin@test.com name="identities.csv", ) self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} + reverse("v2:identities-import-from-csv"), + {"sourcefile": f, "crypt_password": True}, ) self.assertTrue( Alias.objects.filter(address="user@test.com", internal=False).exists() ) def test_domains_import_utf8(self): - response = self.client.get(reverse("admin:domain_import")) - self.assertEqual(response.status_code, 200) - self.assertIn("Provide a CSV", response.content.decode()) - f = ContentFile( """domain; dómªin1.com; 1000; 100; True dómain; dómªin2.com; 1000; 100; True """.encode(), name="dómains.csv", ) - self.client.post(reverse("admin:domain_import"), {"sourcefile": f}) + self.client.post(reverse("v2:domain-import-from-csv"), {"sourcefile": f}) admin = User.objects.get(username="admin") dom = Domain.objects.get(name="dómªin1.com") self.assertEqual(dom.quota, 1000) @@ -412,7 +314,8 @@ alias; alias1@test.com; True; user1@test.com name="identities.csv", ) # NOQA:E501 resp = self.client.post( - reverse("admin:identity_import"), {"sourcefile": f, "crypt_password": True} + reverse("v2:identities-import-from-csv"), + {"sourcefile": f, "crypt_password": True}, ) self.assertEqual(resp.status_code, 200) diff --git a/modoboa/admin/tests/test_mailbox_operations.py b/modoboa/admin/tests/test_mailbox_operations.py index 84a45a0de..42eefb4f0 100644 --- a/modoboa/admin/tests/test_mailbox_operations.py +++ b/modoboa/admin/tests/test_mailbox_operations.py @@ -2,19 +2,18 @@ import os import shutil -import tempfile from unittest import mock from django.core.management import call_command from django.test import override_settings from django.urls import reverse -from modoboa.lib.tests import ModoTestCase +from modoboa.lib.tests import ModoAPITestCase from .. import factories, models @override_settings(DOVECOT_LOOKUP_PATH=[f"{os.path.dirname(__file__)}/dovecot"]) -class MailboxOperationTestCase(ModoTestCase): +class MailboxOperationTestCase(ModoAPITestCase): """Test management command.""" @classmethod @@ -26,7 +25,6 @@ class MailboxOperationTestCase(ModoTestCase): def setUp(self): """Initiate test env.""" super().setUp() - self.workdir = tempfile.mkdtemp() path = f"{self.workdir}/test.com/admin" os.makedirs(path) self.set_global_parameter("handle_mailboxes", True) @@ -44,7 +42,9 @@ class MailboxOperationTestCase(ModoTestCase): mb = models.Mailbox.objects.select_related("user").get( address="admin", domain__name="test.com" ) - self.ajax_post(reverse("admin:account_delete", args=[mb.user.pk]), {}) + self.client.post( + reverse("v2:account-delete", args=[mb.user.pk]), {}, format="json" + ) call_command("handle_mailbox_operations") self.assertFalse(models.MailboxOperation.objects.exists()) self.assertFalse(os.path.exists(mb.mail_home)) @@ -63,10 +63,11 @@ class MailboxOperationTestCase(ModoTestCase): "is_active": True, "email": "admin2@test.com", "language": "en", - "subject": "test", - "content": "content", + "mailbox": {"use_domain_quota": True}, } - self.ajax_post(reverse("admin:account_change", args=[mb.user.pk]), values) + self.client.post( + reverse("v2:account-detail", args=[mb.user.pk]), values, format="json" + ) path = f"{self.workdir}/test.com/admin2" mail_home_mock.__get__ = mock.Mock(return_value=path) call_command("handle_mailbox_operations") @@ -79,7 +80,9 @@ class MailboxOperationTestCase(ModoTestCase): path = f"{self.workdir}/test.com/admin" mail_home_mock.__get__ = mock.Mock(return_value=path) domain = models.Domain.objects.get(name="test.com") - self.ajax_post(reverse("admin:domain_delete", args=[domain.pk])) + self.client.post( + reverse("v2:domain-delete", args=[domain.pk]), {}, format="json" + ) call_command("handle_mailbox_operations") self.assertFalse(models.MailboxOperation.objects.exists()) self.assertFalse(os.path.exists(path)) diff --git a/modoboa/admin/tests/test_mx.py b/modoboa/admin/tests/test_mx.py index a2e967b2c..54d0ca305 100644 --- a/modoboa/admin/tests/test_mx.py +++ b/modoboa/admin/tests/test_mx.py @@ -7,7 +7,6 @@ from testfixtures import LogCapture from django.core import mail, management from django.test import override_settings -from django.urls import reverse from django.utils.translation import gettext as _ from modoboa.core import models as core_models, factories as core_factories @@ -241,10 +240,6 @@ class DNSBLTestCase(ModoTestCase): self.assertFalse( models.DNSBLResult.objects.filter(domain=self.domain3).exists() ) - response = self.client.get( - reverse("admin:dnsbl_domain_detail", args=[self.domain.pk]) - ) - self.assertEqual(response.status_code, 200) self.assertFalse(self.domain.uses_a_reserved_tld) self.assertTrue(self.domain2.uses_a_reserved_tld) @@ -285,10 +280,6 @@ class DNSBLTestCase(ModoTestCase): self.assertEqual(models.DNSBLResult.objects.count(), 0) management.call_command("modo", "check_mx", "--no-dnsbl") self.assertFalse(models.DNSBLResult.objects.filter(domain=self.domain).exists()) - response = self.client.get( - reverse("admin:dnsbl_domain_detail", args=[self.domain.pk]) - ) - self.assertEqual(response.status_code, 200) class DNSChecksTestCase(ModoTestCase): diff --git a/modoboa/admin/tests/test_password_schemes.py b/modoboa/admin/tests/test_password_schemes.py index 7a5d56fdc..57411fbc7 100644 --- a/modoboa/admin/tests/test_password_schemes.py +++ b/modoboa/admin/tests/test_password_schemes.py @@ -1,11 +1,11 @@ from django.urls import reverse from modoboa.core.models import User -from modoboa.lib.tests import ModoTestCase +from modoboa.lib.tests import ModoAPITestCase from .. import factories -class PasswordSchemesTestCase(ModoTestCase): +class PasswordSchemesTestCase(ModoAPITestCase): @classmethod def setUpTestData(cls): # NOQA:N802 @@ -18,15 +18,14 @@ class PasswordSchemesTestCase(ModoTestCase): "username": "tester@test.com", "first_name": "Tester", "last_name": "Toto", - "password1": "Toto1234", - "password2": "Toto1234", + "password": "Toto1234", "role": "SimpleUsers", - "quota_act": True, "is_active": True, "email": "tester@test.com", - "stepid": "step2", + "mailbox": {"use_domain_quota": True}, } - self.ajax_post(reverse("admin:account_add"), values) + response = self.client.post(reverse("v2:account-list"), values, format="json") + self.assertEqual(response.status_code, 201) def _test_scheme(self, name, startpattern): self.set_global_parameter("password_scheme", name, app="core") diff --git a/modoboa/admin/tests/test_user.py b/modoboa/admin/tests/test_user.py deleted file mode 100644 index b5096ff92..000000000 --- a/modoboa/admin/tests/test_user.py +++ /dev/null @@ -1,49 +0,0 @@ -"""User related tests.""" - -from django.urls import reverse - -from modoboa.core.models import User -from modoboa.lib.tests import ModoTestCase -from ..factories import populate_database -from ..models import Alias - - -class ForwardTestCase(ModoTestCase): - """User forward test cases.""" - - def setUp(self): - super().setUp() - populate_database() - - def test_set_forward(self): - self.client.logout() - self.client.login(username="user@test.com", password="toto") - url = reverse("user_forward") - self.ajax_post(url, {"dest": "user@extdomain.com", "keepcopies": True}) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - content = response.json() - self.assertIn("user@extdomain.com", content["content"]) - self.assertNotIn("user@test.com", content["content"]) - forward = Alias.objects.get(address="user@test.com", internal=False) - sadmin = User.objects.get(username="admin") - self.assertTrue(sadmin.can_access(forward)) - domadmin = User.objects.get(username="admin@test.com") - self.assertTrue(domadmin.can_access(forward)) - - selfalias = Alias.objects.get(address="user@test.com", internal=True) - self.assertTrue(selfalias.enabled) - - # Deactivate local copies - self.ajax_post(url, {"dest": "user@extdomain.com", "keepcopies": False}) - selfalias.refresh_from_db() - self.assertFalse(selfalias.enabled) - - # Now, empty forward - self.ajax_post(url, {"dest": "", "keepcopies": False}) - response = self.client.get(url) - self.assertEqual(response.status_code, 200) - content = response.json() - self.assertNotIn("user@extdomain.com", content["content"]) - selfalias.refresh_from_db() - self.assertTrue(selfalias.enabled) diff --git a/modoboa/core/tests/test_ldap.py b/modoboa/core/tests/test_ldap.py index 21c6ae290..3ed2b8b3f 100644 --- a/modoboa/core/tests/test_ldap.py +++ b/modoboa/core/tests/test_ldap.py @@ -8,7 +8,7 @@ from django.urls import reverse from django.utils.functional import cached_property from modoboa.lib import exceptions -from modoboa.lib.tests import NO_LDAP, ModoTestCase +from modoboa.lib.tests import NO_LDAP, ModoTestCase, ModoAPITestCase from .. import factories, models @@ -136,7 +136,7 @@ class LDAPAuthenticationTestCase(LDAPTestCaseMixin, ModoTestCase): self.check_created_user("mailadmin@example.com", "DomainAdmins", False) -class ProfileTestCase(LDAPTestCaseMixin, ModoTestCase): +class ProfileTestCase(LDAPTestCaseMixin, ModoAPITestCase): """Profile related tests.""" @classmethod @@ -159,14 +159,12 @@ class ProfileTestCase(LDAPTestCaseMixin, ModoTestCase): self.searchbind_mode() username = "testuser@example.com" + account = models.User.objects.get(username=username) self.authenticate(username, "test") - self.ajax_post( - reverse("core:user_profile"), - { - "language": "en", - "oldpassword": "test", - "newpassword": "Toto1234", - "confirmation": "Toto1234", - }, + response = self.client.patch( + reverse("v2:account-detail", args=[account.id]), + {"password": "Toto1234"}, + format="json", ) + self.assertEqual(response.status_code, 200) self.authenticate(username, "Toto1234", False) diff --git a/modoboa/dnstools/tests.py b/modoboa/dnstools/tests.py index 1b2bf7411..dde640522 100644 --- a/modoboa/dnstools/tests.py +++ b/modoboa/dnstools/tests.py @@ -3,7 +3,6 @@ from unittest import mock from django.test import SimpleTestCase -from django.urls import reverse from django.utils import timezone from dns.rdtypes.ANY.TXT import TXT @@ -127,56 +126,6 @@ class LibTestCase(SimpleTestCase): self.assertEqual(key, "XXX123") -class ViewsTestCase(ModoTestCase): - """A test case for views.""" - - @classmethod - def setUpTestData(cls): - """Create some records.""" - super().setUpTestData() - cls.spf_rec = factories.DNSRecordFactory( - type="spf", value="v=SPF1 mx -all", is_valid=True, domain__name="test.com" - ) - cls.dmarc_rec = factories.DNSRecordFactory( - type="dmarc", - value="XXX", - is_valid=False, - error="Not a DMARC record", - domain__name="test.com", - ) - cls.dkim_rec = factories.DNSRecordFactory( - type="dkim", - value="12345", - is_valid=False, - error="Public key mismatchs", - domain__name="test.com", - ) - cls.ac_rec = factories.DNSRecordFactory( - type="autoconfig", value="1.2.3.4", is_valid=True, domain__name="test.com" - ) - - def test_record_detail_view(self): - url = reverse("dnstools:dns_record_detail", args=[self.spf_rec.pk]) - response = self.client.get(url) - self.assertContains(response, "A DNS record has been found and is valid") - url = reverse("dnstools:dns_record_detail", args=[self.dmarc_rec.pk]) - response = self.client.get(url) - self.assertContains(response, "Not a DMARC record") - - def test_autoconfig_record_status_view(self): - url = reverse( - "dnstools:autoconfig_records_status", args=[self.ac_rec.domain.pk] - ) - response = self.client.get(url) - self.assertContains(response, "autoconfig record (Mozilla) found") - self.assertContains(response, "autodiscover record (Microsoft) not found") - - def test_domain_dns_configuration(self): - url = reverse("dnstools:domain_dns_configuration", args=[self.ac_rec.domain.pk]) - response = self.client.get(url) - self.assertContains(response, "[IP address of your Modoboa server]") - - class DomainTestCase(ModoTestCase): def test_dns_global_status(self): diff --git a/modoboa/lib/tests/__init__.py b/modoboa/lib/tests/__init__.py index 5a17e59cb..3927f1024 100644 --- a/modoboa/lib/tests/__init__.py +++ b/modoboa/lib/tests/__init__.py @@ -30,6 +30,122 @@ except ImportError: NO_LDAP = True +SETTINGS_SAMPLE = { + "core-check_new_versions": "True", + "core-log_maximum_age": "365", + "core-ldap_auth_method": "searchbind", + "limits-deflt_domain_mailbox_aliases_limit": "0", + "core-send_statistics": "True", + "core-default_top_redirection": "user", + "core-sender_address": "noreply@modoboa.org", + "admin-auto_account_removal": "False", + "core-ldap_server_port": "389", + "core-rounds_number": "70000", + "core-ldap_bind_password": "", + "limits-deflt_domain_domain_aliases_limit": "0", + "core-secret_key": ":?j3]QPWo!.'_c4n", + "limits-deflt_domain_domain_admins_limit": "0", + "limits-enable_admin_limits": "True", + "core-ldap_bind_dn": "", + "core-enable_api_communication": "True", + "limits-deflt_user_domain_admins_limit": "0", + "limits-enable_domain_limits": "False", + "csrfmiddlewaretoken": "SGgMVZsA4TPqoiV786TMST6xgOlhAf4F", + "limits-deflt_user_mailboxes_limit": "0", + "core-password_scheme": "plain", + "core-update_scheme": True, + "core-items_per_page": "30", + "limits-deflt_user_mailbox_aliases_limit": "0", + "limits-deflt_domain_mailboxes_limit": "0", + "core-ldap_is_active_directory": "False", + "core-ldap_group_type": "posixgroup", + "limits-deflt_user_domain_aliases_limit": "0", + "core-top_notifications_check_interval": "30", + "core-ldap_password_attribute": "userPassword", + "admin-auto_create_domain_and_mailbox": "True", + "admin-enable_dnsbl_checks": "True", + "admin-default_domain_quota": "0", + "admin-default_mailbox_quota": "0", + "core-ldap_server_address": "localhost", + "core-authentication_type": "local", + "core-ldap_admin_groups": "", + "core-ldap_groups_search_base": "", + "admin-enable_mx_checks": "True", + "admin-enable_ipv6_mx_checks": "True", + "core-ldap_search_base": "", + "admin-valid_mxs": "", + "limits-deflt_user_domains_limit": "0", + "core-ldap_search_filter": "(mail=%(user)s)", + "core-ldap_secured": "none", + "core-ldap_user_dn_template": "", + "core-default_password": "Toto1000", + "limits-deflt_user_quota_limit": "0", + "core-hide_features_widget": "False", + "core-enable_inactive_accounts": "True", + "core-inactive_account_threshold": "30", + "admin-domains_must_have_authorized_mx": False, + "core-random_password_length": "8", + "admin-create_alias_on_mbox_rename": False, + "admin-dkim_keys_storage_dir": "", + "admin-dkim_default_key_length": 1024, + "admin-custom_dns_server": "193.43.55.67", + "admin-enable_spf_checks": True, + "admin-enable_dkim_checks": True, + "admin-enable_dmarc_checks": True, + "admin-enable_autoconfig_checks": True, + "core-ldap_enable_sync": False, + "core-ldap_sync_bind_dn": "", + "core-ldap_sync_bind_password": "", + "core-ldap_sync_account_dn_template": "", + "core-ldap_sync_delete_remote_account": False, + "core-send_new_versions_email": False, + "core-new_versions_email_rcpt": "postmaster@domain.test", + "core-ldap_enable_secondary_server": False, + "core-ldap_secondary_server_address": "localhost", + "core-ldap_secondary_server_port": 389, + "core-ldap_enable_import": False, + "core-ldap_import_search_base": "", + "core-ldap_import_search_filter": "", + "core-ldap_import_username_attr": "cn", + "core-sms_password_recovery": False, + "core-sms_provider": "", + "core-sms_ovh_endpoint": "ovh-eu", + "core-password_recovery_msg": "", + "core-ldap_dovecot_sync": False, + "maillog-logfile": "/var/log/mail.log", + "maillog-rrd_rootdir": "/tmp", + "maillog-greylist": False, + "pdfcredentials-enabled_pdfcredentials": True, + "pdfcredentials-storage_dir": "./", + "pdfcredentials-delete_first_dl": True, + "pdfcredentials-generate_at_creation": True, + "pdfcredentials-title": "Modoboa", + "pdfcredentials-webpanel_url": "local.host/", + "pdfcredentials-custom_message": "test", + "pdfcredentials-include_connection_settings": False, + "pdfcredentials-smtp_server_address": "127.0.0.1", + "pdfcredentials-smtp_server_port": 666, + "pdfcredentials-smtp_connection_security": "starttls", + "pdfcredentials-imap_server_address": "127.0.0.1", + "pdfcredentials-imap_server_port": 667, + "pdfcredentials-imap_connection_security": "starttls", + "dmarc-enable_rlookups": False, + "imap_migration-enabled_imapmigration": True, + "imap_migration-max_sync_accounts": 2, + "imap_migration-create_folders": True, + "postfix_autoreply-autoreplies_timeout": 86400, + "postfix_autoreply-default_subject": "I'm off", + "postfix_autoreply-default_content": "I'm off", + "sievefilters-server": "127.0.0.1", + "sievefilters-port": 4190, + "sievefilters-starttls": False, + "sievefilters-authentication_mech": "AUTO", + "sievefilters-imap_server": "127.0.0.1", + "sievefilters-imap_secured": False, + "sievefilters-imap_port": 143, +} + + class ParametersMixin: """Add tools to manage parameters.""" diff --git a/modoboa/maillog/api/v2/tests.py b/modoboa/maillog/api/v2/tests.py index 073b1aea8..50e020a24 100644 --- a/modoboa/maillog/api/v2/tests.py +++ b/modoboa/maillog/api/v2/tests.py @@ -1,8 +1,13 @@ """API v2 tests.""" -from django.urls import reverse +from dateutil.relativedelta import relativedelta +from django.urls import reverse +from django.utils import timezone + +from modoboa.admin import factories as admin_factories, models from modoboa.lib.tests import ModoAPITestCase +from modoboa.maillog import factories class StatisticsViewSetTestCase(ModoAPITestCase): @@ -23,7 +28,23 @@ class StatisticsViewSetTestCase(ModoAPITestCase): class MaillogViewSetTestCase(ModoAPITestCase): + @classmethod + def setUpTestData(cls): # NOQA:N802 + """Create test data.""" + super().setUpTestData() + admin_factories.populate_database() + domain = models.Domain.objects.get(name="test.com") + factories.MaillogFactory(from_domain=domain) + factories.MaillogFactory( + to_domain=domain, + status="received", + date=timezone.now() + relativedelta(days=1), + ) + factories.MaillogFactory(date=timezone.now() + relativedelta(days=2)) + factories.MaillogFactory(date=timezone.now() + relativedelta(days=3)) + def test_list(self): url = reverse("v2:maillog-list") resp = self.client.get(url) self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.json()["count"], 4) diff --git a/modoboa/parameters/tools.py b/modoboa/parameters/tools.py index 7f9225aa4..f0f89002f 100644 --- a/modoboa/parameters/tools.py +++ b/modoboa/parameters/tools.py @@ -83,7 +83,7 @@ class Registry: def get_label(self, level: str, app: str) -> str: return self._registry2[level][app]["label"] - def get_serializer_classes(self, level): + def get_serializers(self, level): """Return form instances for all app of the given level.""" sorted_apps = [] first_app = "core" diff --git a/modoboa/policyd/tests.py b/modoboa/policyd/tests.py index 82cea054c..9fc394a7f 100644 --- a/modoboa/policyd/tests.py +++ b/modoboa/policyd/tests.py @@ -11,13 +11,12 @@ import time from django import db from django.core.management import call_command from django.test import TransactionTestCase -from django.urls import reverse from modoboa.admin import factories as admin_factories from modoboa.admin import models as admin_models from modoboa.core import models as core_models from modoboa.lib.redis import get_redis_connection -from modoboa.lib.tests import ModoTestCase, ParametersMixin +from modoboa.lib.tests import ModoAPITestCase, ParametersMixin from modoboa.policyd import core as policyd_core from . import constants @@ -210,7 +209,7 @@ sasl_username=user@test.com self.assertEqual(self.rclient.hget(constants.REDIS_HASHNAME, account.email), 10) -class ModelsTestCase(RedisTestCaseMixin, ModoTestCase): +class ModelsTestCase(RedisTestCaseMixin, ModoAPITestCase): """Admin models test cases.""" @classmethod @@ -219,24 +218,6 @@ class ModelsTestCase(RedisTestCaseMixin, ModoTestCase): super().setUpTestData() admin_factories.populate_database() - def test_domain_detail_view(self): - domain = admin_models.Domain.objects.get(name="test.com") - domain.message_limit = 10 - domain.save() - url = reverse("admin:domain_detail", args=[domain.pk]) - response = self.client.get(url) - self.assertContains(response, "Message sending limit") - - def test_account_detail_view(self): - account = core_models.User.objects.get(username="user@test.com") - mb = account.mailbox - mb.message_limit = 10 - mb.save() - - url = reverse("admin:account_detail", args=[account.pk]) - response = self.client.get(url) - self.assertContains(response, "Message sending limit") - def test_domain_signal_handler(self): domain = admin_models.Domain.objects.get(name="test.com") domain.message_limit = 10