mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Merge pull request #2497 from modoboa/refacto/django_3_2
Django 3.2 support
This commit is contained in:
@@ -313,6 +313,24 @@ class WritableAccountSerializer(AccountSerializer):
|
||||
raise serializers.ValidationError({
|
||||
"username": _("Must be equal to mailbox full_address")
|
||||
})
|
||||
if "mailbox" in data:
|
||||
self.address, domain_name = email_utils.split_mailbox(data["mailbox"]["full_address"])
|
||||
self.domain = get_object_or_404(
|
||||
admin_models.Domain, name=domain_name)
|
||||
creator = self.context["request"].user
|
||||
if not creator.can_access(self.domain):
|
||||
raise serializers.ValidationError({"mailbox": _("Permission denied.")})
|
||||
if not self.instance:
|
||||
try:
|
||||
core_signals.can_create_object.send(
|
||||
sender=self.__class__, context=creator,
|
||||
klass=admin_models.Mailbox)
|
||||
core_signals.can_create_object.send(
|
||||
sender=self.__class__, context=self.domain,
|
||||
object_type="mailboxes")
|
||||
except lib_exceptions.ModoboaException as inst:
|
||||
raise serializers.ValidationError({
|
||||
"mailbox": force_text(inst)})
|
||||
condition = (
|
||||
not data.get("random_password") and (
|
||||
data.get("password") or
|
||||
@@ -350,25 +368,9 @@ class WritableAccountSerializer(AccountSerializer):
|
||||
def _create_mailbox(self, creator, account, data):
|
||||
"""Create a new Mailbox instance."""
|
||||
full_address = data.pop("full_address")
|
||||
address, domain_name = email_utils.split_mailbox(full_address)
|
||||
domain = get_object_or_404(
|
||||
admin_models.Domain, name=domain_name)
|
||||
if not creator.can_access(domain):
|
||||
raise serializers.ValidationError({
|
||||
"domain": _("Permission denied.")})
|
||||
try:
|
||||
core_signals.can_create_object.send(
|
||||
sender=self.__class__, context=creator,
|
||||
klass=admin_models.Mailbox)
|
||||
core_signals.can_create_object.send(
|
||||
sender=self.__class__, context=domain,
|
||||
object_type="mailboxes")
|
||||
except lib_exceptions.ModoboaException as inst:
|
||||
raise serializers.ValidationError({
|
||||
"domain": force_text(inst)})
|
||||
quota = data.pop("quota", None)
|
||||
mb = admin_models.Mailbox(
|
||||
user=account, address=address, domain=domain, **data)
|
||||
user=account, address=self.address, domain=self.domain, **data)
|
||||
mb.set_quota(quota, creator.has_perm("admin.add_domain"))
|
||||
default_msg_limit = param_tools.get_global_parameter(
|
||||
"default_mailbox_message_limit")
|
||||
|
||||
@@ -249,7 +249,7 @@ class AccountAPITestCase(ModoAPITestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Test setup."""
|
||||
super(AccountAPITestCase, self).setUp()
|
||||
super().setUp()
|
||||
self.set_global_parameters({
|
||||
"enable_admin_limits": False,
|
||||
"enable_domain_limits": False
|
||||
@@ -400,15 +400,17 @@ class AccountAPITestCase(ModoAPITestCase):
|
||||
data["mailbox"]["quota"] = 1000
|
||||
url = reverse("v1:account-list")
|
||||
response = self.client.post(url, data, format="json")
|
||||
# Should fail because domain quota is exceeded
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
data["username"] = "fromapi@test2.com"
|
||||
data["mailbox"].update({"full_address": "fromapi@test2.com",
|
||||
"quota": 10})
|
||||
url = reverse("v1:account-list")
|
||||
response = self.client.post(url, data, format="json")
|
||||
# Should fail because admin has no access to @test2.com domain
|
||||
self.assertEqual(response.status_code, 400)
|
||||
errors = response.json()
|
||||
self.assertIn("domain", errors)
|
||||
self.assertIn("mailbox", errors)
|
||||
|
||||
def test_create_account_bad_master_user(self):
|
||||
"""Try to create a new account."""
|
||||
|
||||
@@ -5,6 +5,7 @@ import os
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core import validators as dj_validators
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from django.contrib.auth import password_validation
|
||||
@@ -13,6 +14,7 @@ from rest_framework import serializers
|
||||
|
||||
from modoboa.admin.api.v1 import serializers as v1_serializers
|
||||
from modoboa.core import models as core_models, signals as core_signals
|
||||
from modoboa.lib import email_utils
|
||||
from modoboa.lib import exceptions as lib_exceptions
|
||||
from modoboa.lib import fields as lib_fields
|
||||
from modoboa.lib import validators, web_utils
|
||||
@@ -402,6 +404,25 @@ class WritableAccountSerializer(v1_serializers.WritableAccountSerializer):
|
||||
data["mailbox"] = {
|
||||
"use_domain_quota": True
|
||||
}
|
||||
if "mailbox" in data:
|
||||
self.address, domain_name = email_utils.split_mailbox(data["username"])
|
||||
self.domain = get_object_or_404(
|
||||
models.Domain, name=domain_name)
|
||||
creator = self.context["request"].user
|
||||
if not creator.can_access(self.domain):
|
||||
raise serializers.ValidationError({"mailbox": _("Permission denied.")})
|
||||
if not self.instance:
|
||||
try:
|
||||
core_signals.can_create_object.send(
|
||||
sender=self.__class__, context=creator,
|
||||
klass=models.Mailbox)
|
||||
core_signals.can_create_object.send(
|
||||
sender=self.__class__, context=self.domain,
|
||||
object_type="mailboxes")
|
||||
except lib_exceptions.ModoboaException as inst:
|
||||
raise serializers.ValidationError({
|
||||
"mailbox": force_text(inst)
|
||||
})
|
||||
if data.get("password") or not self.partial:
|
||||
password = data.get("password")
|
||||
if password:
|
||||
|
||||
@@ -6,9 +6,9 @@ from .app_settings import load_admin_settings
|
||||
|
||||
|
||||
class AdminConfig(AppConfig):
|
||||
|
||||
"""App configuration."""
|
||||
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "modoboa.admin"
|
||||
verbose_name = "Modoboa admin console"
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ from reversion import revisions as reversion
|
||||
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.db import models
|
||||
from django.utils.encoding import python_2_unicode_compatible, smart_text
|
||||
from django.utils.encoding import smart_text
|
||||
from django.utils.translation import ugettext as _, ugettext_lazy
|
||||
|
||||
from modoboa.core import models as core_models, signals as core_signals
|
||||
@@ -26,7 +26,6 @@ class DomainAliasManager(models.Manager):
|
||||
return self.get_queryset().filter(owners__user=admin)
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DomainAlias(AdminObject):
|
||||
|
||||
"""Domain aliases."""
|
||||
|
||||
@@ -26,6 +26,7 @@ def load_core_settings():
|
||||
class CoreConfig(AppConfig):
|
||||
"""App configuration."""
|
||||
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "modoboa.core"
|
||||
verbose_name = "Modoboa core"
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class DnstoolsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'modoboa.dnstools'
|
||||
|
||||
@@ -4,7 +4,6 @@ import datetime
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from . import constants
|
||||
@@ -35,7 +34,6 @@ class DNSRecordManager(models.Manager):
|
||||
return record
|
||||
|
||||
|
||||
@python_2_unicode_compatible
|
||||
class DNSRecord(models.Model):
|
||||
"""A model to store DNS records for Domain."""
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ def render_field(
|
||||
@register.simple_tag
|
||||
def render_fields_group(form, pattern):
|
||||
"""Render a group of fields."""
|
||||
first = forms.forms.BoundField(form, form.fields[pattern], pattern)
|
||||
first = forms.BoundField(form, form.fields[pattern], pattern)
|
||||
configure_field_classes(first)
|
||||
label = first.label
|
||||
group = [first]
|
||||
@@ -66,7 +66,7 @@ def render_fields_group(form, pattern):
|
||||
fname = "%s_%d" % (pattern, cpt)
|
||||
if fname not in form.fields:
|
||||
break
|
||||
bfield = forms.forms.BoundField(form, form.fields[fname], fname)
|
||||
bfield = forms.BoundField(form, form.fields[fname], fname)
|
||||
if len(bfield.errors):
|
||||
haserror = True
|
||||
configure_field_classes(bfield)
|
||||
|
||||
@@ -18,9 +18,9 @@ def load_limits_settings():
|
||||
|
||||
|
||||
class LimitsConfig(AppConfig):
|
||||
|
||||
"""App configuration."""
|
||||
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "modoboa.limits"
|
||||
verbose_name = "Modoboa admin limits"
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ from .forms import load_settings
|
||||
class MaillogConfig(AppConfig):
|
||||
"""App configuration."""
|
||||
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "modoboa.maillog"
|
||||
verbose_name = "Modoboa graphical statistics"
|
||||
|
||||
|
||||
@@ -2,4 +2,4 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class ParametersConfig(AppConfig):
|
||||
name = "parameters"
|
||||
name = "modoboa.parameters"
|
||||
|
||||
+7
-12
@@ -1,5 +1,6 @@
|
||||
"""Core components of the policy daemon."""
|
||||
|
||||
from asgiref.sync import sync_to_async
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
from email.message import EmailMessage
|
||||
@@ -216,6 +217,7 @@ def get_next_execution_dt():
|
||||
hour=0, minute=0, second=0)
|
||||
|
||||
|
||||
@sync_to_async
|
||||
@close_db_connections
|
||||
def get_domains_to_reset():
|
||||
"""
|
||||
@@ -230,9 +232,10 @@ def get_domains_to_reset():
|
||||
).update(
|
||||
status=admin_constants.ALARM_CLOSED, closed=timezone.now()
|
||||
)
|
||||
return qset
|
||||
return list(qset)
|
||||
|
||||
|
||||
@sync_to_async
|
||||
@close_db_connections
|
||||
def get_mailboxes_to_reset():
|
||||
"""
|
||||
@@ -250,25 +253,17 @@ def get_mailboxes_to_reset():
|
||||
).update(
|
||||
status=admin_constants.ALARM_CLOSED, closed=timezone.now()
|
||||
)
|
||||
return qset
|
||||
return list(qset)
|
||||
|
||||
|
||||
async def reset_counters():
|
||||
"""Reset all counters."""
|
||||
rclient = await aioredis.create_redis_pool(settings.REDIS_URL)
|
||||
logger.info("Resetting all counters")
|
||||
# We're going to execute sync code so we need an executor
|
||||
executor = concurrent.futures.ThreadPoolExecutor(max_workers=3)
|
||||
loop = asyncio.get_event_loop()
|
||||
futures = [
|
||||
loop.run_in_executor(executor, get_domains_to_reset),
|
||||
loop.run_in_executor(executor, get_mailboxes_to_reset)
|
||||
]
|
||||
domains, mboxes = await asyncio.gather(*futures)
|
||||
for domain in domains:
|
||||
for domain in await get_domains_to_reset():
|
||||
rclient.hset(
|
||||
constants.REDIS_HASHNAME, domain.name, domain.message_limit)
|
||||
for mb in mboxes:
|
||||
for mb in await get_mailboxes_to_reset():
|
||||
rclient.hset(
|
||||
constants.REDIS_HASHNAME, mb.full_address, mb.message_limit)
|
||||
rclient.close()
|
||||
|
||||
@@ -4,9 +4,9 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class RelayDomainsConfig(AppConfig):
|
||||
|
||||
"""App configuration."""
|
||||
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "modoboa.relaydomains"
|
||||
verbose_name = "Modoboa relay domains"
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ from django.apps import AppConfig
|
||||
|
||||
|
||||
class TransportConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "modoboa.transport"
|
||||
|
||||
def ready(self):
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
django>=2.2,<2.3
|
||||
django<4.0
|
||||
django-ckeditor==6.3.0
|
||||
django-phonenumber-field[phonenumbers]==6.1.0
|
||||
django-reversion==3.0.9
|
||||
django-reversion==5.0.0
|
||||
django-xforwardedfor-middleware==2.0
|
||||
django-otp==1.1.3
|
||||
django-filter
|
||||
|
||||
Reference in New Issue
Block a user