Fixed unit tests.

This commit is contained in:
Antoine Nguyen
2021-05-30 09:49:29 +02:00
parent ea98bed16b
commit d3d2c505c4
26 changed files with 228 additions and 215 deletions
+2 -1
View File
@@ -171,8 +171,9 @@ class MailboxSerializer(serializers.ModelSerializer):
def validate(self, data):
"""Check if quota is required."""
method = self.context["request"].method
if not data.get("use_domain_quota", False):
if "quota" not in data:
if "quota" not in data and method != "PATCH":
raise serializers.ValidationError({
"quota": _("This field is required")
})
@@ -12,11 +12,11 @@ from django.urls import reverse
from rest_framework.authtoken.models import Token
from reversion.models import Version
from modoboa.admin import models as admin_models
from modoboa.admin import factories
from modoboa.admin import models
from modoboa.admin.tests import utils
from modoboa.core import factories as core_factories, models as core_models
from modoboa.lib.tests import ModoAPITestCase
from . import utils
from .. import factories, models
class DomainAPITestCase(ModoAPITestCase):
@@ -32,13 +32,13 @@ class DomainAPITestCase(ModoAPITestCase):
def test_get_domains(self):
"""Retrieve a list of domains."""
url = reverse("api:domain-list")
url = reverse("v1:domain-list")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
domain = response.data[0]
url = reverse(
"api:domain-detail", args=[domain["pk"]])
"v1:domain-detail", args=[domain["pk"]])
response = self.client.get(url)
data = response.json()
self.assertEqual(response.status_code, 200)
@@ -47,7 +47,7 @@ class DomainAPITestCase(ModoAPITestCase):
def test_create_domain(self):
"""Check domain creation."""
url = reverse("api:domain-list")
url = reverse("v1:domain-list")
response = self.client.post(
url, {"name": "test3.com", "quota": 0, "default_mailbox_quota": 10}
)
@@ -83,7 +83,7 @@ class DomainAPITestCase(ModoAPITestCase):
token = Token.objects.create(user=reseller)
self.client.credentials(HTTP_AUTHORIZATION="Token " + token.key)
url = reverse("api:domain-list")
url = reverse("v1:domain-list")
mock_query.side_effect = utils.mock_dns_query_result
mock_getaddrinfo.side_effect = utils.mock_ip_query_result
response = self.client.post(
@@ -107,7 +107,7 @@ class DomainAPITestCase(ModoAPITestCase):
models.Mailbox.objects.filter(
domain__name="test.com", address="user").update(
use_domain_quota=True)
url = reverse("api:domain-detail", args=[domain.pk])
url = reverse("v1:domain-detail", args=[domain.pk])
response = self.client.put(
url, {"name": "test.com", "default_mailbox_quota": 1000})
self.assertEqual(response.status_code, 200)
@@ -127,7 +127,7 @@ class DomainAPITestCase(ModoAPITestCase):
def test_patch_domain(self):
"""Check domain partial update."""
domain = models.Domain.objects.get(name="test.com")
url = reverse("api:domain-detail", args=[domain.pk])
url = reverse("v1:domain-detail", args=[domain.pk])
response = self.client.put(url, {"name": "toto.test"})
self.assertEqual(response.status_code, 200)
domain.refresh_from_db()
@@ -136,7 +136,7 @@ class DomainAPITestCase(ModoAPITestCase):
def test_delete_domain(self):
"""Try to delete a domain."""
domain = models.Domain.objects.get(name="test.com")
url = reverse("api:domain-detail", args=[domain.pk])
url = reverse("v1:domain-detail", args=[domain.pk])
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
self.assertFalse(models.Domain.objects.filter(pk=domain.pk).exists())
@@ -159,30 +159,30 @@ class DomainAliasAPITestCase(ModoAPITestCase):
def test_get(self):
"""Retrieve a list of domain aliases."""
url = reverse("api:domain_alias-list")
url = reverse("v1:domain_alias-list")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
url = reverse(
"api:domain_alias-detail", args=[response.data[0]["pk"]])
"v1:domain_alias-detail", args=[response.data[0]["pk"]])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data["name"], "dalias1.com")
url = reverse("api:domain_alias-list")
url = reverse("v1:domain_alias-list")
response = self.client.get("{}?domain=test.com".format(url))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 1)
self.client.credentials(
HTTP_AUTHORIZATION="Token " + self.da_token.key)
response = self.client.get(reverse("api:domain_alias-list"))
response = self.client.get(reverse("v1:domain_alias-list"))
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 0)
def test_post(self):
"""Try to create a new domain alias."""
url = reverse("api:domain_alias-list")
url = reverse("v1:domain_alias-list")
target = models.Domain.objects.get(name="test.com")
data = {
"name": "dalias3.com",
@@ -205,7 +205,7 @@ class DomainAliasAPITestCase(ModoAPITestCase):
def test_put(self):
"""Try to update a domain alias."""
dalias = models.DomainAlias.objects.get(name="dalias1.com")
url = reverse("api:domain_alias-detail", args=[dalias.pk])
url = reverse("v1:domain_alias-detail", args=[dalias.pk])
data = {
"name": "dalias3.com", "target": dalias.target.pk
}
@@ -219,7 +219,7 @@ class DomainAliasAPITestCase(ModoAPITestCase):
def test_delete(self):
"""Try to delete an existing domain alias."""
dalias = models.DomainAlias.objects.get(name="dalias1.com")
url = reverse("api:domain_alias-detail", args=[dalias.pk])
url = reverse("v1:domain_alias-detail", args=[dalias.pk])
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
self.assertFalse(
@@ -257,7 +257,7 @@ class AccountAPITestCase(ModoAPITestCase):
def test_get_accounts(self):
"""Retrieve a list of accounts."""
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = response.json()
@@ -280,7 +280,7 @@ class AccountAPITestCase(ModoAPITestCase):
def test_create_account(self):
"""Try to create a new account."""
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, self.ACCOUNT_DATA, format="json")
self.assertEqual(response.status_code, 201)
@@ -306,7 +306,7 @@ class AccountAPITestCase(ModoAPITestCase):
def test_create_account_with_random_password(self):
"""Try to create a new account with random password."""
url = reverse("api:account-list")
url = reverse("v1:account-list")
data = dict(self.ACCOUNT_DATA)
data["random_password"] = True
del data["password"]
@@ -316,7 +316,7 @@ class AccountAPITestCase(ModoAPITestCase):
@override_settings(LANGUAGE_CODE="fr")
def test_create_account_default_lang(self):
"""Try to create a new account with(out) language."""
url = reverse("api:account-list")
url = reverse("v1:account-list")
data = dict(self.ACCOUNT_DATA)
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
@@ -337,16 +337,16 @@ class AccountAPITestCase(ModoAPITestCase):
data = copy.deepcopy(self.ACCOUNT_DATA)
data["domains"] = ["test.com"]
data["role"] = "DomainAdmins"
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
domain = admin_models.Domain.objects.get(name="test.com")
domain = models.Domain.objects.get(name="test.com")
admin = core_models.User.objects.get(
pk=response.json()["pk"])
self.assertIn(admin, domain.admins)
response = self.client.get(
reverse("api:account-detail", args=[admin.pk]))
reverse("v1:account-detail", args=[admin.pk]))
self.assertEqual(response.status_code, 200)
self.assertIn("domains", response.json())
@@ -359,7 +359,7 @@ class AccountAPITestCase(ModoAPITestCase):
"""Try to create a new account."""
data = copy.deepcopy(self.ACCOUNT_DATA)
del data["mailbox"]
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
account = response.json()
@@ -373,7 +373,7 @@ class AccountAPITestCase(ModoAPITestCase):
"""Check if unicity is respected."""
data = copy.deepcopy(self.ACCOUNT_DATA)
data["username"] = "user@test.com"
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
@@ -386,7 +386,7 @@ class AccountAPITestCase(ModoAPITestCase):
"""Try to create a new account."""
data = copy.deepcopy(self.ACCOUNT_DATA)
data["password"] = "toto"
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
errors = response.json()
@@ -398,13 +398,13 @@ class AccountAPITestCase(ModoAPITestCase):
HTTP_AUTHORIZATION="Token " + self.da_token.key)
data = copy.deepcopy(self.ACCOUNT_DATA)
data["mailbox"]["quota"] = 1000
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
data["username"] = "fromapi@test2.com"
data["mailbox"].update({"full_address": "fromapi@test2.com",
"quota": 10})
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
errors = response.json()
@@ -414,7 +414,7 @@ class AccountAPITestCase(ModoAPITestCase):
"""Try to create a new account."""
data = copy.deepcopy(self.ACCOUNT_DATA)
data["master_user"] = True
url = reverse("api:account-list")
url = reverse("v1:account-list")
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
errors = response.json()
@@ -423,7 +423,7 @@ class AccountAPITestCase(ModoAPITestCase):
def test_update_account(self):
"""Try to update an account."""
account = core_models.User.objects.get(username="user@test.com")
url = reverse("api:account-detail", args=[account.pk])
url = reverse("v1:account-detail", args=[account.pk])
data = {
"username": "fromapi@test.com",
"role": account.role,
@@ -450,7 +450,7 @@ class AccountAPITestCase(ModoAPITestCase):
"""Try to disable an account."""
account = core_factories.UserFactory(
username="reseller", groups=("Resellers", ))
url = reverse("api:account-detail", args=[account.pk])
url = reverse("v1:account-detail", args=[account.pk])
data = {
"username": "reseller",
"role": account.role,
@@ -463,7 +463,7 @@ class AccountAPITestCase(ModoAPITestCase):
"""Try to patch an account."""
account = core_models.User.objects.get(username="user@test.com")
old_quota = account.mailbox.quota
url = reverse("api:account-detail", args=[account.pk])
url = reverse("v1:account-detail", args=[account.pk])
data = {
"username": "fromapi@test.com",
"mailbox": {
@@ -479,7 +479,7 @@ class AccountAPITestCase(ModoAPITestCase):
def test_update_domain_admin_account(self):
"""Try to change administered domains."""
account = core_models.User.objects.get(username="admin@test.com")
url = reverse("api:account-detail", args=[account.pk])
url = reverse("v1:account-detail", args=[account.pk])
data = {
"username": account.username,
"role": account.role,
@@ -492,21 +492,21 @@ class AccountAPITestCase(ModoAPITestCase):
}
response = self.client.put(url, data, format="json")
self.assertEqual(response.status_code, 200)
domains = admin_models.Domain.objects.get_for_admin(account)
domains = models.Domain.objects.get_for_admin(account)
self.assertEqual(domains.count(), 2)
self.assertTrue(domains.filter(name="test2.com").exists())
data["domains"] = ["test2.com"]
response = self.client.put(url, data, format="json")
self.assertEqual(response.status_code, 200)
domains = admin_models.Domain.objects.get_for_admin(account)
domains = models.Domain.objects.get_for_admin(account)
self.assertEqual(domains.count(), 1)
self.assertTrue(domains.filter(name="test2.com").exists())
def test_update_account_wrong_address(self):
"""Try to update an account."""
account = core_models.User.objects.get(username="user@test.com")
url = reverse("api:account-detail", args=[account.pk])
url = reverse("v1:account-detail", args=[account.pk])
data = {
"username": "fromapi@test3.com",
"role": account.role,
@@ -524,7 +524,7 @@ class AccountAPITestCase(ModoAPITestCase):
account = core_models.User.objects.get(username="user@test.com")
domadmin = core_models.User.objects.get(username="admin@test.com")
self.assertTrue(domadmin.can_access(account))
url = reverse("api:account-detail", args=[account.pk])
url = reverse("v1:account-detail", args=[account.pk])
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
self.assertFalse(
@@ -533,7 +533,7 @@ class AccountAPITestCase(ModoAPITestCase):
def test_account_exists(self):
"""Validate /exists/ service."""
url = reverse("api:account-exists")
url = reverse("v1:account-exists")
response = self.client.get(
"{}?email={}".format(url, "user@test.com"))
self.assertEqual(response.status_code, 200)
@@ -551,7 +551,7 @@ class AccountAPITestCase(ModoAPITestCase):
"""Check the change password service."""
account = core_models.User.objects.get(username="user@test.com")
url = reverse(
"api:account-password", args=[account.pk])
"v1:account-password", args=[account.pk])
response = self.client.put(
url, {"password": "toto", "new_password": "pass"},
format="json")
@@ -568,7 +568,7 @@ class AccountAPITestCase(ModoAPITestCase):
@mock.patch("ovh.Client.get")
@mock.patch("ovh.Client.post")
def test_reset_password(self, client_post, client_get):
url = reverse("api:account-reset-password")
url = reverse("v1:account-reset-password")
# SMS password recovery not enabled
response = self.client.post(url)
self.assertEqual(response.status_code, 404)
@@ -621,7 +621,7 @@ class AliasAPITestCase(ModoAPITestCase):
def test_get_aliases(self):
"""Retrieve a list of aliases."""
url = reverse("api:alias-list")
url = reverse("v1:alias-list")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = response.json()
@@ -635,7 +635,7 @@ class AliasAPITestCase(ModoAPITestCase):
def test_get_alias(self):
"""Retrieve an alias."""
al = models.Alias.objects.get(address="alias@test.com")
url = reverse("api:alias-detail", args=[al.pk])
url = reverse("v1:alias-detail", args=[al.pk])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = response.json()
@@ -643,7 +643,7 @@ class AliasAPITestCase(ModoAPITestCase):
def test_create_alias(self):
"""Try to create a new alias."""
url = reverse("api:alias-list")
url = reverse("v1:alias-list")
response = self.client.post(url, self.ALIAS_DATA, format="json")
self.assertEqual(response.status_code, 201)
@@ -670,7 +670,7 @@ class AliasAPITestCase(ModoAPITestCase):
"""As DomainAdmin, try to create a new alias."""
self.client.credentials(
HTTP_AUTHORIZATION="Token " + self.da_token.key)
url = reverse("api:alias-list")
url = reverse("v1:alias-list")
response = self.client.post(url, self.ALIAS_DATA, format="json")
self.assertEqual(response.status_code, 201)
@@ -684,7 +684,7 @@ class AliasAPITestCase(ModoAPITestCase):
def test_update_alias(self):
"""Try to update an alias."""
alias = models.Alias.objects.get(address="alias@test.com")
url = reverse("api:alias-detail", args=[alias.pk])
url = reverse("v1:alias-detail", args=[alias.pk])
data = {
"address": "alias@test.com",
"recipients": ["user@test.com", "user@nonlocal.com"]
@@ -715,7 +715,7 @@ class AliasAPITestCase(ModoAPITestCase):
alias = models.Alias.objects.get(address="alias@test.com")
domadmin = core_models.User.objects.get(username="admin@test.com")
self.assertTrue(domadmin.can_access(alias))
url = reverse("api:alias-detail", args=[alias.pk])
url = reverse("v1:alias-detail", args=[alias.pk])
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
self.assertFalse(
@@ -750,7 +750,7 @@ class SenderAddressAPITestCase(ModoAPITestCase):
def test_list(self):
"""Retrieve a list of sender addresses."""
url = reverse("api:sender_address-list")
url = reverse("v1:sender_address-list")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
response = response.json()
@@ -758,7 +758,7 @@ class SenderAddressAPITestCase(ModoAPITestCase):
def test_create(self):
"""Create a new sender addresses."""
url = reverse("api:sender_address-list")
url = reverse("v1:sender_address-list")
mbox = models.Mailbox.objects.get(
address="admin", domain__name="test.com")
data = {"address": "@extdomain.test", "mailbox": mbox.pk}
@@ -785,7 +785,7 @@ class SenderAddressAPITestCase(ModoAPITestCase):
def test_patch(self):
"""Patch an existing sender address."""
url = reverse("api:sender_address-detail", args=[self.sa1.pk])
url = reverse("v1:sender_address-detail", args=[self.sa1.pk])
mbox = models.Mailbox.objects.get(
address="user", domain__name="test.com")
data = {"address": "@extdomain.test"}
@@ -797,7 +797,7 @@ class SenderAddressAPITestCase(ModoAPITestCase):
def test_update(self):
"""Update an existing sender address."""
url = reverse("api:sender_address-detail", args=[self.sa1.pk])
url = reverse("v1:sender_address-detail", args=[self.sa1.pk])
mbox = models.Mailbox.objects.get(
address="user", domain__name="test.com")
data = {"address": "@extdomain.test", "mailbox": mbox.pk}
@@ -809,7 +809,7 @@ class SenderAddressAPITestCase(ModoAPITestCase):
def test_delete(self):
"""Delete an existing sender address."""
url = reverse("api:sender_address-detail", args=[self.sa1.pk])
url = reverse("v1:sender_address-detail", args=[self.sa1.pk])
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
with self.assertRaises(models.SenderAddress.DoesNotExist):
-2
View File
@@ -111,13 +111,11 @@ def mailbox_deleted_handler(sender, **kwargs):
alias.delete()
models.Quota.objects.filter(username=mb.full_address).delete()
request = lib_signals.get_request()
print(request)
if request:
if not request.localconfig.parameters.get_value(
"handle_mailboxes", raise_exception=False):
return
keepdir = request.POST.get("keepdir", "false") == "true"
print(keepdir)
if keepdir:
return
mb.delete_dir()
+6 -6
View File
@@ -54,11 +54,13 @@ class AliasManager(models.Manager):
def create(self, *args, **kwargs):
"""Custom create method."""
creator = kwargs.pop("creator")
recipients = kwargs.pop("recipients")
creator = kwargs.pop("creator", None)
recipients = kwargs.pop("recipients", None)
alias = super().create(*args, **kwargs)
alias.post_create(creator)
alias.set_recipients(recipients)
if creator:
alias.post_create(creator)
if recipients:
alias.set_recipients(recipients)
return alias
@@ -208,8 +210,6 @@ class Alias(AdminObject):
raise BadRequest(_("Invalid line: {}").format(row))
self.address = row[1].strip().lower()
local_part, self.domain = validate_alias_address(self.address, user)
if Alias.objects.filter(address=self.address, internal=False).exists():
raise Conflict
self.enabled = (row[2].strip().lower() in ["true", "1", "yes", "y"])
self.save()
self.set_recipients([raddress.strip() for raddress in row[3:]])
@@ -4,7 +4,7 @@ from modoboa.lib.tests import ModoTestCase
class OpenAPITestCase(ModoTestCase):
openapi_schema_url = reverse_lazy('schema')
openapi_schema_url = reverse_lazy('schema-v1-legacy')
def test_unauthorized(self):
self.client.logout()
View File
View File
@@ -2,7 +2,7 @@
from rest_framework import serializers
from . import lib
from ... import lib
class ResourcesSerializer(serializers.Serializer):
@@ -32,23 +32,3 @@ class ResourcesSerializer(serializers.Serializer):
limit.max_value = max_value
limit.save(update_fields=["max_value"])
return instance
class LimitsGlobalParemetersSerializer(serializers.Serializer):
"""A serializer for global parameters."""
# Per-admin limits
enable_admin_limits = serializers.BooleanField(default=True)
deflt_user_domain_admins_limit = serializers.IntegerField(default=0)
deflt_user_domains_limit = serializers.IntegerField(default=0)
deflt_user_domain_aliases_limit = serializers.IntegerField(default=0)
deflt_user_mailboxes_limit = serializers.IntegerField(default=0)
deflt_user_mailbox_aliases_limit = serializers.IntegerField(default=0)
deflt_user_quota_limit = serializers.IntegerField(default=0)
# Per-domain limits
enable_domain_limits = serializers.BooleanField(default=False)
deflt_domain_domain_admins_limit = serializers.IntegerField(default=0)
deflt_domain_domain_aliases_limit = serializers.IntegerField(default=0)
deflt_domain_mailboxes_limit = serializers.IntegerField(default=0)
deflt_domain_mailbox_aliases_limit = serializers.IntegerField(default=0)
@@ -11,7 +11,7 @@ from modoboa.admin.models import Domain
from modoboa.core import factories as core_factories
from modoboa.core.models import User
from modoboa.lib import permissions, tests as lib_tests
from .. import utils
from ... import utils
class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
@@ -39,7 +39,7 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
HTTP_AUTHORIZATION="Token " + self.r_token.key)
limit = self.reseller.userobjectlimit_set.get(name="domain_admins")
url = reverse("api:account-list")
url = reverse("v1:account-list")
data = {
"username": "fromapi@test.com",
"role": "DomainAdmins",
@@ -61,7 +61,7 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
user = User.objects.get(username="user@test.com")
domain = Domain.objects.get(name="test.com")
domain.add_admin(self.reseller)
url = reverse("api:account-detail", args=[user.pk])
url = reverse("v1:account-detail", args=[user.pk])
data = {
"username": user.username,
"role": "DomainAdmins",
@@ -82,7 +82,7 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
quota = self.reseller.userobjectlimit_set.get(name="quota")
quota.max_value = 3
quota.save(update_fields=["max_value"])
url = reverse("api:domain-list")
url = reverse("v1:domain-list")
data = {"name": "test3.com", "quota": 1}
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
@@ -102,9 +102,10 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
response.content.decode("utf-8"), '"Domains: limit reached"'
)
self.client.delete(
reverse("api:domain-detail",
resp = self.client.delete(
reverse("v1:domain-detail",
args=[Domain.objects.get(name="test4.com").pk]))
self.assertEqual(resp.status_code, 204)
data["quota"] = 0
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
@@ -119,7 +120,7 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
domain = Domain.objects.get(name="test.com")
domain.add_admin(self.reseller)
limit = self.reseller.userobjectlimit_set.get(name="domain_aliases")
url = reverse("api:domain_alias-list")
url = reverse("v1:domain_alias-list")
data = {"name": "dalias1.com", "target": domain.pk}
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
@@ -140,7 +141,7 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
HTTP_AUTHORIZATION="Token " + self.da_token.key)
limit = self.user.userobjectlimit_set.get(name="mailboxes")
url = reverse("api:account-list")
url = reverse("v1:account-list")
data = {
"username": "fromapi@test.com",
"role": "SimpleUsers",
@@ -171,7 +172,7 @@ class APIAdminLimitsTestCase(lib_tests.ModoAPITestCase):
HTTP_AUTHORIZATION="Token " + self.da_token.key)
limit = self.user.userobjectlimit_set.get(name="mailbox_aliases")
url = reverse("api:alias-list")
url = reverse("v1:alias-list")
data = {
"address": "alias_fromapi@test.com",
"recipients": [
@@ -212,7 +213,7 @@ class APIDomainLimitsTestCase(lib_tests.ModoAPITestCase):
domain = Domain.objects.get(name="test.com")
limit = domain.domainobjectlimit_set.get(name="mailboxes")
self.assertTrue(limit.is_exceeded())
url = reverse("api:account-list")
url = reverse("v1:account-list")
data = {
"username": "fromapi@test.com",
"role": "SimpleUsers",
@@ -229,7 +230,7 @@ class APIDomainLimitsTestCase(lib_tests.ModoAPITestCase):
"""Check domain_aliases limit."""
domain = Domain.objects.get(name="test.com")
limit = domain.domainobjectlimit_set.get(name="domain_aliases")
url = reverse("api:domain_alias-list")
url = reverse("v1:domain_alias-list")
data = {"name": "dalias1.com", "target": domain.pk}
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
@@ -246,7 +247,7 @@ class APIDomainLimitsTestCase(lib_tests.ModoAPITestCase):
domain = Domain.objects.get(name="test.com")
limit = domain.domainobjectlimit_set.get(name="mailbox_aliases")
self.assertTrue(limit.is_exceeded())
url = reverse("api:alias-list")
url = reverse("v1:alias-list")
data = {
"address": "alias_fromapi@test.com",
"recipients": [
@@ -278,7 +279,7 @@ class ResourcesAPITestCase(lib_tests.ModoAPITestCase):
def test_get_admin_resources(self):
"""Retrieve admin resources."""
url = reverse("api:resources-detail", args=[self.user.pk])
url = reverse("v1:resources-detail", args=[self.user.pk])
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
expected = {
@@ -305,7 +306,7 @@ class ResourcesAPITestCase(lib_tests.ModoAPITestCase):
def test_update_resources(self):
"""Update resources."""
url = reverse("api:resources-detail", args=[self.reseller.pk])
url = reverse("v1:resources-detail", args=[self.reseller.pk])
response = self.client.get(url)
resources = response.data
resources.update({"domains": 1000, "mailboxes": 1000})
@@ -319,7 +320,7 @@ class ResourcesAPITestCase(lib_tests.ModoAPITestCase):
self.client.credentials(
HTTP_AUTHORIZATION="Token {}".format(self.da_token.key))
resources.update({"domains": 2, "mailboxes": 2})
url = reverse("api:resources-detail", args=[self.user.pk])
url = reverse("v1:resources-detail", args=[self.user.pk])
response = self.client.put(url, resources)
self.assertEqual(response.status_code, 404)
@@ -328,7 +329,7 @@ class ResourcesAPITestCase(lib_tests.ModoAPITestCase):
self.client.credentials(
HTTP_AUTHORIZATION="Token {}".format(self.r_token.key))
resources.update({"domains": 500, "mailboxes": 500})
url = reverse("api:resources-detail", args=[self.user.pk])
url = reverse("v1:resources-detail", args=[self.user.pk])
response = self.client.put(url, resources)
self.assertEqual(response.status_code, 200)
self.assertEqual(
View File
+23
View File
@@ -0,0 +1,23 @@
"""Limits serializers for API v2."""
from rest_framework import serializers
class LimitsGlobalParemetersSerializer(serializers.Serializer):
"""A serializer for global parameters."""
# Per-admin limits
enable_admin_limits = serializers.BooleanField(default=True)
deflt_user_domain_admins_limit = serializers.IntegerField(default=0)
deflt_user_domains_limit = serializers.IntegerField(default=0)
deflt_user_domain_aliases_limit = serializers.IntegerField(default=0)
deflt_user_mailboxes_limit = serializers.IntegerField(default=0)
deflt_user_mailbox_aliases_limit = serializers.IntegerField(default=0)
deflt_user_quota_limit = serializers.IntegerField(default=0)
# Per-domain limits
enable_domain_limits = serializers.BooleanField(default=False)
deflt_domain_domain_admins_limit = serializers.IntegerField(default=0)
deflt_domain_domain_aliases_limit = serializers.IntegerField(default=0)
deflt_domain_mailboxes_limit = serializers.IntegerField(default=0)
deflt_domain_mailbox_aliases_limit = serializers.IntegerField(default=0)
+1 -1
View File
@@ -8,7 +8,7 @@ def load_limits_settings():
"""Load settings."""
from modoboa.parameters import tools as param_tools
from . import app_settings
from . import serializers
from .api.v2 import serializers
param_tools.registry.add("global", app_settings.ParametersForm, _("Limits"))
param_tools.registry.add2(
-2
View File
@@ -2,7 +2,6 @@
from django.conf import settings
from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.functional import cached_property
from django.utils.translation import ugettext as _
@@ -59,7 +58,6 @@ class ObjectLimitMixin(object):
return "{}%".format(self.usage)
@python_2_unicode_compatible
class UserObjectLimit(ObjectLimitMixin, models.Model):
"""Object level limit."""
+8 -7
View File
@@ -1,3 +1,4 @@
from django.core import exceptions
from django.core.files.base import ContentFile
from django.urls import reverse
@@ -107,7 +108,7 @@ account; user3@{domain}; toto; User; One; True; SimpleUsers; user3@{domain}; 5
f = ContentFile("""alias; alias1@{domain}; True; user@{domain}
alias; alias2@{domain}; True; user@{domain}
""".format(domain=self.domain), name="aliases.csv")
response = self.client.post(
self.client.post(
reverse("admin:identity_import"), {
"sourcefile": f
}
@@ -117,12 +118,12 @@ alias; alias2@{domain}; True; user@{domain}
f = ContentFile("""
alias; alias3@{domain}; True; user@{domain}
""".format(domain=self.domain), name="aliases.csv")
response = self.client.post(
reverse("admin:identity_import"), {
"sourcefile": f
}
)
self.assertContains(response, "Mailbox aliases: limit reached")
with self.assertRaises(exceptions.ValidationError):
self.client.post(
reverse("admin:identity_import"), {
"sourcefile": f
}
)
class UserLimitImportTestCase(LimitImportTestCase):
+108
View File
@@ -0,0 +1,108 @@
"""relaydomains API v1 unit tests."""
import json
from django.urls import reverse
from modoboa.admin import factories as admin_factories, models as admin_models
from modoboa.lib.tests import ModoAPITestCase
from modoboa.transport import factories as tr_factories, models as tr_models
class DataMixin(object):
"""A mixin to provide test data."""
@classmethod
def setUpTestData(cls): # NOQA:N802
super(DataMixin, cls).setUpTestData()
transport = tr_factories.TransportFactory(
pattern="test.com", _settings={
"relay_target_host": "external.host.tld",
"relay_target_port": 25,
"relay_verify_recipients": False
}
)
cls.domain1 = admin_factories.DomainFactory(
name="test.com", type="relaydomain", transport=transport)
transport = tr_factories.TransportFactory(
pattern="domain2.test", _settings={
"relay_target_host": "external.host.tld",
"relay_target_port": 25,
"relay_verify_recipients": True
}
)
cls.domain2 = admin_factories.DomainFactory(
name="test2.com", type="relaydomain", transport=transport)
class RelayDomainAPITestCase(DataMixin, ModoAPITestCase):
"""API test cases."""
def test_list(self):
"""Test list service."""
url = reverse("api:relaydomain-list")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
def test_create(self):
"""Test create service."""
url = reverse("api:relaydomain-list")
settings = {
"relay_target_host": "1.2.3.4"
}
data = {
"name": "test3.com",
"transport": {
"service": "relay",
"_settings": json.dumps(settings)
}
}
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
self.assertEqual(
response.data["transport"]["_settings"],
["relay_target_port: This field is required"]
)
settings.update({"relay_target_port": 25})
data["transport"]["_settings"] = json.dumps(settings)
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
domain = admin_models.Domain.objects.get(name="test3.com")
self.assertEqual(
domain.transport.next_hop, "[{}]:{}".format(
settings["relay_target_host"], settings["relay_target_port"])
)
def test_update(self):
"""Test update service."""
url = reverse("api:relaydomain-detail", args=[self.domain1.pk])
settings = self.domain1.transport._settings.copy()
settings.update({"relay_target_port": 1000})
data = {
"name": "test3.com",
"transport": {
"service": "relay",
"_settings": json.dumps(settings)
}
}
response = self.client.put(url, data, format="json")
self.assertEqual(response.status_code, 200)
self.domain1.refresh_from_db()
self.domain1.transport.refresh_from_db()
self.assertEqual(self.domain1.name, data["name"])
self.assertEqual(
self.domain1.transport.next_hop, "[{}]:{}".format(
settings["relay_target_host"], settings["relay_target_port"])
)
def test_delete(self):
"""Test delete service."""
url = reverse("api:relaydomain-detail", args=[self.domain1.pk])
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
with self.assertRaises(admin_models.Domain.DoesNotExist):
self.domain1.refresh_from_db()
self.assertFalse(
tr_models.Transport.objects.filter(pattern="test.com").exists())
+1 -102
View File
@@ -1,7 +1,5 @@
"""relaydomains unit tests."""
import json
from django.core.files.base import ContentFile
from django.test import TestCase
from django.urls import reverse
@@ -9,7 +7,7 @@ from django.urls import reverse
from modoboa.admin import factories as admin_factories, models as admin_models
from modoboa.core.factories import UserFactory
from modoboa.lib.test_utils import MapFilesTestCaseMixin
from modoboa.lib.tests import ModoAPITestCase, ModoTestCase
from modoboa.lib.tests import ModoTestCase
from modoboa.limits import utils as limits_utils
from modoboa.transport import factories as tr_factories, models as tr_models
from . import models
@@ -363,102 +361,3 @@ class MapFilesTestCase(MapFilesTestCaseMixin, TestCase):
"sql-relaydomains.cf",
"sql-relay-recipient-verification.cf"
]
class DataMixin(object):
"""A mixin to provide test data."""
@classmethod
def setUpTestData(cls): # NOQA:N802
super(DataMixin, cls).setUpTestData()
transport = tr_factories.TransportFactory(
pattern="test.com", _settings={
"relay_target_host": "external.host.tld",
"relay_target_port": 25,
"relay_verify_recipients": False
}
)
cls.domain1 = admin_factories.DomainFactory(
name="test.com", type="relaydomain", transport=transport)
transport = tr_factories.TransportFactory(
pattern="domain2.test", _settings={
"relay_target_host": "external.host.tld",
"relay_target_port": 25,
"relay_verify_recipients": True
}
)
cls.domain2 = admin_factories.DomainFactory(
name="test2.com", type="relaydomain", transport=transport)
class RelayDomainAPITestCase(DataMixin, ModoAPITestCase):
"""API test cases."""
def test_list(self):
"""Test list service."""
url = reverse("api:relaydomain-list")
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.data), 2)
def test_create(self):
"""Test create service."""
url = reverse("api:relaydomain-list")
settings = {
"relay_target_host": "1.2.3.4"
}
data = {
"name": "test3.com",
"transport": {
"service": "relay",
"_settings": json.dumps(settings)
}
}
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 400)
self.assertEqual(
response.data["transport"]["_settings"],
["relay_target_port: This field is required"]
)
settings.update({"relay_target_port": 25})
data["transport"]["_settings"] = json.dumps(settings)
response = self.client.post(url, data, format="json")
self.assertEqual(response.status_code, 201)
domain = admin_models.Domain.objects.get(name="test3.com")
self.assertEqual(
domain.transport.next_hop, "[{}]:{}".format(
settings["relay_target_host"], settings["relay_target_port"])
)
def test_update(self):
"""Test update service."""
url = reverse("api:relaydomain-detail", args=[self.domain1.pk])
settings = self.domain1.transport._settings.copy()
settings.update({"relay_target_port": 1000})
data = {
"name": "test3.com",
"transport": {
"service": "relay",
"_settings": json.dumps(settings)
}
}
response = self.client.put(url, data, format="json")
self.assertEqual(response.status_code, 200)
self.domain1.refresh_from_db()
self.domain1.transport.refresh_from_db()
self.assertEqual(self.domain1.name, data["name"])
self.assertEqual(
self.domain1.transport.next_hop, "[{}]:{}".format(
settings["relay_target_host"], settings["relay_target_port"])
)
def test_delete(self):
"""Test delete service."""
url = reverse("api:relaydomain-detail", args=[self.domain1.pk])
response = self.client.delete(url)
self.assertEqual(response.status_code, 204)
with self.assertRaises(admin_models.Domain.DoesNotExist):
self.domain1.refresh_from_db()
self.assertFalse(
tr_models.Transport.objects.filter(pattern="test.com").exists())
+4
View File
@@ -60,6 +60,10 @@ if extra_routes:
# API urls
urlpatterns += [
# FIXME: legacy, to remove ASAP
path('docs/openapi.json',
SpectacularJSONAPIView.as_view(api_version="v1"), name='schema-v1-legacy'),
path('api/schema-v1/',
SpectacularJSONAPIView.as_view(api_version="v1"), name='schema-v1'),
path('api/schema-v1/swagger/',
+2 -2
View File
@@ -9,8 +9,8 @@ app_name = "api"
urlpatterns = [
path('', include("modoboa.core.api.v1.urls")),
path('', include("modoboa.admin.api.v1.urls")),
path('', include("modoboa.limits.urls_api")),
path('', include("modoboa.relaydomains.urls_api"))
path('', include("modoboa.limits.api.v1.urls")),
path('', include("modoboa.relaydomains.api.v1.urls"))
]
urlpatterns += exts_pool.get_urls(category="api")
+2 -2
View File
@@ -18,8 +18,8 @@ urlpatterns = [
path('', include("modoboa.core.api.v2.urls")),
path('', include("modoboa.admin.api.v2.urls")),
path('', include("modoboa.parameters.api.v2.urls")),
path('', include("modoboa.limits.urls_api")),
path('', include("modoboa.relaydomains.urls_api")),
path('', include("modoboa.limits.api.v1.urls")),
path('', include("modoboa.relaydomains.api.v1.urls")),
path('', include("modoboa.dnstools.api.v2.urls")),
path('', include("modoboa.maillog.api.v2.urls")),
]