From 3ba8c5cdfdf08e6b372b24991374cbdb733b0016 Mon Sep 17 00:00:00 2001 From: Spitap Date: Wed, 26 Apr 2023 08:06:35 +0200 Subject: [PATCH 01/11] Removed deprecation --- modoboa/admin/api/v1/serializers.py | 14 +- modoboa/admin/api/v1/viewsets.py | 2 +- modoboa/admin/api/v2/serializers.py | 2 +- modoboa/admin/api/v2/tests.py | 6 +- modoboa/admin/api/v2/viewsets.py | 2 +- modoboa/admin/app_settings.py | 182 ++++---- modoboa/admin/constants.py | 2 +- modoboa/admin/forms/account.py | 46 +- modoboa/admin/forms/alias.py | 14 +- modoboa/admin/forms/domain.py | 44 +- modoboa/admin/forms/export.py | 4 +- modoboa/admin/forms/forward.py | 10 +- modoboa/admin/forms/import_.py | 14 +- modoboa/admin/handlers.py | 2 +- modoboa/admin/lib.py | 10 +- .../commands/subcommands/_export.py | 4 +- .../commands/subcommands/_import.py | 2 +- .../commands/subcommands/_manage_dkim_keys.py | 10 +- .../management/commands/subcommands/_mx.py | 8 +- modoboa/admin/models/alias.py | 18 +- modoboa/admin/models/domain.py | 32 +- modoboa/admin/models/domain_alias.py | 18 +- modoboa/admin/models/mailbox.py | 18 +- modoboa/admin/signals.py | 39 +- modoboa/admin/templatetags/admin_tags.py | 4 +- modoboa/admin/tests/test_export.py | 12 +- modoboa/admin/tests/test_mx.py | 4 +- modoboa/admin/views/alias.py | 4 +- modoboa/admin/views/dns.py | 2 +- modoboa/admin/views/domain.py | 4 +- modoboa/admin/views/export.py | 2 +- modoboa/admin/views/identity.py | 4 +- modoboa/admin/views/import_.py | 4 +- modoboa/admin/views/user.py | 2 +- modoboa/core/api/v1/serializers.py | 2 +- modoboa/core/api/v1/viewsets.py | 2 +- modoboa/core/api/v2/serializers.py | 18 +- modoboa/core/api/v2/views.py | 2 +- modoboa/core/app_settings.py | 436 +++++++++--------- modoboa/core/apps.py | 6 +- modoboa/core/checks/settings_checks.py | 2 +- modoboa/core/constants.py | 20 +- modoboa/core/drf_authentication.py | 2 +- modoboa/core/extensions.py | 5 +- modoboa/core/forms.py | 16 +- modoboa/core/handlers.py | 8 +- .../commands/communicate_with_public_api.py | 2 +- ...il_is_active_core_user_email_c0c03f_idx.py | 17 + modoboa/core/models.py | 40 +- modoboa/core/password_hashers/__init__.py | 4 +- modoboa/core/password_hashers/advanced.py | 6 +- modoboa/core/password_hashers/base.py | 6 +- modoboa/core/password_validation.py | 10 +- modoboa/core/signals.py | 49 +- modoboa/core/sms_backends/ovh.py | 2 +- modoboa/core/templatetags/core_tags.py | 6 +- modoboa/core/tests/stupid_extension_2/urls.py | 4 +- modoboa/core/utils.py | 2 +- modoboa/core/views/admin.py | 2 +- modoboa/core/views/auth.py | 2 +- modoboa/core/views/base.py | 4 +- modoboa/core/views/user.py | 6 +- modoboa/dmarc/forms.py | 2 +- modoboa/dmarc/handlers.py | 2 +- modoboa/dmarc/lib.py | 6 +- modoboa/dmarc/models.py | 2 +- modoboa/dmarc/templatetags/dmarc_tags.py | 2 +- modoboa/dmarc/views.py | 2 +- modoboa/dnstools/lib.py | 2 +- modoboa/dnstools/models.py | 2 +- modoboa/dnstools/views.py | 2 +- modoboa/imap_migration/app_settings.py | 2 +- modoboa/imap_migration/apps.py | 6 +- modoboa/imap_migration/auth_backends.py | 2 +- modoboa/imap_migration/checks.py | 2 +- modoboa/ldapsync/lib.py | 2 +- modoboa/lib/api_client.py | 2 +- modoboa/lib/cryptutils.py | 6 +- modoboa/lib/db_utils.py | 2 +- modoboa/lib/email_utils.py | 10 +- modoboa/lib/exceptions.py | 2 +- modoboa/lib/fields.py | 8 +- modoboa/lib/form_utils.py | 6 +- modoboa/lib/ldap_utils.py | 2 +- modoboa/lib/middleware.py | 16 +- modoboa/lib/sysutils.py | 4 +- modoboa/lib/templatetags/form_tags.py | 4 +- modoboa/lib/templatetags/lib_tags.py | 2 +- modoboa/lib/tests/test_email_utils.py | 4 +- modoboa/lib/u2u_decode.py | 4 +- modoboa/lib/validators.py | 4 +- modoboa/limits/app_settings.py | 2 +- modoboa/limits/apps.py | 2 +- modoboa/limits/constants.py | 2 +- modoboa/limits/forms.py | 2 +- modoboa/limits/handlers.py | 2 +- modoboa/limits/lib.py | 2 +- modoboa/limits/models.py | 2 +- modoboa/maillog/api/v2/serializers.py | 2 +- modoboa/maillog/forms.py | 18 +- modoboa/maillog/graphics.py | 36 +- modoboa/maillog/handlers.py | 2 +- modoboa/maillog/signals.py | 2 +- modoboa/maillog/views.py | 2 +- modoboa/pdfcredentials/api/v2/serializers.py | 2 +- modoboa/pdfcredentials/api/v2/views.py | 2 +- modoboa/pdfcredentials/app_settings.py | 2 +- modoboa/pdfcredentials/apps.py | 6 +- modoboa/pdfcredentials/constants.py | 4 +- modoboa/pdfcredentials/documents.py | 2 +- modoboa/pdfcredentials/handlers.py | 2 +- modoboa/pdfcredentials/lib.py | 2 +- modoboa/pdfcredentials/views.py | 2 +- modoboa/policyd/core.py | 6 +- modoboa/relaydomains/api/v1/serializers.py | 2 +- modoboa/relaydomains/handlers.py | 2 +- modoboa/relaydomains/lib.py | 2 +- modoboa/relaydomains/transport.py | 2 +- modoboa/transport/backends.py | 2 +- modoboa/transport/models.py | 2 +- requirements.txt | 2 +- 121 files changed, 729 insertions(+), 729 deletions(-) create mode 100644 modoboa/core/migrations/0025_rename_user_email_is_active_core_user_email_c0c03f_idx.py diff --git a/modoboa/admin/api/v1/serializers.py b/modoboa/admin/api/v1/serializers.py index db86de661..545028bdf 100644 --- a/modoboa/admin/api/v1/serializers.py +++ b/modoboa/admin/api/v1/serializers.py @@ -6,8 +6,8 @@ from django.conf import settings from django.contrib.auth import password_validation from django.core.exceptions import ValidationError from django.shortcuts import get_object_or_404 -from django.utils.encoding import force_text -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.encoding import force_str +from django.utils.translation import gettext as _, gettext_lazy from drf_spectacular.types import OpenApiTypes from drf_spectacular.utils import extend_schema_field @@ -31,14 +31,14 @@ class DomainSerializer(serializers.ModelSerializer): quota = serializers.CharField( required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Quota shared between mailboxes. Can be expressed in KB, " "MB (default) or GB. A value of 0 means no quota." ) ) default_mailbox_quota = serializers.CharField( required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Default quota in MB applied to mailboxes. A value of 0 means " "no quota." ) @@ -140,7 +140,7 @@ class DomainAliasSerializer(serializers.ModelSerializer): object_type="domain_aliases") except lib_exceptions.ModoboaException as inst: raise serializers.ValidationError({ - "domain": force_text(inst)}) + "domain": force_str(inst)}) domain_alias.save(creator=creator) return domain_alias @@ -331,7 +331,7 @@ class WritableAccountSerializer(AccountSerializer): object_type="mailboxes") except lib_exceptions.ModoboaException as inst: raise serializers.ValidationError({ - "mailbox": force_text(inst)}) + "mailbox": force_str(inst)}) condition = ( not data.get("random_password") and ( data.get("password") or @@ -447,7 +447,7 @@ class AliasSerializer(serializers.ModelSerializer): recipients = serializers.ListField( child=lib_fields.DRFEmailFieldUTF8AndEmptyUser(), allow_empty=False, - help_text=ugettext_lazy("A list of recipient") + help_text=gettext_lazy("A list of recipient") ) class Meta: diff --git a/modoboa/admin/api/v1/viewsets.py b/modoboa/admin/api/v1/viewsets.py index 2c60701ed..d417253e7 100644 --- a/modoboa/admin/api/v1/viewsets.py +++ b/modoboa/admin/api/v1/viewsets.py @@ -2,7 +2,7 @@ from django import http from django.contrib.contenttypes.models import ContentType -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django_filters import rest_framework as dj_filters from drf_spectacular.utils import extend_schema, extend_schema_view diff --git a/modoboa/admin/api/v2/serializers.py b/modoboa/admin/api/v2/serializers.py index 9e884bbfe..c4f12b446 100644 --- a/modoboa/admin/api/v2/serializers.py +++ b/modoboa/admin/api/v2/serializers.py @@ -8,7 +8,7 @@ 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.utils.translation import gettext as _ from django.contrib.auth import password_validation diff --git a/modoboa/admin/api/v2/tests.py b/modoboa/admin/api/v2/tests.py index 2bf6a510b..fcea7e95b 100644 --- a/modoboa/admin/api/v2/tests.py +++ b/modoboa/admin/api/v2/tests.py @@ -2,7 +2,7 @@ from django.core.files.base import ContentFile from django.urls import reverse -from django.utils.encoding import force_text +from django.utils.encoding import force_str from rest_framework.authtoken.models import Token @@ -165,7 +165,7 @@ domainalias; domalias1.com; domain1.com; True ] self.assertCountEqual( expected_response, - force_text(response.content.strip()).split("\r\n") + force_str(response.content.strip()).split("\r\n") ) @@ -385,7 +385,7 @@ dlist; dlist@test.com; True; user1@test.com; user@extdomain.com def test_export(self): response = self.client.get(reverse("v2:identities-export")) 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_text(response.content.strip()).split("\r\n") + 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] = "" diff --git a/modoboa/admin/api/v2/viewsets.py b/modoboa/admin/api/v2/viewsets.py index 56874a07e..cf473f54a 100644 --- a/modoboa/admin/api/v2/viewsets.py +++ b/modoboa/admin/api/v2/viewsets.py @@ -1,6 +1,6 @@ """Admin API v2 viewsets.""" -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.contrib.contenttypes.models import ContentType diff --git a/modoboa/admin/app_settings.py b/modoboa/admin/app_settings.py index 5bf9543a2..be18a0ab8 100644 --- a/modoboa/admin/app_settings.py +++ b/modoboa/admin/app_settings.py @@ -6,8 +6,8 @@ import os from django import forms from django.conf import settings -from django.utils.encoding import force_text -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.encoding import force_str +from django.utils.translation import gettext as _, gettext_lazy from django.forms.fields import GenericIPAddressField from modoboa.lib.form_utils import SeparatorField, YesNoField @@ -20,20 +20,20 @@ from . import constants class AdminParametersForm(param_forms.AdminParametersForm): app = "admin" - dom_sep = SeparatorField(label=ugettext_lazy("Domains")) + dom_sep = SeparatorField(label=gettext_lazy("Domains")) enable_mx_checks = YesNoField( - label=ugettext_lazy("Enable MX checks"), + label=gettext_lazy("Enable MX checks"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Check that every domain has a valid MX record" ) ) valid_mxs = forms.CharField( - label=ugettext_lazy("Valid MXs"), + label=gettext_lazy("Valid MXs"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "A list of IP or network address every MX record should match." " A warning will be sent if a record does not respect it." ), @@ -42,68 +42,68 @@ class AdminParametersForm(param_forms.AdminParametersForm): ) domains_must_have_authorized_mx = YesNoField( - label=ugettext_lazy("New domains must use authorized MX(s)"), + label=gettext_lazy("New domains must use authorized MX(s)"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Prevent the creation of a new domain if its MX record does " "not use one of the defined addresses." ) ) enable_spf_checks = YesNoField( - label=ugettext_lazy("Enable SPF checks"), + label=gettext_lazy("Enable SPF checks"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Check if every domain has a valid SPF record" ) ) enable_dkim_checks = YesNoField( - label=ugettext_lazy("Enable DKIM checks"), + label=gettext_lazy("Enable DKIM checks"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Check if every domain with DKIM signin enabled has a valid DNS " "record" ) ) enable_dmarc_checks = YesNoField( - label=ugettext_lazy("Enable DMARC checks"), + label=gettext_lazy("Enable DMARC checks"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Check if every domain has a valid DMARC record" ) ) enable_autoconfig_checks = YesNoField( - label=ugettext_lazy("Enable autoconfig checks"), + label=gettext_lazy("Enable autoconfig checks"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Check if every domain has a valid records for autoconfiguration" ) ) enable_dnsbl_checks = YesNoField( - label=ugettext_lazy("Enable DNSBL checks"), + label=gettext_lazy("Enable DNSBL checks"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Check every domain against major DNSBL providers" ) ) custom_dns_server = GenericIPAddressField( - label=ugettext_lazy("Custom DNS server"), + label=gettext_lazy("Custom DNS server"), required=False, initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "Use a custom DNS server instead of local server configuration" ) ) dkim_keys_storage_dir = forms.CharField( - label=ugettext_lazy("DKIM keys storage directory"), + label=gettext_lazy("DKIM keys storage directory"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "Absolute path of the directory where DKIM private keys will " "be stored. Make sure this directory belongs to root user " "and is not readable by the outside world." @@ -112,81 +112,81 @@ class AdminParametersForm(param_forms.AdminParametersForm): ) dkim_default_key_length = forms.ChoiceField( - label=ugettext_lazy("Default DKIM key length"), + label=gettext_lazy("Default DKIM key length"), initial=2048, choices=constants.DKIM_KEY_LENGTHS, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Default length in bits for newly generated DKIM keys." ) ) default_domain_quota = forms.IntegerField( - label=ugettext_lazy("Default domain quota"), + label=gettext_lazy("Default domain quota"), initial=0, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Default quota (in MB) applied to freshly created domains with no " "value specified. A value of 0 means no quota." ) ) default_domain_message_limit = forms.IntegerField( - label=ugettext_lazy("Default domain sending limit"), + label=gettext_lazy("Default domain sending limit"), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Number of messages freshly created domains will be " "allowed to send per day. Leave empty for no limit." ) ) - mbsep = SeparatorField(label=ugettext_lazy("Mailboxes")) + mbsep = SeparatorField(label=gettext_lazy("Mailboxes")) handle_mailboxes = YesNoField( - label=ugettext_lazy("Handle mailboxes on filesystem"), + label=gettext_lazy("Handle mailboxes on filesystem"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Rename or remove mailboxes on the filesystem when they get" " renamed or removed within Modoboa" ) ) default_mailbox_quota = forms.IntegerField( - label=ugettext_lazy("Default mailbox quota"), + label=gettext_lazy("Default mailbox quota"), initial=0, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Default mailbox quota (in MB) applied to freshly created " "mailboxes with no value specified. A value of 0 means no quota." ) ) default_mailbox_message_limit = forms.IntegerField( - label=ugettext_lazy("Default mailbox sending limit"), + label=gettext_lazy("Default mailbox sending limit"), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Number of messages freshly created mailboxes will be " "allowed to send per day. Leave empty for no limit." ) ) auto_account_removal = YesNoField( - label=ugettext_lazy("Automatic account removal"), + label=gettext_lazy("Automatic account removal"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "When a mailbox is removed, also remove the associated account") ) auto_create_domain_and_mailbox = YesNoField( - label=ugettext_lazy("Automatic domain/mailbox creation"), + label=gettext_lazy("Automatic domain/mailbox creation"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Create a domain and a mailbox when an account is automatically " "created." ) ) create_alias_on_mbox_rename = YesNoField( - label=ugettext_lazy("Create an alias when a mailbox is renamed"), + label=gettext_lazy("Create an alias when a mailbox is renamed"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Create an alias using the old address when a mailbox is renamed." ) ) @@ -207,7 +207,7 @@ class AdminParametersForm(param_forms.AdminParametersForm): dpath = None code, output = exec_cmd("which dovecot") if not code: - dpath = force_text(output).strip() + dpath = force_str(output).strip() else: known_paths = getattr( settings, "DOVECOT_LOOKUP_PATH", @@ -222,7 +222,7 @@ class AdminParametersForm(param_forms.AdminParametersForm): except OSError: hide_fields = True else: - version = force_text(version) + version = force_str(version) if code or not version.strip().startswith("2"): hide_fields = True else: @@ -234,7 +234,7 @@ class AdminParametersForm(param_forms.AdminParametersForm): """Ensure quota is a positive integer.""" if self.cleaned_data["default_domain_quota"] < 0: raise forms.ValidationError( - ugettext_lazy("Must be a positive integer") + gettext_lazy("Must be a positive integer") ) return self.cleaned_data["default_domain_quota"] @@ -242,7 +242,7 @@ class AdminParametersForm(param_forms.AdminParametersForm): """Ensure quota is a positive integer.""" if self.cleaned_data["default_mailbox_quota"] < 0: raise forms.ValidationError( - ugettext_lazy("Must be a positive integer") + gettext_lazy("Must be a positive integer") ) return self.cleaned_data["default_mailbox_quota"] @@ -252,12 +252,12 @@ class AdminParametersForm(param_forms.AdminParametersForm): if storage_dir: if not os.path.isdir(storage_dir): raise forms.ValidationError( - ugettext_lazy("Directory not found.") + gettext_lazy("Directory not found.") ) code, output = exec_cmd("which openssl") if code: raise forms.ValidationError( - ugettext_lazy( + gettext_lazy( "openssl not found, please make sure it is installed.") ) return storage_dir @@ -274,7 +274,7 @@ class AdminParametersForm(param_forms.AdminParametersForm): ] except ValueError: raise forms.ValidationError( - ugettext_lazy( + gettext_lazy( "This field only allows valid IP addresses (or networks)" ) ) @@ -297,94 +297,94 @@ class AdminParametersForm(param_forms.AdminParametersForm): GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ ("domains", { - "label": ugettext_lazy("Domains"), + "label": gettext_lazy("Domains"), "params": collections.OrderedDict([ ("enable_mx_checks", { - "label": ugettext_lazy("Enable MX checks"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable MX checks"), + "help_text": gettext_lazy( "Check that every domain has a valid MX record" ) }), ("valid_mxs", { - "label": ugettext_lazy("Valid MXs"), + "label": gettext_lazy("Valid MXs"), "display": "enable_mx_checks=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "A list of IP or network address every MX record should " "match. A warning will be sent if a record does not " "respect it." ), }), ("domains_must_have_authorized_mx", { - "label": ugettext_lazy("New domains must use authorized MX(s)"), + "label": gettext_lazy("New domains must use authorized MX(s)"), "display": "enable_mx_checks=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Prevent the creation of a new domain if its MX record " "does not use one of the defined addresses." ) }), ("enable_spf_checks", { - "label": ugettext_lazy("Enable SPF checks"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable SPF checks"), + "help_text": gettext_lazy( "Check if every domain has a valid SPF record" ) }), ("enable_dkim_checks", { - "label": ugettext_lazy("Enable DKIM checks"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable DKIM checks"), + "help_text": gettext_lazy( "Check if every domain with DKIM signin enabled " "has a valid DNS record" ) }), ("enable_dmarc_checks", { - "label": ugettext_lazy("Enable DMARC checks"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable DMARC checks"), + "help_text": gettext_lazy( "Check if every domain has a valid DMARC record" ) }), ("enable_autoconfig_checks", { - "label": ugettext_lazy("Enable autoconfig checks"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable autoconfig checks"), + "help_text": gettext_lazy( "Check if every domain has a valid records for " "autoconfiguration" ) }), ("enable_dnsbl_checks", { - "label": ugettext_lazy("Enable DNSBL checks"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable DNSBL checks"), + "help_text": gettext_lazy( "Check every domain against major DNSBL providers" ) }), ("custom_dns_server", { - "label": ugettext_lazy("Custom DNS server"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Custom DNS server"), + "help_text": gettext_lazy( "Use a custom DNS server instead of local server " "configuration" ) }), ("dkim_keys_storage_dir", { - "label": ugettext_lazy("DKIM keys storage directory"), - "help_text": ugettext_lazy( + "label": gettext_lazy("DKIM keys storage directory"), + "help_text": gettext_lazy( "Absolute path of the directory where DKIM private keys " "will be stored. Make sure this directory belongs to root " "user and is not readable by the outside world." ), }), ("dkim_default_key_length", { - "label": ugettext_lazy("Default DKIM key length"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default DKIM key length"), + "help_text": gettext_lazy( "Default length in bits for newly generated DKIM keys." ) }), ("default_domain_quota", { - "label": ugettext_lazy("Default domain quota"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default domain quota"), + "help_text": gettext_lazy( "Default quota (in MB) applied to freshly created domains " "with no value specified. A value of 0 means no quota." ) }), ("default_domain_message_limit", { - "label": ugettext_lazy("Default domain sending limit"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default domain sending limit"), + "help_text": gettext_lazy( "Number of messages freshly created domains will be " "allowed to send per day. Leave empty for no limit." ) @@ -392,47 +392,47 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ ]) }), ("mailboxes", { - "label": ugettext_lazy("Mailboxes"), + "label": gettext_lazy("Mailboxes"), "params": collections.OrderedDict([ ("handle_mailboxes", { - "label": ugettext_lazy("Handle mailboxes on filesystem"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Handle mailboxes on filesystem"), + "help_text": gettext_lazy( "Rename or remove mailboxes on the filesystem when they get" " renamed or removed within Modoboa" ) }), ("default_mailbox_quota", { - "label": ugettext_lazy("Default mailbox quota"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default mailbox quota"), + "help_text": gettext_lazy( "Default mailbox quota (in MB) applied to freshly created " "domains with no value specified. A value of 0 means no " "quota." ) }), ("default_mailbox_message_limit", { - "label": ugettext_lazy("Default mailbox sending limit"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default mailbox sending limit"), + "help_text": gettext_lazy( "Number of messages freshly created mailboxes will be " "allowed to send per day. Leave empty for no limit." ) }), ("auto_account_removal", { - "label": ugettext_lazy("Automatic account removal"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Automatic account removal"), + "help_text": gettext_lazy( "When a mailbox is removed, also remove the associated " "account") }), ("auto_create_domain_and_mailbox", { - "label": ugettext_lazy("Automatic domain/mailbox creation"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Automatic domain/mailbox creation"), + "help_text": gettext_lazy( "Create a domain and a mailbox when an account is " "automatically created." ) }), ("create_alias_on_mbox_rename", { - "label": ugettext_lazy( + "label": gettext_lazy( "Create an alias when a mailbox is renamed"), - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Create an alias using the old address when a mailbox is " "renamed." ) @@ -448,8 +448,8 @@ def load_admin_settings(): from .api.v2 import serializers param_tools.registry.add( - "global", AdminParametersForm, ugettext_lazy("Administration")) + "global", AdminParametersForm, gettext_lazy("Administration")) param_tools.registry.add2( - "global", "admin", ugettext_lazy("Administration"), + "global", "admin", gettext_lazy("Administration"), GLOBAL_PARAMETERS_STRUCT, serializers.AdminGlobalParametersSerializer) diff --git a/modoboa/admin/constants.py b/modoboa/admin/constants.py index c1272c052..56924eef3 100644 --- a/modoboa/admin/constants.py +++ b/modoboa/admin/constants.py @@ -1,6 +1,6 @@ """Admin constants.""" -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ DNSBL_PROVIDERS = [ "b.barracudacentral.org", diff --git a/modoboa/admin/forms/account.py b/modoboa/admin/forms/account.py index e406c147b..fac6c1e32 100644 --- a/modoboa/admin/forms/account.py +++ b/modoboa/admin/forms/account.py @@ -8,7 +8,7 @@ from django.conf import settings from django.contrib.auth import password_validation from django.http import QueryDict from django.urls import reverse -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core import signals as core_signals from modoboa.core.models import User @@ -29,34 +29,34 @@ class AccountFormGeneral(forms.ModelForm): """General account form.""" username = forms.CharField( - label=ugettext_lazy("Username"), - help_text=ugettext_lazy( + label=gettext_lazy("Username"), + help_text=gettext_lazy( "The user's name. Must be a valid e-mail address for simple users " "or administrators with a mailbox." ) ) role = forms.ChoiceField( - label=ugettext_lazy("Role"), - choices=[("", ugettext_lazy("Choose"))], - help_text=ugettext_lazy("What level of permission this user will have") + label=gettext_lazy("Role"), + choices=[("", gettext_lazy("Choose"))], + help_text=gettext_lazy("What level of permission this user will have") ) random_password = forms.BooleanField( - label=ugettext_lazy("Random password"), - help_text=ugettext_lazy( + label=gettext_lazy("Random password"), + help_text=gettext_lazy( "Generate a random password. If you're updating this account and " "check this box, a new password will be generated." ), required=False ) password1 = forms.CharField( - label=ugettext_lazy("Password"), widget=forms.widgets.PasswordInput, + label=gettext_lazy("Password"), widget=forms.widgets.PasswordInput, required=False ) password2 = forms.CharField( - label=ugettext_lazy("Confirmation"), + label=gettext_lazy("Confirmation"), widget=forms.widgets.PasswordInput, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Enter the same password as above, for verification." ), required=False @@ -69,7 +69,7 @@ class AccountFormGeneral(forms.ModelForm): "master_user", ) labels = { - "is_active": ugettext_lazy("Enabled") + "is_active": gettext_lazy("Enabled") } def __init__(self, user, *args, **kwargs): @@ -223,14 +223,14 @@ class AccountFormMail(forms.Form, DynamicForm): """Form to handle mail part.""" email = lib_fields.UTF8EmailField( - label=ugettext_lazy("E-mail"), required=False) + label=gettext_lazy("E-mail"), required=False) create_alias_with_old_address = forms.BooleanField( - label=ugettext_lazy("Create an alias using the old address"), + label=gettext_lazy("Create an alias using the old address"), required=False, initial=False ) quota = forms.CharField( - label=ugettext_lazy("Quota"), + label=gettext_lazy("Quota"), required=False, help_text=_( "Quota for this mailbox, can be expressed in KB, MB (default) or " @@ -243,25 +243,25 @@ class AccountFormMail(forms.Form, DynamicForm): ) quota_act = forms.BooleanField(required=False) message_limit = forms.IntegerField( - label=ugettext_lazy("Message sending limit"), + label=gettext_lazy("Message sending limit"), required=False, min_value=0, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Number of messages this mailbox can send per day") ) aliases = lib_fields.UTF8AndEmptyUserEmailField( - label=ugettext_lazy("Alias(es)"), + label=gettext_lazy("Alias(es)"), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Alias(es) of this mailbox. Indicate only one address per input, " "press ENTER to add a new input. To create a catchall alias, just " "enter the domain name (@domain.tld)." ) ) senderaddress = lib_fields.UTF8AndEmptyUserEmailField( - label=ugettext_lazy("Sender addresses"), + label=gettext_lazy("Sender addresses"), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Additional sender address(es) for this account. The user will be " "allowed to send emails using this address, even if it " "does not exist locally. Indicate one address per input. Press " @@ -473,9 +473,9 @@ class AccountPermissionsForm(forms.Form, DynamicForm): """A form to assign domain(s) permission.""" domains = lib_fields.DomainNameField( - label=ugettext_lazy("Domain(s)"), + label=gettext_lazy("Domain(s)"), required=False, - help_text=ugettext_lazy("Domain(s) that user administrates") + help_text=gettext_lazy("Domain(s) that user administrates") ) def __init__(self, *args, **kwargs): diff --git a/modoboa/admin/forms/alias.py b/modoboa/admin/forms/alias.py index 3a5238ac6..86e95b5da 100644 --- a/modoboa/admin/forms/alias.py +++ b/modoboa/admin/forms/alias.py @@ -4,7 +4,7 @@ from collections import OrderedDict from django import forms from django.http import QueryDict -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core import signals as core_signals from modoboa.lib import exceptions as lib_exceptions, fields as lib_fields @@ -17,19 +17,19 @@ class AliasForm(forms.ModelForm, DynamicForm): """A form to create/modify an alias.""" random_address = forms.BooleanField( - label=ugettext_lazy("Random address"), + label=gettext_lazy("Random address"), required=False) address = lib_fields.UTF8AndEmptyUserEmailField( - label=ugettext_lazy("Email address"), - help_text=ugettext_lazy( + label=gettext_lazy("Email address"), + help_text=gettext_lazy( "The alias address. To create a catchall alias, just enter the " "domain name (@domain.tld)." ), widget=forms.TextInput(attrs={"class": "form-control"}) ) recipients = lib_fields.UTF8AndEmptyUserEmailField( - label=ugettext_lazy("Recipients"), required=False, - help_text=ugettext_lazy( + label=gettext_lazy("Recipients"), required=False, + help_text=gettext_lazy( "Addresses this alias will point to. Indicate only one address " "per input, press ENTER to add a new input." ), @@ -40,7 +40,7 @@ class AliasForm(forms.ModelForm, DynamicForm): model = Alias fields = ("address", "domain", "enabled", "expire_at", "description") labels = { - "domain": ugettext_lazy("Domain") + "domain": gettext_lazy("Domain") } widgets = { "domain": forms.widgets.Select( diff --git a/modoboa/admin/forms/domain.py b/modoboa/admin/forms/domain.py index ac915608d..01375d217 100644 --- a/modoboa/admin/forms/domain.py +++ b/modoboa/admin/forms/domain.py @@ -5,8 +5,8 @@ from functools import reduce from django import forms from django.http import QueryDict from django.urls import reverse -from django.utils.encoding import force_text -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.encoding import force_str +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core import signals as core_signals from modoboa.core.models import User @@ -25,30 +25,30 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm): """A form to create/edit a domain.""" type = forms.ChoiceField( # NOQA:A003 - label=ugettext_lazy("Type"), + label=gettext_lazy("Type"), ) aliases = DomainNameField( - label=ugettext_lazy("Alias(es)"), + label=gettext_lazy("Alias(es)"), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Alias(es) of this domain. Indicate only one name per input, " "press ENTER to add a new input." ) ) dkim_key_selector = forms.CharField( - label=ugettext_lazy("Key selector"), initial="modoboa", required=False) + label=gettext_lazy("Key selector"), initial="modoboa", required=False) quota = forms.CharField( - label=ugettext_lazy("Quota"), + label=gettext_lazy("Quota"), initial=0, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Quota shared between mailboxes. Can be expressed in KB, " "MB (default) or GB. A value of 0 means no quota." ) ) default_mailbox_quota = forms.CharField( - label=ugettext_lazy("Default mailbox quota"), + label=gettext_lazy("Default mailbox quota"), initial=0, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Default quota applied to mailboxes. Can be expressed in KB, MB " "(default) or GB. A value of 0 means no quota." ) @@ -97,7 +97,7 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm): name, [(DomainAlias, _("domain alias"))]) if label is not None: raise forms.ValidationError( - _("A %s with this name already exists") % force_text(label)) + _("A %s with this name already exists") % force_str(label)) domains_must_have_authorized_mx = ( param_tools.get_global_parameter("domains_must_have_authorized_mx") @@ -182,7 +182,7 @@ class DomainFormGeneral(forms.ModelForm, DynamicForm): if label is not None: self.add_error( k, _("A %s with this name already exists") - % force_text(label) + % force_str(label) ) else: self.aliases.append(cleaned_data[k]) @@ -227,17 +227,17 @@ class DomainFormOptions(forms.Form): """A form containing options for domain creation.""" create_dom_admin = YesNoField( - label=ugettext_lazy("Create a domain administrator"), + label=gettext_lazy("Create a domain administrator"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Automatically create an administrator for this domain" ) ) dom_admin_username = forms.CharField( - label=ugettext_lazy("Name"), + label=gettext_lazy("Name"), initial="admin", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The administrator's name. Don't include the domain's name here, " "it will be automatically appended." ), @@ -245,27 +245,27 @@ class DomainFormOptions(forms.Form): ) random_password = YesNoField( - label=ugettext_lazy("Random password"), + label=gettext_lazy("Random password"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Generate a random password for the administrator." ), required=False ) with_mailbox = YesNoField( - label=ugettext_lazy("With a mailbox"), + label=gettext_lazy("With a mailbox"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Create a mailbox for the administrator." ), required=False ) create_aliases = YesNoField( - label=ugettext_lazy("Create aliases"), + label=gettext_lazy("Create aliases"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Automatically create standard aliases for this domain" ), required=False diff --git a/modoboa/admin/forms/export.py b/modoboa/admin/forms/export.py index 234bbd9d4..786a726e4 100644 --- a/modoboa/admin/forms/export.py +++ b/modoboa/admin/forms/export.py @@ -1,12 +1,12 @@ """Export related forms.""" from django import forms -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy class ExportDataForm(forms.Form): sepchar = forms.CharField( - label=ugettext_lazy("Separator"), + label=gettext_lazy("Separator"), max_length=1, required=False, widget=forms.TextInput(attrs={"class": "form-control"}) diff --git a/modoboa/admin/forms/forward.py b/modoboa/admin/forms/forward.py index 5cd7b1b7c..8308d2f2a 100644 --- a/modoboa/admin/forms/forward.py +++ b/modoboa/admin/forms/forward.py @@ -2,23 +2,23 @@ from django import forms from django.core import validators -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy class ForwardForm(forms.Form): """Forward definition form.""" dest = forms.CharField( - label=ugettext_lazy("Recipient(s)"), + label=gettext_lazy("Recipient(s)"), widget=forms.Textarea(attrs={"class": "form-control"}), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Indicate one or more recipients separated by a ','") ) keepcopies = forms.BooleanField( - label=ugettext_lazy("Keep local copies"), + label=gettext_lazy("Keep local copies"), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Forward messages and store copies into your local mailbox") ) diff --git a/modoboa/admin/forms/import_.py b/modoboa/admin/forms/import_.py index e598658e7..acdb1f3fb 100644 --- a/modoboa/admin/forms/import_.py +++ b/modoboa/admin/forms/import_.py @@ -1,23 +1,23 @@ """Forms related to import operations.""" from django import forms -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy class ImportDataForm(forms.Form): """Base form to import objects.""" - sourcefile = forms.FileField(label=ugettext_lazy("Select a file")) + sourcefile = forms.FileField(label=gettext_lazy("Select a file")) sepchar = forms.CharField( - label=ugettext_lazy("Separator"), + label=gettext_lazy("Separator"), max_length=1, required=False, widget=forms.TextInput(attrs={"class": "form-control"}) ) continue_if_exists = forms.BooleanField( - label=ugettext_lazy("Continue on error"), required=False, - help_text=ugettext_lazy("Don't treat duplicated objects as error") + label=gettext_lazy("Continue on error"), required=False, + help_text=gettext_lazy("Don't treat duplicated objects as error") ) def __init__(self, *args, **kwargs): @@ -35,8 +35,8 @@ class ImportIdentitiesForm(ImportDataForm): """A form to import identities.""" crypt_password = forms.BooleanField( - label=ugettext_lazy("Crypt passwords"), required=False, - help_text=ugettext_lazy( + label=gettext_lazy("Crypt passwords"), required=False, + help_text=gettext_lazy( "Check this option if passwords contained in your file " "are not crypted" ) diff --git a/modoboa/admin/handlers.py b/modoboa/admin/handlers.py index 0b3bef1ab..d7bfc1361 100644 --- a/modoboa/admin/handlers.py +++ b/modoboa/admin/handlers.py @@ -4,7 +4,7 @@ from django.contrib.contenttypes.models import ContentType from django.db.models import signals from django.dispatch import receiver from django.urls import reverse -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import models as core_models, signals as core_signals from modoboa.lib import exceptions, permissions, signals as lib_signals diff --git a/modoboa/admin/lib.py b/modoboa/admin/lib.py index 80fbaee0a..e88f55b45 100644 --- a/modoboa/admin/lib.py +++ b/modoboa/admin/lib.py @@ -15,8 +15,8 @@ from dns.name import IDNA_2008_UTS_46 from django.core.exceptions import ValidationError from django.db import transaction from django.db.models import Q -from django.utils.encoding import smart_text -from django.utils.translation import ugettext as _ +from django.utils.encoding import smart_str +from django.utils.translation import gettext as _ from django.contrib.auth import password_validation from django.contrib.contenttypes.models import ContentType @@ -232,14 +232,14 @@ def get_domain_mx_list(domain): continue for ip_answer in ip_answers: try: - address_smart = smart_text(ip_answer.address) + address_smart = smart_str(ip_answer.address) mx_ip = ipaddress.ip_address(address_smart) except ValueError as e: logger.warning( _("Invalid IP address format for " "{domain}; {addr}").format( domain=mx_domain, - addr=smart_text(ip_answer.address) + addr=smart_str(ip_answer.address) ), exc_info=e) else: result.append((mx_domain, mx_ip)) @@ -249,7 +249,7 @@ def get_domain_mx_list(domain): def domain_has_authorized_mx(name): """Check if domain has authorized mx record at least.""" valid_mxs = param_tools.get_global_parameter("valid_mxs") - valid_mxs = [ipaddress.ip_network(smart_text(v.strip())) + valid_mxs = [ipaddress.ip_network(smart_str(v.strip())) for v in valid_mxs.split() if v.strip()] domain_mxs = get_domain_mx_list(name) for _mx_addr, mx_ip_addr in domain_mxs: diff --git a/modoboa/admin/management/commands/subcommands/_export.py b/modoboa/admin/management/commands/subcommands/_export.py index 050eda391..694035adb 100644 --- a/modoboa/admin/management/commands/subcommands/_export.py +++ b/modoboa/admin/management/commands/subcommands/_export.py @@ -3,7 +3,7 @@ import csv from django.core.management.base import BaseCommand -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from modoboa.core.extensions import exts_pool from modoboa.core.models import User @@ -56,5 +56,5 @@ class ExportCommand(BaseCommand): def handle(self, *args, **options): exts_pool.load_all() self.csvwriter = csv.writer( - self.stdout, delimiter=smart_text(options["sepchar"])) + self.stdout, delimiter=smart_str(options["sepchar"])) getattr(self, "export_{}".format(options["objtype"]))() diff --git a/modoboa/admin/management/commands/subcommands/_import.py b/modoboa/admin/management/commands/subcommands/_import.py index d4b7054db..8e3562a97 100644 --- a/modoboa/admin/management/commands/subcommands/_import.py +++ b/modoboa/admin/management/commands/subcommands/_import.py @@ -9,7 +9,7 @@ from chardet.universaldetector import UniversalDetector from django.core.management.base import BaseCommand, CommandError from django.db import transaction -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import models as core_models from modoboa.core.extensions import exts_pool diff --git a/modoboa/admin/management/commands/subcommands/_manage_dkim_keys.py b/modoboa/admin/management/commands/subcommands/_manage_dkim_keys.py index 1d125ed43..d3ccdda67 100644 --- a/modoboa/admin/management/commands/subcommands/_manage_dkim_keys.py +++ b/modoboa/admin/management/commands/subcommands/_manage_dkim_keys.py @@ -3,8 +3,8 @@ import os from django.core.management.base import BaseCommand -from django.utils.encoding import smart_text -from django.utils.translation import ugettext as _ +from django.utils.encoding import smart_str +from django.utils.translation import gettext as _ from modoboa.lib import sysutils from modoboa.parameters import tools as param_tools @@ -41,15 +41,15 @@ class ManageDKIMKeys(BaseCommand): "openssl genrsa -out {} {}".format(pkey_path, key_size)) if code: print("Failed to generate DKIM private key for domain {}: {}" - .format(domain.name, smart_text(output))) + .format(domain.name, smart_str(output))) domain.dkim_private_key_path = pkey_path code, output = sysutils.exec_cmd( "openssl rsa -in {} -pubout".format(pkey_path)) if code: print("Failed to generate DKIM public key for domain {}: {}" - .format(domain.name, smart_text(output))) + .format(domain.name, smart_str(output))) public_key = "" - for cpt, line in enumerate(smart_text(output).splitlines()): + for cpt, line in enumerate(smart_str(output).splitlines()): if cpt == 0 or line.startswith("-----"): continue public_key += line diff --git a/modoboa/admin/management/commands/subcommands/_mx.py b/modoboa/admin/management/commands/subcommands/_mx.py index d1ea6abee..41fd9a349 100644 --- a/modoboa/admin/management/commands/subcommands/_mx.py +++ b/modoboa/admin/management/commands/subcommands/_mx.py @@ -10,9 +10,9 @@ from django.core.mail import EmailMessage from django.core.management.base import BaseCommand from django.template.loader import render_to_string from django.utils import timezone -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from django.utils.functional import cached_property -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import constants, models from modoboa.dnstools import models as dns_models @@ -40,7 +40,7 @@ class CheckMXRecords(BaseCommand): def valid_mxs(self): """Return valid MXs set in admin.""" valid_mxs = param_tools.get_global_parameter("valid_mxs") - return [ipaddress.ip_network(smart_text(v.strip())) + return [ipaddress.ip_network(smart_str(v.strip())) for v in valid_mxs.split() if v.strip()] def add_arguments(self, parser): @@ -70,7 +70,7 @@ class CheckMXRecords(BaseCommand): results = {} for ip, mxs in mx_list.items(): try: - ip = ipaddress.ip_address(smart_text(ip)) + ip = ipaddress.ip_address(smart_str(ip)) except ValueError: continue else: diff --git a/modoboa/admin/models/alias.py b/modoboa/admin/models/alias.py index b24b89de5..312f52020 100644 --- a/modoboa/admin/models/alias.py +++ b/modoboa/admin/models/alias.py @@ -7,9 +7,9 @@ from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse from django.utils.encoding import ( - force_bytes, force_str, smart_text + force_bytes, force_str, smart_str ) -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from reversion import revisions as reversion @@ -68,22 +68,22 @@ class Alias(AdminObject): """Mailbox alias.""" address = models.CharField( - ugettext_lazy("address"), max_length=254, - help_text=ugettext_lazy( + gettext_lazy("address"), max_length=254, + help_text=gettext_lazy( "The alias address." ) ) domain = models.ForeignKey(Domain, null=True, on_delete=models.CASCADE) enabled = models.BooleanField( - ugettext_lazy("enabled"), - help_text=ugettext_lazy("Check to activate this alias"), + gettext_lazy("enabled"), + help_text=gettext_lazy("Check to activate this alias"), default=True ) internal = models.BooleanField(default=False) description = models.TextField( - ugettext_lazy("Description"), blank=True) + gettext_lazy("Description"), blank=True) expire_at = models.DateTimeField( - ugettext_lazy("Expire at"), blank=True, null=True) + gettext_lazy("Expire at"), blank=True, null=True) _objectname = "MailboxAlias" objects = AliasManager() @@ -258,6 +258,6 @@ class AliasRecipient(models.Model): def __str__(self): """Return alias and recipient.""" - return smart_text( + return smart_str( "{} -> {}".format(self.alias.address, self.address) ) diff --git a/modoboa/admin/models/domain.py b/modoboa/admin/models/domain.py index 8b8fc0a1b..dd997b9a6 100644 --- a/modoboa/admin/models/domain.py +++ b/modoboa/admin/models/domain.py @@ -6,9 +6,9 @@ from reversion import revisions as reversion from django.db import models from django.utils import timezone -from django.utils.encoding import force_text, smart_text +from django.utils.encoding import force_str, smart_str from django.utils.functional import cached_property -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core import signals as core_signals from modoboa.core.models import User @@ -23,46 +23,46 @@ from . import mixins class Domain(mixins.MessageLimitMixin, AdminObject): """Mail domain.""" - name = models.CharField(ugettext_lazy("name"), max_length=253, unique=True, - help_text=ugettext_lazy("The domain name")) + name = models.CharField(gettext_lazy("name"), max_length=253, unique=True, + help_text=gettext_lazy("The domain name")) quota = models.PositiveIntegerField( default=0, ) default_mailbox_quota = models.PositiveIntegerField( - verbose_name=ugettext_lazy("Default mailbox quota"), + verbose_name=gettext_lazy("Default mailbox quota"), default=0 ) message_limit = models.PositiveIntegerField( - ugettext_lazy("Message sending limit"), + gettext_lazy("Message sending limit"), null=True, blank=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Number of messages this domain can send per day" ) ) enabled = models.BooleanField( - ugettext_lazy("enabled"), - help_text=ugettext_lazy("Check to activate this domain"), + gettext_lazy("enabled"), + help_text=gettext_lazy("Check to activate this domain"), default=True ) type = models.CharField(default="domain", max_length=20) # NOQA:A003 enable_dns_checks = models.BooleanField( - ugettext_lazy("Enable DNS checks"), default=True, - help_text=ugettext_lazy("Check to enable DNS checks for this domain") + gettext_lazy("Enable DNS checks"), default=True, + help_text=gettext_lazy("Check to enable DNS checks for this domain") ) transport = models.OneToOneField( "transport.Transport", null=True, on_delete=models.SET_NULL) enable_dkim = models.BooleanField( - ugettext_lazy("Enable DKIM signing"), - help_text=ugettext_lazy( + gettext_lazy("Enable DKIM signing"), + help_text=gettext_lazy( "If you activate this feature, a DKIM key will be " "generated for this domain."), default=False ) dkim_key_selector = models.CharField(max_length=30, default="modoboa") dkim_key_length = models.PositiveIntegerField( - ugettext_lazy("Key length"), choices=constants.DKIM_KEY_LENGTHS, + gettext_lazy("Key length"), choices=constants.DKIM_KEY_LENGTHS, blank=True, null=True ) dkim_public_key = models.TextField(blank=True) @@ -339,7 +339,7 @@ class Domain(mixins.MessageLimitMixin, AdminObject): super().delete() def __str__(self): - return smart_text(self.name) + return smart_str(self.name) def from_csv(self, user, row): """Create a new domain from a CSV entry. @@ -397,7 +397,7 @@ class Domain(mixins.MessageLimitMixin, AdminObject): result = [ [ "domain", - force_text(self.name), + force_str(self.name), self.quota, self.default_mailbox_quota, self.enabled diff --git a/modoboa/admin/models/domain_alias.py b/modoboa/admin/models/domain_alias.py index 2bdd95c51..c312f34ec 100644 --- a/modoboa/admin/models/domain_alias.py +++ b/modoboa/admin/models/domain_alias.py @@ -4,8 +4,8 @@ from reversion import revisions as reversion from django.contrib.contenttypes.fields import GenericRelation from django.db import models -from django.utils.encoding import smart_text -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.encoding import smart_str +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core import models as core_models, signals as core_signals from modoboa.lib.exceptions import BadRequest, Conflict @@ -30,16 +30,16 @@ class DomainAlias(AdminObject): """Domain aliases.""" - name = models.CharField(ugettext_lazy("name"), max_length=100, unique=True, - help_text=ugettext_lazy("The alias name")) + name = models.CharField(gettext_lazy("name"), max_length=100, unique=True, + help_text=gettext_lazy("The alias name")) target = models.ForeignKey( - Domain, verbose_name=ugettext_lazy("target"), - help_text=ugettext_lazy("The domain this alias points to"), + Domain, verbose_name=gettext_lazy("target"), + help_text=gettext_lazy("The domain this alias points to"), on_delete=models.CASCADE ) enabled = models.BooleanField( - ugettext_lazy("enabled"), - help_text=ugettext_lazy("Check to activate this alias"), + gettext_lazy("enabled"), + help_text=gettext_lazy("Check to activate this alias"), default=True ) @@ -51,7 +51,7 @@ class DomainAlias(AdminObject): app_label = "admin" def __str__(self): - return smart_text(self.name) + return smart_str(self.name) def from_csv(self, user, row): """Create a domain alias from a CSV row diff --git a/modoboa/admin/models/mailbox.py b/modoboa/admin/models/mailbox.py index 4f0021429..fd2612ab1 100644 --- a/modoboa/admin/models/mailbox.py +++ b/modoboa/admin/models/mailbox.py @@ -6,8 +6,8 @@ from django.contrib.contenttypes.models import ContentType from django.db import models from django.db.models import Q from django.db.models.manager import Manager -from django.utils.encoding import smart_text, force_text -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.encoding import smart_str, force_str +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core.models import User from modoboa.lib import exceptions as lib_exceptions @@ -89,15 +89,15 @@ class Mailbox(mixins.MessageLimitMixin, AdminObject): """User mailbox.""" address = models.CharField( - ugettext_lazy("address"), max_length=252, - help_text=ugettext_lazy( + gettext_lazy("address"), max_length=252, + help_text=gettext_lazy( "Mailbox address (without the @domain.tld part)") ) quota = models.PositiveIntegerField(default=0) use_domain_quota = models.BooleanField(default=False) message_limit = models.PositiveIntegerField( - ugettext_lazy("Message sending limit"), null=True, blank=True, - help_text=ugettext_lazy( + gettext_lazy("Message sending limit"), null=True, blank=True, + help_text=gettext_lazy( "Number of messages this mailbox can send per day") ) domain = models.ForeignKey(Domain, on_delete=models.CASCADE) @@ -115,7 +115,7 @@ class Mailbox(mixins.MessageLimitMixin, AdminObject): self.old_message_limit = self.message_limit def __str__(self): - return smart_text(self.full_address) + return smart_str(self.full_address) def __full_address(self, localpart): return "%s@%s" % (localpart, self.domain.name) @@ -154,7 +154,7 @@ class Mailbox(mixins.MessageLimitMixin, AdminObject): if code: raise lib_exceptions.InternalError( _("Failed to retrieve mailbox location (%s)") % output) - self.__mail_home = force_text(output.strip()) + self.__mail_home = force_str(output.strip()) return self.__mail_home @property @@ -363,7 +363,7 @@ class SenderAddress(models.Model): def __str__(self): """Return address.""" - return smart_text(self.address) + return smart_str(self.address) reversion.register(SenderAddress) diff --git a/modoboa/admin/signals.py b/modoboa/admin/signals.py index 9610ec7bd..756ddb9c8 100644 --- a/modoboa/admin/signals.py +++ b/modoboa/admin/signals.py @@ -2,31 +2,22 @@ import django.dispatch -check_extra_account_form = django.dispatch.Signal( - providing_args=["account", "form"]) -extra_account_dashboard_widgets = django.dispatch.Signal( - providing_args=["user", "account"]) -extra_account_forms = django.dispatch.Signal( - providing_args=["user", "account"]) -extra_admin_content = django.dispatch.Signal( - providing_args=["user", "location", "currentpage"]) -extra_domain_actions = django.dispatch.Signal( - providing_args=["user", "domain"]) -extra_domain_dashboard_widgets = django.dispatch.Signal( - providing_args=["user", "domain"]) +check_extra_account_form = django.dispatch.Signal() # Provides account, form +extra_account_dashboard_widgets = django.dispatch.Signal() # Provides user, account +extra_account_forms = django.dispatch.Signal() # Provides user, account +extra_admin_content = django.dispatch.Signal() # Provides user, location, currentpage +extra_domain_actions = django.dispatch.Signal() # Provides user, domain +extra_domain_dashboard_widgets = django.dispatch.Signal() # Provides user, domain extra_domain_filters = django.dispatch.Signal() -extra_domain_forms = django.dispatch.Signal(providing_args=["user", "domain"]) -extra_domain_menu_entries = django.dispatch.Signal(providing_args=["user"]) -extra_domain_qset_filters = django.dispatch.Signal( - providing_args=["domfilter", "extrafilters"]) +extra_domain_forms = django.dispatch.Signal() # Provides user, domain +extra_domain_menu_entries = django.dispatch.Signal() # Provides user +extra_domain_qset_filters = django.dispatch.Signal() # Provides domfilter, extrafilters # extra_domain_types = django.dispatch.Signal() extra_domain_wizard_steps = django.dispatch.Signal() -get_account_form_instances = django.dispatch.Signal( - providing_args=["user", "account"]) -get_domain_form_instances = django.dispatch.Signal( - providing_args=["user", "domain"]) +get_account_form_instances = django.dispatch.Signal() # Provides user, account +get_domain_form_instances = django.dispatch.Signal() # Provides user, domain # get_domain_tags = django.dispatch.Signal(providing_args=["domain"]) -import_object = django.dispatch.Signal(providing_args=["objtype"]) -use_external_recipients = django.dispatch.Signal(providing_args=["recipients"]) -new_dkim_keys = django.dispatch.Signal(providing_args=["domains"]) -extra_account_identities_actions = django.dispatch.Signal(providing_args=["account"]) \ No newline at end of file +import_object = django.dispatch.Signal() # Provides objtype +use_external_recipients = django.dispatch.Signal() # Provides recipients +new_dkim_keys = django.dispatch.Signal() # Provides domain +extra_account_identities_actions = django.dispatch.Signal() # Provides account diff --git a/modoboa/admin/templatetags/admin_tags.py b/modoboa/admin/templatetags/admin_tags.py index c6e93bf44..1e7e74bb8 100644 --- a/modoboa/admin/templatetags/admin_tags.py +++ b/modoboa/admin/templatetags/admin_tags.py @@ -6,7 +6,7 @@ from django import template from django.template.loader import render_to_string from django.urls import reverse from django.utils.safestring import mark_safe -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core import signals as core_signals from modoboa.lib.templatetags.lib_tags import render_link @@ -16,7 +16,7 @@ from .. import signals register = template.Library() genders = { - "Enabled": (ugettext_lazy("enabled_m"), ugettext_lazy("enabled_f")) + "Enabled": (gettext_lazy("enabled_m"), gettext_lazy("enabled_f")) } diff --git a/modoboa/admin/tests/test_export.py b/modoboa/admin/tests/test_export.py index 2ff43176b..9317dd7ad 100644 --- a/modoboa/admin/tests/test_export.py +++ b/modoboa/admin/tests/test_export.py @@ -5,7 +5,7 @@ from io import StringIO from django.core.management import call_command from django.urls import reverse -from django.utils.encoding import force_text +from django.utils.encoding import force_str from modoboa.lib.tests import ModoTestCase from .. import factories, models @@ -50,7 +50,7 @@ class ExportTestCase(ModoTestCase): ] self.assertCountEqual( expected_response, - force_text(response.content.strip()).split("\r\n") + force_str(response.content.strip()).split("\r\n") ) # Test management command too. @@ -59,12 +59,12 @@ class ExportTestCase(ModoTestCase): response = sys.stdout.getvalue() sys.stdout = stdout_backup self.assertCountEqual( - expected_response, force_text(response.strip()).split("\r\n")) + 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_text(response.content.strip()).split("\r\n") + 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] = "" @@ -86,7 +86,7 @@ class ExportTestCase(ModoTestCase): 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_text(response.content.strip()).split("\r\n") + force_str(response.content.strip()).split("\r\n") ) def test_export_superadmins(self): @@ -111,7 +111,7 @@ class ExportTestCase(ModoTestCase): 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_text(response.content.strip()).split("\r\n") + force_str(response.content.strip()).split("\r\n") ) def test_export_aliases(self): diff --git a/modoboa/admin/tests/test_mx.py b/modoboa/admin/tests/test_mx.py index 8505d3666..c15f5ef95 100644 --- a/modoboa/admin/tests/test_mx.py +++ b/modoboa/admin/tests/test_mx.py @@ -8,7 +8,7 @@ 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 ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import factories as core_factories from modoboa.lib.tests import ModoTestCase @@ -221,7 +221,7 @@ class DNSBLTestCase(ModoTestCase): management.call_command( "modo", "check_mx", "--email", "user@example.test") self.assertEqual(len(mail.outbox), 2) - + @mock.patch("gevent.socket.gethostbyname") @mock.patch("socket.getaddrinfo") @mock.patch.object(dns.resolver.Resolver, "resolve") diff --git a/modoboa/admin/views/alias.py b/modoboa/admin/views/alias.py index 3271cc48e..b22132dca 100644 --- a/modoboa/admin/views/alias.py +++ b/modoboa/admin/views/alias.py @@ -7,7 +7,7 @@ from django.contrib.auth.decorators import login_required, permission_required from django.db import IntegrityError from django.shortcuts import render from django.urls import reverse -from django.utils.translation import ugettext as _, ungettext +from django.utils.translation import gettext as _, ngettext from django.views import generic from django.views.decorators.http import require_http_methods @@ -102,7 +102,7 @@ def delalias(request): if not request.user.can_access(alias): raise PermDeniedException alias.delete() - msg = ungettext("Alias deleted", "Aliases deleted", len(selection)) + msg = ngettext("Alias deleted", "Aliases deleted", len(selection)) return render_to_json_response(msg) diff --git a/modoboa/admin/views/dns.py b/modoboa/admin/views/dns.py index 42d1738de..3a46b84c5 100644 --- a/modoboa/admin/views/dns.py +++ b/modoboa/admin/views/dns.py @@ -1,7 +1,7 @@ """DNSBL related views.""" from django.contrib.auth import mixins as auth_mixins -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.views import generic from .. import models diff --git a/modoboa/admin/views/domain.py b/modoboa/admin/views/domain.py index 6797f04e3..83c1218e9 100644 --- a/modoboa/admin/views/domain.py +++ b/modoboa/admin/views/domain.py @@ -13,7 +13,7 @@ from django.http import HttpResponseRedirect from django.shortcuts import render from django.template.loader import render_to_string from django.urls import reverse -from django.utils.translation import ugettext as _, ungettext +from django.utils.translation import gettext as _, ngettext from django.views import generic from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods @@ -247,7 +247,7 @@ def deldomain(request, dom_id): raise PermDeniedException(_("You can't delete your own domain")) dom.delete(request.user, keepdir) - msg = ungettext("Domain deleted", "Domains deleted", 1) + msg = ngettext("Domain deleted", "Domains deleted", 1) return render_to_json_response(msg) diff --git a/modoboa/admin/views/export.py b/modoboa/admin/views/export.py index 183206f2a..b395a1865 100644 --- a/modoboa/admin/views/export.py +++ b/modoboa/admin/views/export.py @@ -9,7 +9,7 @@ from django.contrib.auth.decorators import ( from django.http import HttpResponse from django.shortcuts import render from django.urls import reverse -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from ..forms import ExportDataForm from ..lib import get_domains, get_identities diff --git a/modoboa/admin/views/identity.py b/modoboa/admin/views/identity.py index f2b8ab869..2d9ea3786 100644 --- a/modoboa/admin/views/identity.py +++ b/modoboa/admin/views/identity.py @@ -8,7 +8,7 @@ from django.contrib.auth.decorators import ( ) from django.shortcuts import render from django.template.loader import render_to_string -from django.utils.translation import ugettext as _, ungettext +from django.utils.translation import gettext as _, ngettext from django.views import generic from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.http import require_http_methods @@ -191,7 +191,7 @@ def editaccount(request, pk): def delaccount(request, pk): User.objects.get(pk=pk).delete() return render_to_json_response( - ungettext("Account deleted", "Accounts deleted", 1) + ngettext("Account deleted", "Accounts deleted", 1) ) diff --git a/modoboa/admin/views/import_.py b/modoboa/admin/views/import_.py index ed5f883a8..575eb3be1 100644 --- a/modoboa/admin/views/import_.py +++ b/modoboa/admin/views/import_.py @@ -11,8 +11,8 @@ from django.contrib.auth.decorators import ( from django.db import transaction from django.shortcuts import render from django.urls import reverse -from django.utils.encoding import smart_text -from django.utils.translation import ugettext as _ +from django.utils.encoding import smart_str +from django.utils.translation import gettext as _ from modoboa.lib.exceptions import Conflict, ModoboaException from .. import lib diff --git a/modoboa/admin/views/user.py b/modoboa/admin/views/user.py index 8edc6fa09..f21de52c7 100644 --- a/modoboa/admin/views/user.py +++ b/modoboa/admin/views/user.py @@ -4,7 +4,7 @@ from reversion import revisions as reversion from django.contrib.auth.decorators import login_required from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.lib.web_utils import render_to_json_response from ..forms import ForwardForm diff --git a/modoboa/core/api/v1/serializers.py b/modoboa/core/api/v1/serializers.py index 0e0256857..39e9ff6e1 100644 --- a/modoboa/core/api/v1/serializers.py +++ b/modoboa/core/api/v1/serializers.py @@ -1,6 +1,6 @@ """Core API serializers.""" -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from rest_framework import serializers diff --git a/modoboa/core/api/v1/viewsets.py b/modoboa/core/api/v1/viewsets.py index 7c4bf11f1..31a44fa25 100644 --- a/modoboa/core/api/v1/viewsets.py +++ b/modoboa/core/api/v1/viewsets.py @@ -1,6 +1,6 @@ """Core API viewsets.""" -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ import django_otp from django_otp.plugins.otp_static.models import StaticDevice, StaticToken diff --git a/modoboa/core/api/v2/serializers.py b/modoboa/core/api/v2/serializers.py index f766fd6ce..56cf3866d 100644 --- a/modoboa/core/api/v2/serializers.py +++ b/modoboa/core/api/v2/serializers.py @@ -13,10 +13,10 @@ from django.core.exceptions import ValidationError as djangoValidationError from django.template import loader from django.utils import formats -from django.utils.encoding import force_text +from django.utils.encoding import force_str from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.encoding import force_bytes -from django.utils.translation import ugettext_lazy, ugettext as _ +from django.utils.translation import gettext_lazy, gettext as _ from rest_framework import serializers, status from rest_framework.exceptions import APIException @@ -36,7 +36,7 @@ class CustomValidationError(APIException): if detail is not None: self.detail = detail else: - self.detail = {'detail': force_text(self.default_detail)} + self.detail = {'detail': force_str(self.default_detail)} class NoSMSAvailable(Exception): @@ -57,7 +57,7 @@ class CoreGlobalParametersSerializer(serializers.Serializer): # General settings authentication_type = serializers.ChoiceField( - choices=[("local", ugettext_lazy("Local")), + choices=[("local", gettext_lazy("Local")), ("ldap", "LDAP")], default="local" ) @@ -65,11 +65,11 @@ class CoreGlobalParametersSerializer(serializers.Serializer): choices=[("sha512crypt", "sha512crypt"), ("sha256crypt", "sha256crypt"), ("blfcrypt", "bcrypt"), - ("md5crypt", ugettext_lazy("md5crypt (weak)")), - ("sha256", ugettext_lazy("sha256 (weak)")), - ("md5", ugettext_lazy("md5 (weak)")), - ("crypt", ugettext_lazy("crypt (weak)")), - ("plain", ugettext_lazy("plain (weak)"))], + ("md5crypt", gettext_lazy("md5crypt (weak)")), + ("sha256", gettext_lazy("sha256 (weak)")), + ("md5", gettext_lazy("md5 (weak)")), + ("crypt", gettext_lazy("crypt (weak)")), + ("plain", gettext_lazy("plain (weak)"))], default="sha512crypt" ) rounds_number = serializers.IntegerField(default=70000) diff --git a/modoboa/core/api/v2/views.py b/modoboa/core/api/v2/views.py index 32e07c503..4f69225dc 100644 --- a/modoboa/core/api/v2/views.py +++ b/modoboa/core/api/v2/views.py @@ -3,7 +3,7 @@ import logging from django.utils.html import escape -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.utils.datastructures import MultiValueDictKeyError from django.contrib.auth import login diff --git a/modoboa/core/app_settings.py b/modoboa/core/app_settings.py index 46e83ee7d..ad817c961 100644 --- a/modoboa/core/app_settings.py +++ b/modoboa/core/app_settings.py @@ -5,7 +5,7 @@ import collections from django import forms from django.conf import settings from django.contrib.auth import password_validation -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from modoboa.core.password_hashers import get_dovecot_schemes from modoboa.core.password_hashers.base import PasswordHasher @@ -36,61 +36,61 @@ class GeneralParametersForm(param_forms.AdminParametersForm): app = "core" - sep1 = SeparatorField(label=ugettext_lazy("Authentication")) + sep1 = SeparatorField(label=gettext_lazy("Authentication")) authentication_type = forms.ChoiceField( - label=ugettext_lazy("Authentication type"), - choices=[("local", ugettext_lazy("Local")), + label=gettext_lazy("Authentication type"), + choices=[("local", gettext_lazy("Local")), ("ldap", "LDAP")], initial="local", - help_text=ugettext_lazy("The backend used for authentication"), + help_text=gettext_lazy("The backend used for authentication"), widget=HorizontalRadioSelect() ) password_scheme = forms.ChoiceField( - label=ugettext_lazy("Default password scheme"), + label=gettext_lazy("Default password scheme"), choices=[], initial="sha512crypt", - help_text=ugettext_lazy("Scheme used to crypt mailbox passwords"), + help_text=gettext_lazy("Scheme used to crypt mailbox passwords"), ) rounds_number = forms.IntegerField( - label=ugettext_lazy("Rounds"), + label=gettext_lazy("Rounds"), initial=70000, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Number of rounds to use (only used by sha256crypt and " "sha512crypt). Must be between 1000 and 999999999, inclusive." ), ) update_scheme = YesNoField( - label=ugettext_lazy("Update password scheme at login"), + label=gettext_lazy("Update password scheme at login"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Update user password at login to use the default password scheme" ) ) default_password = forms.CharField( - label=ugettext_lazy("Default password"), + label=gettext_lazy("Default password"), initial="password", - help_text=ugettext_lazy( + help_text=gettext_lazy( "Default password for automatically created accounts.") ) random_password_length = forms.IntegerField( - label=ugettext_lazy("Random password length"), + label=gettext_lazy("Random password length"), min_value=8, initial=8, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Length of randomly generated passwords.") ) update_password_url = forms.URLField( - label=ugettext_lazy("Update password service URL"), + label=gettext_lazy("Update password service URL"), initial="", required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "The URL of an external page where users will be able" " to update their password. It applies only to non local" " users, ie. those automatically created after a successful" @@ -99,92 +99,92 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) password_recovery_msg = forms.CharField( - label=ugettext_lazy("Password recovery announcement"), + label=gettext_lazy("Password recovery announcement"), initial="", required=False, widget=forms.widgets.Textarea(), - help_text=ugettext_lazy( + help_text=gettext_lazy( "A temporary message that will be displayed on the " "reset password page." ) ) sms_password_recovery = YesNoField( - label=ugettext_lazy("Enable password recovery by SMS"), + label=gettext_lazy("Enable password recovery by SMS"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Enable password recovery by SMS for users who filled " "a phone number." ) ) sms_provider = forms.ChoiceField( - label=ugettext_lazy("SMS provider"), + label=gettext_lazy("SMS provider"), choices=constants.SMS_BACKENDS, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Choose a provider to send password recovery SMS" ), required=False ) # LDAP specific settings - ldap_sep = SeparatorField(label=ugettext_lazy("LDAP settings")) + ldap_sep = SeparatorField(label=gettext_lazy("LDAP settings")) ldap_server_address = forms.CharField( - label=ugettext_lazy("Server address"), + label=gettext_lazy("Server address"), initial="localhost", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The IP address or the DNS name of the LDAP server"), ) ldap_server_port = forms.IntegerField( - label=ugettext_lazy("Server port"), + label=gettext_lazy("Server port"), initial=389, - help_text=ugettext_lazy("The TCP port number used by the LDAP server"), + help_text=gettext_lazy("The TCP port number used by the LDAP server"), ) ldap_enable_secondary_server = YesNoField( - label=ugettext_lazy("Enable secondary server (fallback)"), + label=gettext_lazy("Enable secondary server (fallback)"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Enable a secondary LDAP server which will be used " "if the primary one fails" ) ) ldap_secondary_server_address = forms.CharField( - label=ugettext_lazy("Secondary server address"), + label=gettext_lazy("Secondary server address"), initial="localhost", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The IP address or the DNS name of the seondary LDAP server"), ) ldap_secondary_server_port = forms.IntegerField( - label=ugettext_lazy("Secondary server port"), + label=gettext_lazy("Secondary server port"), initial=389, - help_text=ugettext_lazy( + help_text=gettext_lazy( "The TCP port number used by the LDAP secondary server"), ) ldap_secured = forms.ChoiceField( - label=ugettext_lazy("Use a secured connection"), + label=gettext_lazy("Use a secured connection"), choices=constants.LDAP_SECURE_MODES, initial="none", - help_text=ugettext_lazy( + help_text=gettext_lazy( "Use an SSL/STARTTLS connection to access the LDAP server") ) ldap_is_active_directory = YesNoField( - label=ugettext_lazy("Active Directory"), + label=gettext_lazy("Active Directory"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Tell if the LDAP server is an Active Directory one") ) ldap_admin_groups = forms.CharField( - label=ugettext_lazy("Administrator groups"), + label=gettext_lazy("Administrator groups"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "Members of those LDAP Posix groups will be created as domain " "administrators. Use ';' characters to separate groups." ), @@ -192,45 +192,45 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_group_type = forms.ChoiceField( - label=ugettext_lazy("Group type"), + label=gettext_lazy("Group type"), initial="posixgroup", choices=constants.LDAP_GROUP_TYPES, - help_text=ugettext_lazy( + help_text=gettext_lazy( "The LDAP group type to use with your directory." ) ) ldap_groups_search_base = forms.CharField( - label=ugettext_lazy("Groups search base"), + label=gettext_lazy("Groups search base"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The distinguished name of the search base used to find groups" ), required=False ) ldap_password_attribute = forms.CharField( - label=ugettext_lazy("Password attribute"), + label=gettext_lazy("Password attribute"), initial="userPassword", - help_text=ugettext_lazy("The attribute used to store user passwords"), + help_text=gettext_lazy("The attribute used to store user passwords"), ) # LDAP authentication settings ldap_auth_sep = SeparatorField( - label=ugettext_lazy("LDAP authentication settings")) + label=gettext_lazy("LDAP authentication settings")) ldap_auth_method = forms.ChoiceField( - label=ugettext_lazy("Authentication method"), - choices=[("searchbind", ugettext_lazy("Search and bind")), - ("directbind", ugettext_lazy("Direct bind"))], + label=gettext_lazy("Authentication method"), + choices=[("searchbind", gettext_lazy("Search and bind")), + ("directbind", gettext_lazy("Direct bind"))], initial="searchbind", - help_text=ugettext_lazy("Choose the authentication method to use"), + help_text=gettext_lazy("Choose the authentication method to use"), ) ldap_bind_dn = forms.CharField( - label=ugettext_lazy("Bind DN"), + label=gettext_lazy("Bind DN"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The distinguished name to use when binding to the LDAP server. " "Leave empty for an anonymous bind" ), @@ -238,9 +238,9 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_bind_password = forms.CharField( - label=ugettext_lazy("Bind password"), + label=gettext_lazy("Bind password"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The password to use when binding to the LDAP server " "(with 'Bind DN')" ), @@ -249,18 +249,18 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_search_base = forms.CharField( - label=ugettext_lazy("Users search base"), + label=gettext_lazy("Users search base"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The distinguished name of the search base used to find users" ), required=False, ) ldap_search_filter = forms.CharField( - label=ugettext_lazy("Search filter"), + label=gettext_lazy("Search filter"), initial="(mail=%(user)s)", - help_text=ugettext_lazy( + help_text=gettext_lazy( "An optional filter string (e.g. '(objectClass=person)'). " "In order to be valid, it must be enclosed in parentheses." ), @@ -268,9 +268,9 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_user_dn_template = forms.CharField( - label=ugettext_lazy("User DN template"), + label=gettext_lazy("User DN template"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The template used to construct a user's DN. It should contain " "one placeholder (ie. %(user)s)" ), @@ -279,12 +279,12 @@ class GeneralParametersForm(param_forms.AdminParametersForm): # LDAP sync. settings ldap_sync_sep = SeparatorField( - label=ugettext_lazy("LDAP synchronization settings")) + label=gettext_lazy("LDAP synchronization settings")) ldap_sync_bind_dn = forms.CharField( - label=ugettext_lazy("Bind DN"), + label=gettext_lazy("Bind DN"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The distinguished name to use when binding to the LDAP server. " "Leave empty for an anonymous bind" ), @@ -292,9 +292,9 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_sync_bind_password = forms.CharField( - label=ugettext_lazy("Bind password"), + label=gettext_lazy("Bind password"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The password to use when binding to the LDAP server " "(with 'Bind DN')" ), @@ -303,28 +303,28 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_enable_sync = YesNoField( - label=ugettext_lazy("Enable export to LDAP"), + label=gettext_lazy("Enable export to LDAP"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Enable automatic synchronization between local database and " "LDAP directory") ) ldap_sync_delete_remote_account = YesNoField( - label=ugettext_lazy( + label=gettext_lazy( "Delete remote LDAP account when local account is deleted" ), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Delete remote LDAP account when local account is deleted, " "otherwise it will be disabled." ) ) ldap_sync_account_dn_template = forms.CharField( - label=ugettext_lazy("Account DN template"), + label=gettext_lazy("Account DN template"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The template used to construct an account's DN. It should contain " "one placeholder (ie. %(user)s)" ), @@ -332,27 +332,27 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_enable_import = YesNoField( - label=ugettext_lazy("Enable import from LDAP"), + label=gettext_lazy("Enable import from LDAP"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Enable account synchronization from LDAP directory to local " "database" ) ) ldap_import_search_base = forms.CharField( - label=ugettext_lazy("Users search base"), + label=gettext_lazy("Users search base"), initial="", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The distinguished name of the search base used to find users" ), required=False, ) ldap_import_search_filter = forms.CharField( - label=ugettext_lazy("Search filter"), + label=gettext_lazy("Search filter"), initial="(cn=*)", - help_text=ugettext_lazy( + help_text=gettext_lazy( "An optional filter string (e.g. '(objectClass=person)'). " "In order to be valid, it must be enclosed in parentheses." ), @@ -360,51 +360,51 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ldap_import_username_attr = forms.CharField( - label=ugettext_lazy("Username attribute"), + label=gettext_lazy("Username attribute"), initial="cn", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The name of the LDAP attribute where the username can be found." ), ) ldap_dovecot_sync = YesNoField( - label=ugettext_lazy("Enable Dovecot LDAP sync"), + label=gettext_lazy("Enable Dovecot LDAP sync"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "LDAP authentication settings will be applied to Dovecot " "configuration." ) ) ldap_dovecot_conf_file = forms.CharField( - label=ugettext_lazy("Dovecot LDAP config file"), + label=gettext_lazy("Dovecot LDAP config file"), initial="/etc/dovecot/dovecot-modoboa.conf", required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Location of the configuration file which contains " "Dovecot LDAP settings." ) ) - dash_sep = SeparatorField(label=ugettext_lazy("Dashboard")) + dash_sep = SeparatorField(label=gettext_lazy("Dashboard")) rss_feed_url = forms.URLField( - label=ugettext_lazy("Custom RSS feed"), + label=gettext_lazy("Custom RSS feed"), required=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Display custom RSS feed to resellers and domain administrators" ) ) hide_features_widget = YesNoField( - label=ugettext_lazy("Hide features widget"), + label=gettext_lazy("Hide features widget"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Hide features widget for resellers and domain administrators" ) ) - notif_sep = SeparatorField(label=ugettext_lazy("Notifications")) + notif_sep = SeparatorField(label=gettext_lazy("Notifications")) sender_address = lib_fields.UTF8EmailField( label=_("Sender address"), @@ -414,26 +414,26 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) ) - api_sep = SeparatorField(label=ugettext_lazy("Public API")) + api_sep = SeparatorField(label=gettext_lazy("Public API")) enable_api_communication = YesNoField( - label=ugettext_lazy("Enable communication"), + label=gettext_lazy("Enable communication"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Enable communication with Modoboa public API") ) check_new_versions = YesNoField( - label=ugettext_lazy("Check new versions"), + label=gettext_lazy("Check new versions"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Automatically checks if a newer version is available") ) send_new_versions_email = YesNoField( - label=ugettext_lazy("Send an email when new versions are found"), + label=gettext_lazy("Send an email when new versions are found"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Send an email to notify admins about new versions" ) ) @@ -446,14 +446,14 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) send_statistics = YesNoField( - label=ugettext_lazy("Send statistics"), + label=gettext_lazy("Send statistics"), initial=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Send statistics to Modoboa public API " "(counters and used extensions)") ) - sep3 = SeparatorField(label=ugettext_lazy("Miscellaneous")) + sep3 = SeparatorField(label=gettext_lazy("Miscellaneous")) enable_inactive_accounts = YesNoField( label=_("Enable inactive account tracking"), @@ -481,22 +481,22 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) log_maximum_age = forms.IntegerField( - label=ugettext_lazy("Maximum log record age"), + label=gettext_lazy("Maximum log record age"), initial=365, - help_text=ugettext_lazy("The maximum age in days of a log record"), + help_text=gettext_lazy("The maximum age in days of a log record"), ) items_per_page = forms.IntegerField( - label=ugettext_lazy("Items per page"), + label=gettext_lazy("Items per page"), initial=30, - help_text=ugettext_lazy("Number of displayed items per page"), + help_text=gettext_lazy("Number of displayed items per page"), ) default_top_redirection = forms.ChoiceField( - label=ugettext_lazy("Default top redirection"), + label=gettext_lazy("Default top redirection"), choices=[], initial="user", - help_text=ugettext_lazy( + help_text=gettext_lazy( "The default redirection used when no application is specified" ), ) @@ -537,7 +537,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm): ) available_schemes = get_dovecot_schemes() self.fields["password_scheme"].choices = [ - (hasher.name, ugettext_lazy(hasher.label)) + (hasher.name, gettext_lazy(hasher.label)) for hasher in PasswordHasher.get_password_hashers() if hasher().scheme in available_schemes ] @@ -725,46 +725,46 @@ class GeneralParametersForm(param_forms.AdminParametersForm): GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ ("authentication", { - "label": ugettext_lazy("Authentication"), + "label": gettext_lazy("Authentication"), "params": collections.OrderedDict([ ("authentication_type", { - "label": ugettext_lazy("Authentication type"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Authentication type"), + "help_text": gettext_lazy( "The backend used for authentication"), }), ("password_scheme", { - "label": ugettext_lazy("Default password scheme"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default password scheme"), + "help_text": gettext_lazy( "Scheme used to crypt mailbox passwords"), }), ("rounds_number", { - "label": ugettext_lazy("Rounds"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Rounds"), + "help_text": gettext_lazy( "Number of rounds to use (only used by sha256crypt and " "sha512crypt). Must be between 1000 and 999999999, " "inclusive." ) }), ("update_scheme", { - "label": ugettext_lazy("Update password scheme at login"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Update password scheme at login"), + "help_text": gettext_lazy( "Update user password at login to use the default " "password scheme" ) }), ("default_password", { - "label": ugettext_lazy("Default password"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default password"), + "help_text": gettext_lazy( "Default password for automatically created accounts.") }), ("random_password_length", { - "label": ugettext_lazy("Random password length"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Random password length"), + "help_text": gettext_lazy( "Length of randomly generated passwords.") }), ("update_password_url", { - "label": ugettext_lazy("Update password service URL"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Update password service URL"), + "help_text": gettext_lazy( "The URL of an external page where users will be able" " to update their password. It applies only to non local" " users, ie. those automatically created after a successful" @@ -772,23 +772,23 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ ) }), ("password_recovery_msg", { - "label": ugettext_lazy("Password recovery announcement"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Password recovery announcement"), + "help_text": gettext_lazy( "A temporary message that will be displayed on the " "reset password page." ) }), ("sms_password_recovery", { - "label": ugettext_lazy("Enable password recovery by SMS"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable password recovery by SMS"), + "help_text": gettext_lazy( "Enable password recovery by SMS for users who filled " "a phone number." ) }), ("sms_provider", { - "label": ugettext_lazy("SMS provider"), + "label": gettext_lazy("SMS provider"), "display": "sms_password_recovery=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Choose a provider to send password recovery SMS" ) }), @@ -799,94 +799,94 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ "label": _("LDAP"), "params": collections.OrderedDict([ ("ldap_server_address", { - "label": ugettext_lazy("Server address"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Server address"), + "help_text": gettext_lazy( "The IP address or the DNS name of the LDAP server"), }), ("ldap_server_port", { - "label": ugettext_lazy("Server port"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Server port"), + "help_text": gettext_lazy( "The TCP port number used by the LDAP server") }), ("ldap_enable_secondary_server", { - "label": ugettext_lazy("Enable secondary server (fallback)"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable secondary server (fallback)"), + "help_text": gettext_lazy( "Enable a secondary LDAP server which will be used " "if the primary one fails" ) }), ("ldap_secondary_server_address", { - "label": ugettext_lazy("Secondary server address"), + "label": gettext_lazy("Secondary server address"), "display": "ldap_enable_secondary_server=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "The IP address or the DNS name of the seondary LDAP server" ) }), ("ldap_secondary_server_port", { - "label": ugettext_lazy("Secondary server port"), + "label": gettext_lazy("Secondary server port"), "display": "ldap_enable_secondary_server=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "The TCP port number used by the LDAP secondary server" ) }), ("ldap_secured", { - "label": ugettext_lazy("Use a secured connection"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Use a secured connection"), + "help_text": gettext_lazy( "Use an SSL/STARTTLS connection to access the LDAP server") }), ("ldap_is_active_directory", { - "label": ugettext_lazy("Active Directory"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Active Directory"), + "help_text": gettext_lazy( "Tell if the LDAP server is an Active Directory one") }), ("ldap_admin_groups", { - "label": ugettext_lazy("Administrator groups"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Administrator groups"), + "help_text": gettext_lazy( "Members of those LDAP Posix groups will be created as " "domain administrators. Use ';' characters to separate " "groups." ) }), ("ldap_group_type", { - "label": ugettext_lazy("Group type"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Group type"), + "help_text": gettext_lazy( "The LDAP group type to use with your directory." ) }), ("ldap_groups_search_base", { - "label": ugettext_lazy("Groups search base"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Groups search base"), + "help_text": gettext_lazy( "The distinguished name of the search base used to find " "groups" ) }), ("ldap_password_attribute", { - "label": ugettext_lazy("Password attribute"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Password attribute"), + "help_text": gettext_lazy( "The attribute used to store user passwords"), }), ("ldap_auth_sep", { - "label": ugettext_lazy("LDAP authentication settings"), + "label": gettext_lazy("LDAP authentication settings"), "display": "authentication_type=ldap", "separator": True }), ("ldap_auth_method", { - "label": ugettext_lazy("Authentication method"), + "label": gettext_lazy("Authentication method"), "display": "authentication_type=ldap", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Choose the authentication method to use"), }), ("ldap_bind_dn", { - "label": ugettext_lazy("Bind DN"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Bind DN"), + "help_text": gettext_lazy( "The distinguished name to use when binding to the LDAP " "server. Leave empty for an anonymous bind" ), "display": "authentication_type=ldap&ldap_auth_method=searchbind" }), ("ldap_bind_password", { - "label": ugettext_lazy("Bind password"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Bind password"), + "help_text": gettext_lazy( "The password to use when binding to the LDAP server " "(with 'Bind DN')" ), @@ -894,113 +894,113 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ "password": True }), ("ldap_search_base", { - "label": ugettext_lazy("Users search base"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Users search base"), + "help_text": gettext_lazy( "The distinguished name of the search base used to find " "users" ), "display": "authentication_type=ldap&ldap_auth_method=searchbind" }), ("ldap_search_filter", { - "label": ugettext_lazy("Search filter"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Search filter"), + "help_text": gettext_lazy( "An optional filter string (e.g. '(objectClass=person)'). " "In order to be valid, it must be enclosed in parentheses." ), "display": "authentication_type=ldap&ldap_auth_method=searchbind" }), ("ldap_user_dn_template", { - "label": ugettext_lazy("User DN template"), - "help_text": ugettext_lazy( + "label": gettext_lazy("User DN template"), + "help_text": gettext_lazy( "The template used to construct a user's DN. It should " "contain one placeholder (ie. %(user)s)" ), "display": "authentication_type=ldap&ldap_auth_method=directbind" }), ("ldap_sync_sep", { - "label": ugettext_lazy("LDAP synchronization settings"), + "label": gettext_lazy("LDAP synchronization settings"), "separator": True }), ("ldap_sync_bind_dn", { - "label": ugettext_lazy("Bind DN"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Bind DN"), + "help_text": gettext_lazy( "The distinguished name to use when binding to the LDAP server. " "Leave empty for an anonymous bind" ) }), ("ldap_sync_bind_password", { - "label": ugettext_lazy("Bind password"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Bind password"), + "help_text": gettext_lazy( "The password to use when binding to the LDAP server " "(with 'Bind DN')" ), "password": True }), ("ldap_enable_sync", { - "label": ugettext_lazy("Enable export to LDAP"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable export to LDAP"), + "help_text": gettext_lazy( "Enable automatic synchronization between local database " "and LDAP directory" ) }), ("ldap_sync_delete_remote_account", { - "label": ugettext_lazy( + "label": gettext_lazy( "Delete remote LDAP account when local account is deleted"), - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Delete remote LDAP account when local account is deleted, " "otherwise it will be disabled." ), "display": "ldap_enable_sync=true" }), ("ldap_sync_account_dn_template", { - "label": ugettext_lazy("Account DN template"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Account DN template"), + "help_text": gettext_lazy( "The template used to construct an account's DN. It should " "contain one placeholder (ie. %(user)s)" ), "display": "ldap_enable_sync=true" }), ("ldap_enable_import", { - "label": ugettext_lazy("Enable import from LDAP"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable import from LDAP"), + "help_text": gettext_lazy( "Enable account synchronization from LDAP directory to " "local database" ) }), ("ldap_import_search_base", { - "label": ugettext_lazy("Users search base"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Users search base"), + "help_text": gettext_lazy( "The distinguished name of the search base used to find " "users" ), "display": "ldap_enable_import=true" }), ("ldap_import_search_filter", { - "label": ugettext_lazy("Search filter"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Search filter"), + "help_text": gettext_lazy( "An optional filter string (e.g. '(objectClass=person)'). " "In order to be valid, it must be enclosed in parentheses." ), "display": "ldap_enable_import=true" }), ("ldap_import_username_attr", { - "label": ugettext_lazy("Username attribute"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Username attribute"), + "help_text": gettext_lazy( "The name of the LDAP attribute where the username can be " "found." ), "display": "ldap_enable_import=true" }), ("ldap_dovecot_sync", { - "label": ugettext_lazy("Enable Dovecot LDAP sync"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable Dovecot LDAP sync"), + "help_text": gettext_lazy( "LDAP authentication settings will be applied to Dovecot " "configuration." ) }), ("ldap_dovecot_conf_file", { - "label": ugettext_lazy("Dovecot LDAP config file"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Dovecot LDAP config file"), + "help_text": gettext_lazy( "Location of the configuration file which contains " "Dovecot LDAP settings." ), @@ -1010,18 +1010,18 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ ]) }), ("dashboard", { - "label": ugettext_lazy("Dashboard"), + "label": gettext_lazy("Dashboard"), "params": collections.OrderedDict([ ("rss_feed_url", { - "label": ugettext_lazy("Custom RSS feed"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Custom RSS feed"), + "help_text": gettext_lazy( "Display custom RSS feed to resellers and domain " "administrators" ) }), ("hide_features_widget", { - "label": ugettext_lazy("Hide features widget"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Hide features widget"), + "help_text": gettext_lazy( "Hide features widget for resellers and domain " "administrators" ) @@ -1029,90 +1029,90 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ ]) }), ("notifications", { - "label": ugettext_lazy("Notifications"), + "label": gettext_lazy("Notifications"), "params": collections.OrderedDict([ ("sender_address", { - "label": ugettext_lazy("Sender address"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Sender address"), + "help_text": gettext_lazy( "Email address used to send notifications.") }) ]) }), ("api", { - "label": ugettext_lazy("Public API"), + "label": gettext_lazy("Public API"), "params": collections.OrderedDict([ ("enable_api_communication", { - "label": ugettext_lazy("Enable communication"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable communication"), + "help_text": gettext_lazy( "Automatically checks if a newer version is available") }), ("check_new_versions", { - "label": ugettext_lazy("Check new versions"), + "label": gettext_lazy("Check new versions"), "display": "enable_api_communication=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Automatically checks if a newer version is available") }), ("send_new_versions_email", { - "label": ugettext_lazy( + "label": gettext_lazy( "Send an email when new versions are found"), "display": "check_new_versions=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Send an email to notify admins about new versions" ) }), ("new_versions_email_rcpt", { - "label": ugettext_lazy("Recipient"), + "label": gettext_lazy("Recipient"), "display": "check_new_versions=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Recipient of new versions notification emails." ) }), ("send_statistics", { - "label": ugettext_lazy("Send statistics"), + "label": gettext_lazy("Send statistics"), "display": "enable_api_communication=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "Send statistics to Modoboa public API " "(counters and used extensions)") }) ]) }), ("misc", { - "label": ugettext_lazy("Miscellaneous"), + "label": gettext_lazy("Miscellaneous"), "params": collections.OrderedDict([ ("enable_inactive_accounts", { - "label": ugettext_lazy("Enable inactive account tracking"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Enable inactive account tracking"), + "help_text": gettext_lazy( "Allow the administrator to set a threshold (in days) " "beyond which an account is considered inactive " "if the user hasn't logged in" ), }), ("inactive_account_threshold", { - "label": ugettext_lazy("Inactive account threshold"), + "label": gettext_lazy("Inactive account threshold"), "display": "enable_inactive_accounts=true", - "help_text": ugettext_lazy( + "help_text": gettext_lazy( "An account with a last login date greater than this " "threshold (in days) will be considered as inactive" ) }), ("top_notifications_check_interval", { - "label": ugettext_lazy("Top notifications check interval"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Top notifications check interval"), + "help_text": gettext_lazy( "Interval between two top notification checks (in seconds)" ), }), ("log_maximum_age", { - "label": ugettext_lazy("Maximum log record age"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Maximum log record age"), + "help_text": gettext_lazy( "The maximum age in days of a log record"), }), ("items_per_page", { - "label": ugettext_lazy("Items per page"), - "help_text": ugettext_lazy("Number of displayed items per page") + "label": gettext_lazy("Items per page"), + "help_text": gettext_lazy("Number of displayed items per page") }), ("default_top_redirection", { - "label": ugettext_lazy("Default top redirection"), - "help_text": ugettext_lazy( + "label": gettext_lazy("Default top redirection"), + "help_text": gettext_lazy( "The default redirection used when no application is " "specified" ), diff --git a/modoboa/core/apps.py b/modoboa/core/apps.py index 515174dce..311f497de 100644 --- a/modoboa/core/apps.py +++ b/modoboa/core/apps.py @@ -2,7 +2,7 @@ from django.apps import AppConfig from django.db.models import signals -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy def load_core_settings(): @@ -16,9 +16,9 @@ def load_core_settings(): from .api.v2 import serializers param_tools.registry.add( - "global", app_settings.GeneralParametersForm, ugettext_lazy("General")) + "global", app_settings.GeneralParametersForm, gettext_lazy("General")) param_tools.registry.add2( - "global", "core", ugettext_lazy("General"), + "global", "core", gettext_lazy("General"), app_settings.GLOBAL_PARAMETERS_STRUCT, serializers.CoreGlobalParametersSerializer) diff --git a/modoboa/core/checks/settings_checks.py b/modoboa/core/checks/settings_checks.py index a1efe49d7..d5858e2e1 100644 --- a/modoboa/core/checks/settings_checks.py +++ b/modoboa/core/checks/settings_checks.py @@ -1,6 +1,6 @@ from django.conf import settings from django.core.checks import Warning, register -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ W001 = Warning( _("You have USE_TZ set to False, this may result in issues during " diff --git a/modoboa/core/constants.py b/modoboa/core/constants.py index a44529c6f..cc9a8b11b 100644 --- a/modoboa/core/constants.py +++ b/modoboa/core/constants.py @@ -1,12 +1,12 @@ """Core application constants.""" from django.conf import settings -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy -SIMPLEUSERS_ROLE = ("SimpleUsers", ugettext_lazy("Simple user")) -DOMAINADMINS_ROLE = ("DomainAdmins", ugettext_lazy("Domain administrator")) -RESELLERS_ROLE = ("Resellers", ugettext_lazy("Reseller")) -SUPERADMINS_ROLE = ("SuperAdmins", ugettext_lazy("Super administrator")) +SIMPLEUSERS_ROLE = ("SimpleUsers", gettext_lazy("Simple user")) +DOMAINADMINS_ROLE = ("DomainAdmins", gettext_lazy("Domain administrator")) +RESELLERS_ROLE = ("Resellers", gettext_lazy("Reseller")) +SUPERADMINS_ROLE = ("SuperAdmins", gettext_lazy("Super administrator")) ROLES = ( SIMPLEUSERS_ROLE, @@ -50,14 +50,14 @@ LDAP_GROUP_TYPES = ( ) LDAP_SECURE_MODES = [ - ("none", ugettext_lazy("No")), + ("none", gettext_lazy("No")), ("starttls", "STARTTLS"), ("ssl", "SSL/TLS") ] LDAP_AUTH_METHODS = [ - ("searchbind", ugettext_lazy("Search and bind")), - ("directbind", ugettext_lazy("Direct bind")) + ("searchbind", gettext_lazy("Search and bind")), + ("directbind", gettext_lazy("Direct bind")) ] PERMISSIONS = { @@ -105,11 +105,11 @@ PERMISSIONS = { } SMS_BACKENDS = [ - ("", ugettext_lazy("Choose a provider")), + ("", gettext_lazy("Choose a provider")), ("ovh", "OVH"), ] if settings.DEBUG: - SMS_BACKENDS.insert(1, ("dummy", ugettext_lazy("Dummy"))) + SMS_BACKENDS.insert(1, ("dummy", gettext_lazy("Dummy"))) TFA_DEVICE_TOKEN_KEY = "otp_device_id" diff --git a/modoboa/core/drf_authentication.py b/modoboa/core/drf_authentication.py index 1bb9f5c52..9427fca5a 100644 --- a/modoboa/core/drf_authentication.py +++ b/modoboa/core/drf_authentication.py @@ -1,7 +1,7 @@ """Custom authentication for DRF.""" from django.urls import reverse -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django_otp.models import Device from drf_spectacular.contrib.rest_framework_simplejwt import SimpleJWTScheme diff --git a/modoboa/core/extensions.py b/modoboa/core/extensions.py index 3ea192dee..7d1103eac 100644 --- a/modoboa/core/extensions.py +++ b/modoboa/core/extensions.py @@ -1,7 +1,8 @@ """Extension management.""" from django.conf import settings -from django.conf.urls import include, url +from django.conf.urls import include +from django.urls import re_path from django.utils.encoding import smart_str @@ -111,7 +112,7 @@ class ExtensionsPool(object): pattern = "{}.urls" try: result.append( - url(root, include(pattern.format(ext_name))) + re_path(root, include(pattern.format(ext_name))) ) except ImportError: # No urls for this extension diff --git a/modoboa/core/forms.py b/modoboa/core/forms.py index 3c1d8e0de..61fa248d5 100644 --- a/modoboa/core/forms.py +++ b/modoboa/core/forms.py @@ -7,7 +7,7 @@ from django.contrib.auth import ( forms as auth_forms, get_user_model, password_validation ) from django.db.models import Q -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy import django_otp @@ -20,11 +20,11 @@ class LoginForm(forms.Form): """User login form.""" username = forms.CharField( - label=ugettext_lazy("Username"), + label=gettext_lazy("Username"), widget=forms.TextInput(attrs={"class": "form-control"}) ) password = forms.CharField( - label=ugettext_lazy("Password"), + label=gettext_lazy("Password"), widget=forms.PasswordInput(attrs={"class": "form-control"}) ) rememberme = forms.BooleanField( @@ -37,15 +37,15 @@ class ProfileForm(forms.ModelForm): """Form to update User profile.""" oldpassword = forms.CharField( - label=ugettext_lazy("Old password"), required=False, + label=gettext_lazy("Old password"), required=False, widget=forms.PasswordInput(attrs={"class": "form-control"}) ) newpassword = forms.CharField( - label=ugettext_lazy("New password"), required=False, + label=gettext_lazy("New password"), required=False, widget=forms.PasswordInput(attrs={"class": "form-control"}) ) confirmation = forms.CharField( - label=ugettext_lazy("Confirmation"), required=False, + label=gettext_lazy("Confirmation"), required=False, widget=forms.PasswordInput(attrs={"class": "form-control"}) ) @@ -115,7 +115,7 @@ class APIAccessForm(forms.Form): """Form to control API access.""" enable_api_access = forms.BooleanField( - label=ugettext_lazy("Enable API access"), required=False) + label=gettext_lazy("Enable API access"), required=False) def __init__(self, *args, **kwargs): """Initialize form.""" @@ -149,7 +149,7 @@ class VerifySMSCodeForm(forms.Form): """A form to verify a code received by SMS.""" code = forms.CharField( - label=ugettext_lazy("Verification code"), + label=gettext_lazy("Verification code"), widget=forms.widgets.TextInput(attrs={"class": "form-control"}) ) diff --git a/modoboa/core/handlers.py b/modoboa/core/handlers.py index a0833c22b..0934cb3d0 100644 --- a/modoboa/core/handlers.py +++ b/modoboa/core/handlers.py @@ -9,8 +9,8 @@ from django.contrib.sites import models as sites_models from django.db.models import signals from django.dispatch import receiver from django.urls import reverse -from django.utils.encoding import smart_text -from django.utils.translation import ugettext as _ +from django.utils.encoding import smart_str +from django.utils.translation import gettext as _ from modoboa.lib import exceptions, permissions from modoboa.lib.signals import get_request @@ -39,7 +39,7 @@ def post_revision_commit(sender, **kwargs): action = _("modified") level = "warning" message = _("%(object)s '%(name)s' %(action)s by user %(user)s") % { - "object": smart_text(version.content_type).capitalize(), + "object": smart_str(version.content_type).capitalize(), "name": version.object_repr, "action": action, "user": current_user } @@ -61,7 +61,7 @@ def log_object_removal(sender, instance, **kwargs): return logger = logging.getLogger("modoboa.admin") msg = _("%(object)s '%(name)s' %(action)s by ") % { - "object": smart_text(version.content_type).capitalize(), + "object": smart_str(version.content_type).capitalize(), "name": version.object_repr, "action": _("deleted") } request = get_request() diff --git a/modoboa/core/management/commands/communicate_with_public_api.py b/modoboa/core/management/commands/communicate_with_public_api.py index eac121bf3..d5d850621 100644 --- a/modoboa/core/management/commands/communicate_with_public_api.py +++ b/modoboa/core/management/commands/communicate_with_public_api.py @@ -3,7 +3,7 @@ from django.core.mail import EmailMessage from django.core.management.base import BaseCommand, CommandError from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import models as admin_models from modoboa.core.extensions import exts_pool diff --git a/modoboa/core/migrations/0025_rename_user_email_is_active_core_user_email_c0c03f_idx.py b/modoboa/core/migrations/0025_rename_user_email_is_active_core_user_email_c0c03f_idx.py new file mode 100644 index 000000000..a001c7257 --- /dev/null +++ b/modoboa/core/migrations/0025_rename_user_email_is_active_core_user_email_c0c03f_idx.py @@ -0,0 +1,17 @@ +# Generated by Django 4.2 on 2023-04-25 12:00 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("core", "0024_alter_user_language"), + ] + + operations = [ + migrations.RenameIndex( + model_name="user", + new_name="core_user_email_c0c03f_idx", + old_fields=("email", "is_active"), + ), + ] diff --git a/modoboa/core/models.py b/modoboa/core/models.py index 3cb2ddbf4..efff9e820 100644 --- a/modoboa/core/models.py +++ b/modoboa/core/models.py @@ -6,9 +6,9 @@ from email.header import Header from django.conf import settings from django.db import models from django.urls import reverse -from django.utils.encoding import force_str, smart_bytes, smart_text +from django.utils.encoding import force_str, smart_bytes, smart_str from django.utils.functional import cached_property -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from django.contrib.auth.models import AbstractUser, Group from django.contrib.contenttypes.fields import GenericForeignKey @@ -49,26 +49,26 @@ class User(AbstractUser): is_active = models.BooleanField(default=True, db_index=True) is_local = models.BooleanField(default=True, db_index=True) master_user = models.BooleanField( - ugettext_lazy("Allow mailboxes access"), default=False, - help_text=ugettext_lazy( + gettext_lazy("Allow mailboxes access"), default=False, + help_text=gettext_lazy( "Allow this administrator to access user mailboxes" ) ) - password = models.CharField(ugettext_lazy("password"), max_length=256) + password = models.CharField(gettext_lazy("password"), max_length=256) language = models.CharField( - ugettext_lazy("language"), + gettext_lazy("language"), max_length=10, default="en", choices=constants.LANGUAGES, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Prefered language to display pages." ) ) phone_number = PhoneNumberField( - ugettext_lazy("Phone number"), blank=True, null=True) + gettext_lazy("Phone number"), blank=True, null=True) secondary_email = models.EmailField( - ugettext_lazy("Secondary email"), max_length=254, + gettext_lazy("Secondary email"), max_length=254, blank=True, null=True, - help_text=ugettext_lazy( + help_text=gettext_lazy( "An alternative e-mail address, can be used for recovery needs.") ) @@ -78,9 +78,7 @@ class User(AbstractUser): class Meta(object): ordering = ["username"] - index_together = [ - ["email", "is_active"] - ] + indexes = [models.Index(fields=["email", "is_active"])] password_expr = re.compile(r'\{([\w\-]+)\}(.+)') @@ -144,7 +142,7 @@ class User(AbstractUser): return hasher().verify(raw_value, val2) def __str__(self): - return smart_text(self.get_username()) + return smart_str(self.get_username()) def get_absolute_url(self): """Return detail url for this user.""" @@ -369,13 +367,13 @@ class User(AbstractUser): """Return row that can be included in a CSV file.""" row = [ "account", - smart_text(self.username), - smart_text(self.password), - smart_text(self.first_name), - smart_text(self.last_name), - smart_text(self.is_active), - smart_text(self.role), - smart_text(self.email) + smart_str(self.username), + smart_str(self.password), + smart_str(self.first_name), + smart_str(self.last_name), + smart_str(self.is_active), + smart_str(self.role), + smart_str(self.email) ] results = signals.account_exported.send( sender=self.__class__, user=self) diff --git a/modoboa/core/password_hashers/__init__.py b/modoboa/core/password_hashers/__init__.py index bcbf86b3f..aadf96bca 100644 --- a/modoboa/core/password_hashers/__init__.py +++ b/modoboa/core/password_hashers/__init__.py @@ -3,7 +3,7 @@ Password hashers for Modoboa. """ from django.conf import settings -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from modoboa.core.password_hashers.advanced import ( # NOQA:F401 BLFCRYPTHasher, MD5CRYPTHasher, SHA256CRYPTHasher, SHA512CRYPTHasher, @@ -53,5 +53,5 @@ def get_dovecot_schemes(): if retcode: schemes = default_schemes - return ["{{{}}}".format(smart_text(scheme)) + return ["{{{}}}".format(smart_str(scheme)) for scheme in schemes.split()] diff --git a/modoboa/core/password_hashers/advanced.py b/modoboa/core/password_hashers/advanced.py index dfac9cc99..899b860d6 100644 --- a/modoboa/core/password_hashers/advanced.py +++ b/modoboa/core/password_hashers/advanced.py @@ -40,7 +40,7 @@ class BLFCRYPTHasher(PasswordHasher): # rounds = parameters.get_global_parameter("rounds_number") # To get around this, I use the default of 12. rounds = 12 - return bcrypt.hash(clearvalue, rounds=rounds) + return bcrypt.hash.using(rounds=rounds).hash(clearvalue) def verify(self, clearvalue, hashed_value): return bcrypt.verify(clearvalue, hashed_value) @@ -85,7 +85,7 @@ class SHA256CRYPTHasher(PasswordHasher): def _encrypt(self, clearvalue, salt=None): rounds = param_tools.get_global_parameter("rounds_number") - return sha256_crypt.hash(clearvalue, rounds=rounds) + return sha256_crypt.using(rounds=rounds).hash(clearvalue) def verify(self, clearvalue, hashed_value): return sha256_crypt.verify(clearvalue, hashed_value) @@ -107,7 +107,7 @@ class SHA512CRYPTHasher(PasswordHasher): def _encrypt(self, clearvalue, salt=None): rounds = param_tools.get_global_parameter("rounds_number") - return sha512_crypt.hash(clearvalue, rounds=rounds) + return sha512_crypt.using(rounds=rounds).hash(clearvalue) def verify(self, clearvalue, hashed_value): return sha512_crypt.verify(clearvalue, hashed_value) diff --git a/modoboa/core/password_hashers/base.py b/modoboa/core/password_hashers/base.py index 689ffb82a..2b2bba139 100644 --- a/modoboa/core/password_hashers/base.py +++ b/modoboa/core/password_hashers/base.py @@ -11,7 +11,7 @@ import string from random import Random from django.utils.crypto import constant_time_compare -from django.utils.encoding import force_bytes, force_text +from django.utils.encoding import force_bytes, force_str class MetaHasher(type): @@ -65,8 +65,8 @@ class PasswordHasher(metaclass=MetaHasher): :rtype: str :return: encrypted password """ - pwhash = self._b64encode(self._encrypt(force_text(clearvalue))) - return "%s%s" % (self.scheme, force_text(pwhash)) + pwhash = self._b64encode(self._encrypt(force_str(clearvalue))) + return "%s%s" % (self.scheme, force_str(pwhash)) def verify(self, clearvalue, hashed_value): """Verify a password against a hashed value. diff --git a/modoboa/core/password_validation.py b/modoboa/core/password_validation.py index 3cb944fd7..47522897d 100644 --- a/modoboa/core/password_validation.py +++ b/modoboa/core/password_validation.py @@ -1,7 +1,7 @@ """Custom password validators.""" from django.core.exceptions import ValidationError -from django.utils.translation import ugettext as _, ungettext +from django.utils.translation import gettext as _, ngettext class ComplexityValidator(object): @@ -20,7 +20,7 @@ class ComplexityValidator(object): sum(1 for char in password if char.isdigit()) < self.digits) if condition: raise ValidationError( - ungettext( + ngettext( "Password must contain at least {} digit.", "Password must contain at least {} digits.", self.digits @@ -30,7 +30,7 @@ class ComplexityValidator(object): sum(1 for char in password if char.islower()) < self.lower) if condition: raise ValidationError( - ungettext( + ngettext( "Password must contain at least {} lowercase letter.", "Password must contain at least {} lowercase letters.", self.lower @@ -41,7 +41,7 @@ class ComplexityValidator(object): sum(1 for char in password if char.isupper()) < self.upper) if condition: raise ValidationError( - ungettext( + ngettext( "Password must contain at least {} uppercase letter.", "Password must contain at least {} uppercase letters.", self.upper @@ -53,7 +53,7 @@ class ComplexityValidator(object): self.specials) if condition: raise ValidationError( - ungettext( + ngettext( "Password must contain at least {} special character.", "Password must contain at least {} special characters.", self.specials diff --git a/modoboa/core/signals.py b/modoboa/core/signals.py index 409dc2e0b..05107d396 100644 --- a/modoboa/core/signals.py +++ b/modoboa/core/signals.py @@ -2,36 +2,25 @@ import django.dispatch -account_auto_created = django.dispatch.Signal(providing_args=["user"]) -account_exported = django.dispatch.Signal(providing_args=["account"]) -account_imported = django.dispatch.Signal( - providing_args=["user", "account", "row"]) -account_deleted = django.dispatch.Signal(providing_args=["user"]) -account_role_changed = django.dispatch.Signal( - providing_args=["account", "role"]) -account_password_updated = django.dispatch.Signal( - providing_args=["account", "password", "created"]) -allow_password_change = django.dispatch.Signal(providing_args=["user"]) -can_create_object = django.dispatch.Signal( - providing_args=["context", "klass", "object_type", "count", "instance"]) -extra_account_actions = django.dispatch.Signal(providing_args=["account"]) -extra_admin_dashboard_widgets = django.dispatch.Signal( - providing_args=["user"]) -extra_admin_menu_entries = django.dispatch.Signal( - providing_args=["location", "user"]) -extra_role_permissions = django.dispatch.Signal(providing_args=["role"]) -extra_static_content = django.dispatch.Signal( - providing_args=["caller", "st_type", "user"]) +account_auto_created = django.dispatch.Signal() # Provides user +account_exported = django.dispatch.Signal() # Provides account +account_imported = django.dispatch.Signal() # Provides user, account, row +account_deleted = django.dispatch.Signal() # Provides user +account_role_changed = django.dispatch.Signal() # Provides account, role +account_password_updated = django.dispatch.Signal() # Provides account password created +allow_password_change = django.dispatch.Signal() # Provides user +can_create_object = django.dispatch.Signal() # Provides context, klass, object_type, count, instance +extra_account_actions = django.dispatch.Signal() # Provides account +extra_admin_dashboard_widgets = django.dispatch.Signal() # Provides user +extra_admin_menu_entries = django.dispatch.Signal() # Provides location, user +extra_role_permissions = django.dispatch.Signal() # Provides role +extra_static_content = django.dispatch.Signal() # Provides caller, st_type, user extra_uprefs_routes = django.dispatch.Signal() -extra_user_menu_entries = django.dispatch.Signal( - providing_args=["location", "user"]) -get_announcements = django.dispatch.Signal(providing_args=["location"]) -get_top_notifications = django.dispatch.Signal( - providing_args=["include_all"]) -initial_data_loaded = django.dispatch.Signal(providing_args=["extname"]) +extra_user_menu_entries = django.dispatch.Signal() # Provides location, user +get_announcements = django.dispatch.Signal() # Provides location +get_top_notifications = django.dispatch.Signal() # Provides include_all +initial_data_loaded = django.dispatch.Signal() # Provides extname register_postfix_maps = django.dispatch.Signal() -user_can_set_role = django.dispatch.Signal( - providing_args=["user", "role", "account"]) -user_login = django.dispatch.Signal( - providing_args=["username", "password"]) +user_can_set_role = django.dispatch.Signal() # Provides user, role, account +user_login = django.dispatch.Signal() # Provides username, password user_logout = django.dispatch.Signal() diff --git a/modoboa/core/sms_backends/ovh.py b/modoboa/core/sms_backends/ovh.py index f36f036c6..ae86a9d7b 100644 --- a/modoboa/core/sms_backends/ovh.py +++ b/modoboa/core/sms_backends/ovh.py @@ -4,7 +4,7 @@ import ovh from django import forms from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers diff --git a/modoboa/core/templatetags/core_tags.py b/modoboa/core/templatetags/core_tags.py index 04bc8ae79..3e1bee986 100644 --- a/modoboa/core/templatetags/core_tags.py +++ b/modoboa/core/templatetags/core_tags.py @@ -12,9 +12,9 @@ from django.contrib.sessions.models import Session from django.template.loader import render_to_string from django.urls import reverse from django.utils import timezone -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from django.utils.safestring import mark_safe -from django.utils.translation import get_language, ugettext as _ +from django.utils.translation import get_language, gettext as _ from .. import models from .. import signals @@ -241,7 +241,7 @@ def display_messages(msgs): level = "info" for m in msgs: level = m.tags - text += smart_text(m) + "\\\n" + text += smart_str(m) + "\\\n" if level == "info": level = "success" diff --git a/modoboa/core/tests/stupid_extension_2/urls.py b/modoboa/core/tests/stupid_extension_2/urls.py index a7996a92b..a4098f372 100644 --- a/modoboa/core/tests/stupid_extension_2/urls.py +++ b/modoboa/core/tests/stupid_extension_2/urls.py @@ -1,9 +1,9 @@ """Custom urls.""" -from django.conf.urls import url +from django.urls import re_path from . import views urlpatterns = [ - url("^$", views.test_view, name="index") + re_path("^$", views.test_view, name="index") ] diff --git a/modoboa/core/utils.py b/modoboa/core/utils.py index 9425581fb..9509e22ed 100644 --- a/modoboa/core/utils.py +++ b/modoboa/core/utils.py @@ -2,7 +2,7 @@ from pkg_resources import parse_version -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core.extensions import exts_pool from modoboa.lib.api_client import ModoAPIClient diff --git a/modoboa/core/views/admin.py b/modoboa/core/views/admin.py index 881b396b9..b4681dec7 100644 --- a/modoboa/core/views/admin.py +++ b/modoboa/core/views/admin.py @@ -5,7 +5,7 @@ from functools import reduce from django.contrib.auth.decorators import login_required, user_passes_test from django.shortcuts import render from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core.models import Log from modoboa.core.utils import check_for_updates diff --git a/modoboa/core/views/auth.py b/modoboa/core/views/auth.py index 29c328bf3..3057eb50d 100644 --- a/modoboa/core/views/auth.py +++ b/modoboa/core/views/auth.py @@ -13,7 +13,7 @@ from django.utils import translation from django.utils.encoding import force_bytes from django.utils.html import escape from django.utils.http import urlsafe_base64_encode -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.views import generic from django.views.decorators.cache import never_cache diff --git a/modoboa/core/views/base.py b/modoboa/core/views/base.py index 1c5378b34..0de677140 100644 --- a/modoboa/core/views/base.py +++ b/modoboa/core/views/base.py @@ -2,7 +2,7 @@ from django.contrib.auth import mixins as auth_mixins from django.urls import reverse -from django.utils.http import is_safe_url +from django.utils.http import url_has_allowed_host_and_scheme from django.views import generic from ..extensions import exts_pool @@ -16,7 +16,7 @@ def find_nextlocation(request, user): nextlocation = request.POST.get("next", request.GET.get("next")) condition = ( nextlocation and - is_safe_url(nextlocation, request.get_host()) + url_has_allowed_host_and_scheme(nextlocation, request.get_host()) ) if condition: return nextlocation diff --git a/modoboa/core/views/user.py b/modoboa/core/views/user.py index a91f05379..9c5e6ae52 100644 --- a/modoboa/core/views/user.py +++ b/modoboa/core/views/user.py @@ -9,8 +9,8 @@ from django.conf import settings from django.shortcuts import render from django.template.loader import render_to_string from django.utils import translation -from django.utils.encoding import force_text -from django.utils.translation import ugettext as _ +from django.utils.encoding import force_str +from django.utils.translation import gettext as _ from django.contrib.auth.decorators import login_required, user_passes_test @@ -52,7 +52,7 @@ def profile(request, tplname="core/user_profile.html"): if form.is_valid(): form.save() if update_password and form.cleaned_data["confirmation"] != "": - request.session["password"] = force_text(encrypt( + request.session["password"] = force_str(encrypt( form.cleaned_data["confirmation"] )) translation.activate(request.user.language) diff --git a/modoboa/dmarc/forms.py b/modoboa/dmarc/forms.py index 0d4be9a44..ca374b925 100644 --- a/modoboa/dmarc/forms.py +++ b/modoboa/dmarc/forms.py @@ -4,7 +4,7 @@ import collections from django import forms from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from modoboa.dmarc.api.v2 import serializers from modoboa.lib import form_utils diff --git a/modoboa/dmarc/handlers.py b/modoboa/dmarc/handlers.py index 06a4cb055..fcd89e7a7 100644 --- a/modoboa/dmarc/handlers.py +++ b/modoboa/dmarc/handlers.py @@ -1,7 +1,7 @@ """Django signal handlers for modoboa_dmarc.""" from django.urls import reverse -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.dispatch import receiver from modoboa.admin import signals as admin_signals diff --git a/modoboa/dmarc/lib.py b/modoboa/dmarc/lib.py index 773d6428a..9ae04c019 100644 --- a/modoboa/dmarc/lib.py +++ b/modoboa/dmarc/lib.py @@ -20,8 +20,8 @@ import six from django.db import transaction from django.db.models import Q from django.utils import timezone -from django.utils.encoding import smart_text -from django.utils.translation import ugettext as _ +from django.utils.encoding import smart_str +from django.utils.translation import gettext as _ from modoboa.admin import models as admin_models from modoboa.parameters import tools as param_tools @@ -57,7 +57,7 @@ def import_record(xml_node, report): record.spf_result = policy_evaluated.find("spf").text reason = policy_evaluated.find("reason") if reason: - record.reason_type = smart_text(reason.find("type").text)[:14] + record.reason_type = smart_str(reason.find("type").text)[:14] if record.reason_type not in constants.ALLOWED_REASON_TYPES: record.reason_type = "other" comment = reason.find("comment").text or "" diff --git a/modoboa/dmarc/models.py b/modoboa/dmarc/models.py index 4591feb41..baf57a849 100644 --- a/modoboa/dmarc/models.py +++ b/modoboa/dmarc/models.py @@ -1,7 +1,7 @@ """DMARC models.""" from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from modoboa.admin import models as admin_models diff --git a/modoboa/dmarc/templatetags/dmarc_tags.py b/modoboa/dmarc/templatetags/dmarc_tags.py index c313b67ae..7112ee490 100644 --- a/modoboa/dmarc/templatetags/dmarc_tags.py +++ b/modoboa/dmarc/templatetags/dmarc_tags.py @@ -6,7 +6,7 @@ from collections import OrderedDict from django import template from django.utils.safestring import mark_safe -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ register = template.Library() diff --git a/modoboa/dmarc/views.py b/modoboa/dmarc/views.py index 68c9fdbeb..37c6ba8b4 100644 --- a/modoboa/dmarc/views.py +++ b/modoboa/dmarc/views.py @@ -11,7 +11,7 @@ from django.utils import timezone from django.views import generic from django.contrib.auth import mixins as auth_mixins -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from modoboa.admin import models as admin_models from modoboa.parameters import tools as param_tools diff --git a/modoboa/dnstools/lib.py b/modoboa/dnstools/lib.py index f5dac6bc0..5f92ab731 100644 --- a/modoboa/dnstools/lib.py +++ b/modoboa/dnstools/lib.py @@ -2,7 +2,7 @@ import ipaddress -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import lib as admin_lib diff --git a/modoboa/dnstools/models.py b/modoboa/dnstools/models.py index e3e68ceb0..73fad5ecf 100644 --- a/modoboa/dnstools/models.py +++ b/modoboa/dnstools/models.py @@ -4,7 +4,7 @@ import datetime from django.db import models from django.utils import timezone -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from . import constants from . import lib diff --git a/modoboa/dnstools/views.py b/modoboa/dnstools/views.py index 6ce92c739..dd2297e01 100644 --- a/modoboa/dnstools/views.py +++ b/modoboa/dnstools/views.py @@ -1,6 +1,6 @@ """App related views.""" -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.views import generic from django.contrib.auth import mixins as auth_mixins diff --git a/modoboa/imap_migration/app_settings.py b/modoboa/imap_migration/app_settings.py index c4c3a85df..d73d194da 100644 --- a/modoboa/imap_migration/app_settings.py +++ b/modoboa/imap_migration/app_settings.py @@ -3,7 +3,7 @@ import collections from django import forms -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from modoboa.lib import form_utils from modoboa.parameters import forms as param_forms diff --git a/modoboa/imap_migration/apps.py b/modoboa/imap_migration/apps.py index d611d1da0..e3cf9fb5e 100644 --- a/modoboa/imap_migration/apps.py +++ b/modoboa/imap_migration/apps.py @@ -1,7 +1,7 @@ """AppConfig for IMAP migration.""" from django.apps import AppConfig -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy def load_imapmigration_settings(): @@ -15,9 +15,9 @@ def load_imapmigration_settings(): from .api.v2 import serializers param_tools.registry.add( - "global", app_settings.ParametersForm, ugettext_lazy("IMAP Migration")) + "global", app_settings.ParametersForm, gettext_lazy("IMAP Migration")) param_tools.registry.add2( - "global", "imap_migration", ugettext_lazy("IMAP Migration"), + "global", "imap_migration", gettext_lazy("IMAP Migration"), app_settings.IMAP_MIGRATION_PARAMETERS_STRUCT, serializers.IMAPMigrationSettingsSerializer, True) diff --git a/modoboa/imap_migration/auth_backends.py b/modoboa/imap_migration/auth_backends.py index c1ecf79f3..ac6afe3b7 100644 --- a/modoboa/imap_migration/auth_backends.py +++ b/modoboa/imap_migration/auth_backends.py @@ -5,7 +5,7 @@ import socket import ssl from django.utils.encoding import smart_bytes, smart_str -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import models as core_models from modoboa.lib import email_utils diff --git a/modoboa/imap_migration/checks.py b/modoboa/imap_migration/checks.py index 6f20e160b..9ace9a5ea 100644 --- a/modoboa/imap_migration/checks.py +++ b/modoboa/imap_migration/checks.py @@ -2,7 +2,7 @@ from django.core.checks import Warning, register -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import models as core_models diff --git a/modoboa/ldapsync/lib.py b/modoboa/ldapsync/lib.py index 4d4b7b269..ae2c87120 100644 --- a/modoboa/ldapsync/lib.py +++ b/modoboa/ldapsync/lib.py @@ -5,7 +5,7 @@ import ldap.modlist as modlist from django.conf import settings from django.utils.encoding import force_bytes, force_str -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import models as core_models from modoboa.lib.email_utils import split_mailbox diff --git a/modoboa/lib/api_client.py b/modoboa/lib/api_client.py index a63c80012..e47b38cf1 100644 --- a/modoboa/lib/api_client.py +++ b/modoboa/lib/api_client.py @@ -7,7 +7,7 @@ import pkg_resources import requests from requests.exceptions import RequestException -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ logger = logging.getLogger("modoboa.admin") diff --git a/modoboa/lib/cryptutils.py b/modoboa/lib/cryptutils.py index d413af9b4..19d3f004b 100644 --- a/modoboa/lib/cryptutils.py +++ b/modoboa/lib/cryptutils.py @@ -11,7 +11,7 @@ from cryptography.hazmat.primitives.hashes import SHA1 from django.conf import settings from django.utils.crypto import get_random_string -from django.utils.encoding import smart_bytes, smart_text +from django.utils.encoding import smart_bytes, smart_str def random_key(length=16): @@ -34,12 +34,12 @@ def _get_fernet(): def encrypt(clear_value): """Encrypt a value using secret_key.""" - return smart_text(_get_fernet().encrypt(smart_bytes(clear_value))) + return smart_str(_get_fernet().encrypt(smart_bytes(clear_value))) def decrypt(encrypted_value): """Decrypt a value using secret_key.""" - return smart_text(_get_fernet().decrypt(smart_bytes(encrypted_value))) + return smart_str(_get_fernet().decrypt(smart_bytes(encrypted_value))) def get_password(request): diff --git a/modoboa/lib/db_utils.py b/modoboa/lib/db_utils.py index 569bc8e9f..03b279f80 100644 --- a/modoboa/lib/db_utils.py +++ b/modoboa/lib/db_utils.py @@ -1,6 +1,6 @@ from django.conf import settings from django.db import connection -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.lib.exceptions import InternalError diff --git a/modoboa/lib/email_utils.py b/modoboa/lib/email_utils.py index d3b30b76e..ffb102ec3 100644 --- a/modoboa/lib/email_utils.py +++ b/modoboa/lib/email_utils.py @@ -13,9 +13,9 @@ from lxml.html.clean import Cleaner from django.core.mail import EmailMessage from django.template.loader import render_to_string -from django.utils.encoding import smart_str, smart_text +from django.utils.encoding import smart_str, smart_str from django.utils.html import conditional_escape, escape -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import models as core_models from modoboa.lib import u2u_decode @@ -130,7 +130,7 @@ class Email(object): if not len(value): continue if encoding: - value = smart_text(value, encoding=encoding) + value = smart_str(value, encoding=encoding) elif isinstance(value, bytes): # SMTPUTF8 fallback (most of the time) # Address contains non ASCII chars but is not RFC2047 @@ -229,7 +229,7 @@ class Email(object): _RE_REMOVE_EXTRA_WHITESPACE.sub("\n\n", content).strip() ) mail_text = escape(mail_text) - return smart_text(mail_text) + return smart_str(mail_text) def _post_process_html(self, content): html = lxml.html.fromstring(content) @@ -253,7 +253,7 @@ class Email(object): ) mail_text = lxml.html.tostring( cleaner.clean_html(html), encoding="unicode") - return smart_text(mail_text) + return smart_str(mail_text) def _map_cid(self, url): if url.startswith("cid:"): diff --git a/modoboa/lib/exceptions.py b/modoboa/lib/exceptions.py index 2e740597d..05f8e0d2d 100644 --- a/modoboa/lib/exceptions.py +++ b/modoboa/lib/exceptions.py @@ -4,7 +4,7 @@ """ -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ class ModoboaException(Exception): diff --git a/modoboa/lib/fields.py b/modoboa/lib/fields.py index c5e81ff11..19941473c 100644 --- a/modoboa/lib/fields.py +++ b/modoboa/lib/fields.py @@ -1,7 +1,7 @@ """Custom form fields.""" from django import forms -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy from rest_framework import serializers @@ -12,7 +12,7 @@ class DomainNameField(forms.fields.CharField): """A subclass of CharField that only accepts a valid domain name.""" default_error_messages = { - "invalid": ugettext_lazy("Enter a valid domain name") + "invalid": gettext_lazy("Enter a valid domain name") } default_validators = [validators.validate_hostname] @@ -41,7 +41,7 @@ class DRFEmailFieldUTF8(serializers.CharField): """Custom DRF email field to support UTF8.""" default_error_messages = { - "invalid": ugettext_lazy("Enter a valid email address.") + "invalid": gettext_lazy("Enter a valid email address.") } def __init__(self, **kwargs): @@ -55,7 +55,7 @@ class DRFEmailFieldUTF8AndEmptyUser(serializers.CharField): """Custom DRF email field to support UTF8 and empty local part.""" default_error_messages = { - "invalid": ugettext_lazy("Enter a valid email address.") + "invalid": gettext_lazy("Enter a valid email address.") } def __init__(self, **kwargs): diff --git a/modoboa/lib/form_utils.py b/modoboa/lib/form_utils.py index 771840bfe..1118fc8f0 100644 --- a/modoboa/lib/form_utils.py +++ b/modoboa/lib/form_utils.py @@ -9,7 +9,7 @@ from django.forms.fields import Field from django.forms.widgets import RadioSelect from django.shortcuts import render from django.utils.encoding import force_str -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from modoboa.lib.exceptions import BadRequest from modoboa.lib.web_utils import render_to_json_response @@ -393,8 +393,8 @@ class YesNoField(TypedChoiceField): """Constructor.""" kwargs.update({ "choices": ( - (True, ugettext_lazy("Yes")), - (False, ugettext_lazy("No")) + (True, gettext_lazy("Yes")), + (False, gettext_lazy("No")) ), "widget": HorizontalRadioSelect(), "coerce": lambda x: x == "True" diff --git a/modoboa/lib/ldap_utils.py b/modoboa/lib/ldap_utils.py index c981c25ab..cbadc8e1e 100644 --- a/modoboa/lib/ldap_utils.py +++ b/modoboa/lib/ldap_utils.py @@ -35,7 +35,7 @@ import ldap from django.conf import settings from django.utils.encoding import force_bytes, force_str -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core.password_hashers import get_password_hasher from modoboa.lib.exceptions import InternalError diff --git a/modoboa/lib/middleware.py b/modoboa/lib/middleware.py index 5262af691..4d02b7f15 100644 --- a/modoboa/lib/middleware.py +++ b/modoboa/lib/middleware.py @@ -2,7 +2,7 @@ from django.http import HttpResponseRedirect from django.utils.deprecation import MiddlewareMixin -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from modoboa.lib import signals as lib_signals from modoboa.lib.exceptions import ModoboaException @@ -11,10 +11,14 @@ from modoboa.lib.web_utils import ( ) +def is_ajax(request): + return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' + + class AjaxLoginRedirect(MiddlewareMixin): def process_response(self, request, response): - if request.is_ajax(): + if is_ajax(request): if isinstance(response, HttpResponseRedirect): response.status_code = 278 return response @@ -27,17 +31,17 @@ class CommonExceptionCatcher(MiddlewareMixin): if not isinstance(exception, ModoboaException): return None - if request.is_ajax() or "/api/" in request.path: + if is_ajax(request) or "/api/" in request.path: if exception.http_code is None: return ajax_response( - request, status="ko", respmsg=smart_text(exception), + request, status="ko", respmsg=smart_str(exception), norefresh=True ) return render_to_json_response( - smart_text(exception), status=exception.http_code + smart_str(exception), status=exception.http_code ) return _render_error( - request, user_context={"error": smart_text(exception)} + request, user_context={"error": smart_str(exception)} ) diff --git a/modoboa/lib/sysutils.py b/modoboa/lib/sysutils.py index d290a04a7..6877b3fd0 100644 --- a/modoboa/lib/sysutils.py +++ b/modoboa/lib/sysutils.py @@ -10,7 +10,7 @@ import re import subprocess from django.conf import settings -from django.utils.encoding import force_text +from django.utils.encoding import force_str def exec_cmd(cmd, sudo_user=None, pinput=None, capture_output=True, **kwargs): @@ -59,7 +59,7 @@ def doveadm_cmd(params, pinput=None, capture_output=True, **kwargs): dpath = None code, output = exec_cmd("which doveadm") if not code: - dpath = force_text(output).strip() + dpath = force_str(output).strip() else: known_paths = getattr( settings, "DOVEADM_LOOKUP_PATH", diff --git a/modoboa/lib/templatetags/form_tags.py b/modoboa/lib/templatetags/form_tags.py index fad4637bb..869f9fdd5 100644 --- a/modoboa/lib/templatetags/form_tags.py +++ b/modoboa/lib/templatetags/form_tags.py @@ -4,7 +4,7 @@ Form rendering tags. from django import forms, template from django.template.loader import render_to_string -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str from django.utils.safestring import mark_safe from modoboa.lib.form_utils import SeparatorField @@ -43,7 +43,7 @@ def render_field( from modoboa.core.templatetags.core_tags import visirule if isinstance(field.field, SeparatorField): - return "%s" % (visirule(field), smart_text(field.label)) + return "%s" % (visirule(field), smart_str(field.label)) configure_field_classes(field) context = { "field": field, "help_display_mode": help_display_mode, diff --git a/modoboa/lib/templatetags/lib_tags.py b/modoboa/lib/templatetags/lib_tags.py index 22cf15146..2f72b088a 100644 --- a/modoboa/lib/templatetags/lib_tags.py +++ b/modoboa/lib/templatetags/lib_tags.py @@ -5,7 +5,7 @@ from datetime import datetime from django import template from django.template import Context, Template from django.utils.safestring import mark_safe -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import signals as core_signals diff --git a/modoboa/lib/tests/test_email_utils.py b/modoboa/lib/tests/test_email_utils.py index b64007d3b..405cec905 100644 --- a/modoboa/lib/tests/test_email_utils.py +++ b/modoboa/lib/tests/test_email_utils.py @@ -3,7 +3,7 @@ import os from django.test import SimpleTestCase -from django.utils.encoding import smart_bytes, smart_text +from django.utils.encoding import smart_bytes, smart_str from ..email_utils import ( Email, prepare_addresses, split_address, split_local_part @@ -44,7 +44,7 @@ class EmailTests(SimpleTestCase): with open(message_path, "rb") as fp: # output should always be unicode (py2) or str (py3) - mail_text = smart_text(fp.read()) + mail_text = smart_str(fp.read()) return mail_text diff --git a/modoboa/lib/u2u_decode.py b/modoboa/lib/u2u_decode.py index 34a89e917..c7d3c5cef 100644 --- a/modoboa/lib/u2u_decode.py +++ b/modoboa/lib/u2u_decode.py @@ -9,7 +9,7 @@ import re from email.header import decode_header, make_header from email.utils import parseaddr -from django.utils.encoding import smart_text +from django.utils.encoding import smart_str # check spaces between encoded_words (and strip them) sre = re.compile(r"\?=[ \t]+=\?") @@ -40,7 +40,7 @@ def decode_mime(m): """Substitute matching encoded_word with unicode equiv.""" h = decode_header(clean_spaces(m)) try: - u = smart_text(make_header(h)) + u = smart_str(make_header(h)) except (LookupError, UnicodeDecodeError): return m.group(0) return u diff --git a/modoboa/lib/validators.py b/modoboa/lib/validators.py index fd7e4b91f..645e18dfa 100644 --- a/modoboa/lib/validators.py +++ b/modoboa/lib/validators.py @@ -4,14 +4,14 @@ import re from django.core.exceptions import ValidationError from django.core.validators import EmailValidator, URLValidator -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy class HostnameValidator(object): """Validator for fqdn.""" - message = ugettext_lazy("Enter a valid domain name") + message = gettext_lazy("Enter a valid domain name") code = "invalid" regex = re.compile(URLValidator.host_re) diff --git a/modoboa/limits/app_settings.py b/modoboa/limits/app_settings.py index f4fe0f686..001a0ccf9 100644 --- a/modoboa/limits/app_settings.py +++ b/modoboa/limits/app_settings.py @@ -3,7 +3,7 @@ import collections from django import forms -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from modoboa.lib.form_utils import SeparatorField, YesNoField from modoboa.parameters import forms as param_forms diff --git a/modoboa/limits/apps.py b/modoboa/limits/apps.py index a2f32805b..2f204b0e3 100644 --- a/modoboa/limits/apps.py +++ b/modoboa/limits/apps.py @@ -1,7 +1,7 @@ """App config for limits.""" from django.apps import AppConfig -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ def load_limits_settings(): diff --git a/modoboa/limits/constants.py b/modoboa/limits/constants.py index c916b2b93..970d9eef7 100644 --- a/modoboa/limits/constants.py +++ b/modoboa/limits/constants.py @@ -2,7 +2,7 @@ import collections -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ DEFAULT_USER_LIMITS = collections.OrderedDict(( ("domains", { diff --git a/modoboa/limits/forms.py b/modoboa/limits/forms.py index ac6842505..ddaf69f1d 100644 --- a/modoboa/limits/forms.py +++ b/modoboa/limits/forms.py @@ -1,7 +1,7 @@ """Custom forms.""" from django import forms -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.lib.permissions import get_object_owner from . import utils diff --git a/modoboa/limits/handlers.py b/modoboa/limits/handlers.py index d595f8f3d..a2992db20 100644 --- a/modoboa/limits/handlers.py +++ b/modoboa/limits/handlers.py @@ -4,7 +4,7 @@ from django.contrib.contenttypes.models import ContentType from django.db.models import signals from django.dispatch import receiver from django.template.loader import render_to_string -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import models as admin_models, signals as admin_signals from modoboa.core import models as core_models, signals as core_signals diff --git a/modoboa/limits/lib.py b/modoboa/limits/lib.py index 7da7b97e8..f186bc07f 100644 --- a/modoboa/limits/lib.py +++ b/modoboa/limits/lib.py @@ -4,7 +4,7 @@ """ -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.lib.exceptions import ModoboaException diff --git a/modoboa/limits/models.py b/modoboa/limits/models.py index 65445c342..2f12d8285 100644 --- a/modoboa/limits/models.py +++ b/modoboa/limits/models.py @@ -3,7 +3,7 @@ from django.conf import settings from django.db import models from django.utils.functional import cached_property -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.core import models as core_models from . import lib, utils diff --git a/modoboa/maillog/api/v2/serializers.py b/modoboa/maillog/api/v2/serializers.py index f6c204d76..3d45c627d 100644 --- a/modoboa/maillog/api/v2/serializers.py +++ b/modoboa/maillog/api/v2/serializers.py @@ -1,6 +1,6 @@ """App. related serializers.""" -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from rest_framework import serializers diff --git a/modoboa/maillog/forms.py b/modoboa/maillog/forms.py index 2d38ff2f1..240546199 100644 --- a/modoboa/maillog/forms.py +++ b/modoboa/maillog/forms.py @@ -5,7 +5,7 @@ import rrdtool from pkg_resources import parse_version from django.conf import settings -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy from django import forms from modoboa.lib import form_utils @@ -17,27 +17,27 @@ class ParametersForm(param_forms.AdminParametersForm): app = "maillog" - general_sep = form_utils.SeparatorField(label=ugettext_lazy("General")) + general_sep = form_utils.SeparatorField(label=gettext_lazy("General")) logfile = forms.CharField( - label=ugettext_lazy("Path to the log file"), + label=gettext_lazy("Path to the log file"), initial="/var/log/mail.log", - help_text=ugettext_lazy("Path to log file used to collect statistics"), + help_text=gettext_lazy("Path to log file used to collect statistics"), widget=forms.TextInput(attrs={"class": "form-control"}) ) rrd_rootdir = forms.CharField( - label=ugettext_lazy("Directory to store RRD files"), + label=gettext_lazy("Directory to store RRD files"), initial="/tmp/modoboa", - help_text=ugettext_lazy( + help_text=gettext_lazy( "Path to directory where RRD files are stored"), widget=forms.TextInput(attrs={"class": "form-control"}) ) greylist = form_utils.YesNoField( - label=ugettext_lazy("Show greylisted messages"), + label=gettext_lazy("Show greylisted messages"), initial=False, - help_text=ugettext_lazy( + help_text=gettext_lazy( "Differentiate between hard and soft rejects (greylisting)") ) @@ -56,4 +56,4 @@ def load_settings(): from modoboa.parameters import tools as param_tools param_tools.registry.add( - "global", ParametersForm, ugettext_lazy("Statistics")) + "global", ParametersForm, gettext_lazy("Statistics")) diff --git a/modoboa/maillog/graphics.py b/modoboa/maillog/graphics.py index e228ed0f7..2bac4c098 100644 --- a/modoboa/maillog/graphics.py +++ b/modoboa/maillog/graphics.py @@ -7,8 +7,8 @@ from itertools import chain import os from django.conf import settings -from django.utils.encoding import smart_bytes, smart_text -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.encoding import smart_bytes, smart_str +from django.utils.translation import gettext as _, gettext_lazy from modoboa.admin import models as admin_models from modoboa.lib import exceptions @@ -91,7 +91,7 @@ class Graphic: if dpath is None: raise exceptions.InternalError( _("Failed to locate rrdtool binary.")) - return smart_text(dpath) + return smart_str(dpath) def export(self, rrdfile, start, end): """Export data to JSON using rrdtool.""" @@ -167,22 +167,22 @@ class GraphicSet(object): class AverageTraffic(Graphic): """Average traffic.""" - title = ugettext_lazy('Average traffic (msgs/min)') + title = gettext_lazy('Average traffic (msgs/min)') # Curve definitions - sent = Curve("sent", "lawngreen", ugettext_lazy("sent messages")) - recv = Curve("recv", "steelblue", ugettext_lazy("received messages")) - bounced = Curve("bounced", "yellow", ugettext_lazy("bounced messages")) - reject = Curve("reject", "tomato", ugettext_lazy("rejected messages")) - virus = Curve("virus", "orange", ugettext_lazy("virus messages")) - spam = Curve("spam", "silver", ugettext_lazy("spam messages")) + sent = Curve("sent", "lawngreen", gettext_lazy("sent messages")) + recv = Curve("recv", "steelblue", gettext_lazy("received messages")) + bounced = Curve("bounced", "yellow", gettext_lazy("bounced messages")) + reject = Curve("reject", "tomato", gettext_lazy("rejected messages")) + virus = Curve("virus", "orange", gettext_lazy("virus messages")) + spam = Curve("spam", "silver", gettext_lazy("spam messages")) order = ["reject", "bounced", "recv", "sent", "virus", "spam"] def __init__(self, greylist=False): if greylist: self.greylist = Curve( - "greylist", "dimgrey", ugettext_lazy("greylisted messages")) + "greylist", "dimgrey", gettext_lazy("greylisted messages")) self.order = [ "reject", "greylist", "bounced", "recv", "sent", "virus", "spam" @@ -193,12 +193,12 @@ class AverageTraffic(Graphic): class AverageTrafficSize(Graphic): """Average traffic size.""" - title = ugettext_lazy('Average normal traffic size (bytes/min)') + title = gettext_lazy('Average normal traffic size (bytes/min)') # Curve definitions - size_recv = Curve("size_recv", "orange", ugettext_lazy("received size")) + size_recv = Curve("size_recv", "orange", gettext_lazy("received size")) size_sent = Curve( - "size_sent", "mediumturquoise", ugettext_lazy("sent size") + "size_sent", "mediumturquoise", gettext_lazy("sent size") ) @@ -206,7 +206,7 @@ class MailTraffic(GraphicSet): """Mail traffic graphic set.""" domain_selector = True - title = ugettext_lazy("Mail traffic") + title = gettext_lazy("Mail traffic") _graphics = [AverageTraffic, AverageTrafficSize] def __init__(self, greylist=False): @@ -250,15 +250,15 @@ class MailTraffic(GraphicSet): class AccountCreationGraphic(Graphic): """Account creation over time.""" - title = ugettext_lazy("Average account creation (account/hour)") + title = gettext_lazy("Average account creation (account/hour)") accounts = Curve( - "new_accounts", "steelblue", ugettext_lazy("New accounts")) + "new_accounts", "steelblue", gettext_lazy("New accounts")) class AccountGraphicSet(GraphicSet): """A graphic set for accounts.""" file_name = "new_accounts" - title = ugettext_lazy("Accounts") + title = gettext_lazy("Accounts") _graphics = [AccountCreationGraphic] diff --git a/modoboa/maillog/handlers.py b/modoboa/maillog/handlers.py index 5d820954a..99ff0c906 100644 --- a/modoboa/maillog/handlers.py +++ b/modoboa/maillog/handlers.py @@ -2,7 +2,7 @@ from django.urls import reverse from django.dispatch import receiver -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import signals as admin_signals from modoboa.core import signals as core_signals diff --git a/modoboa/maillog/signals.py b/modoboa/maillog/signals.py index 59b2c7ae4..28b476cae 100644 --- a/modoboa/maillog/signals.py +++ b/modoboa/maillog/signals.py @@ -2,4 +2,4 @@ import django.dispatch -get_graph_sets = django.dispatch.Signal(providing_args=["user"]) +get_graph_sets = django.dispatch.Signal() # Provides user diff --git a/modoboa/maillog/views.py b/modoboa/maillog/views.py index 159464861..b2dcedb0e 100644 --- a/modoboa/maillog/views.py +++ b/modoboa/maillog/views.py @@ -6,7 +6,7 @@ import re import time from django.shortcuts import render -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.contrib.auth.decorators import ( login_required, user_passes_test, permission_required ) diff --git a/modoboa/pdfcredentials/api/v2/serializers.py b/modoboa/pdfcredentials/api/v2/serializers.py index ffb8dcf4b..2832f8ca5 100644 --- a/modoboa/pdfcredentials/api/v2/serializers.py +++ b/modoboa/pdfcredentials/api/v2/serializers.py @@ -2,7 +2,7 @@ import os -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from rest_framework import serializers, status from rest_framework.exceptions import PermissionDenied, APIException diff --git a/modoboa/pdfcredentials/api/v2/views.py b/modoboa/pdfcredentials/api/v2/views.py index 5d2345fce..d7ddc1f03 100644 --- a/modoboa/pdfcredentials/api/v2/views.py +++ b/modoboa/pdfcredentials/api/v2/views.py @@ -2,7 +2,7 @@ import os -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.http import HttpResponse from rest_framework import permissions diff --git a/modoboa/pdfcredentials/app_settings.py b/modoboa/pdfcredentials/app_settings.py index d0055c055..54ec06f10 100644 --- a/modoboa/pdfcredentials/app_settings.py +++ b/modoboa/pdfcredentials/app_settings.py @@ -5,7 +5,7 @@ import collections from django import forms from django.conf import settings from django.utils.functional import cached_property -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from django.contrib.sites import models as sites_models diff --git a/modoboa/pdfcredentials/apps.py b/modoboa/pdfcredentials/apps.py index 2342e98af..cb47c6bb0 100644 --- a/modoboa/pdfcredentials/apps.py +++ b/modoboa/pdfcredentials/apps.py @@ -2,7 +2,7 @@ from django.apps import AppConfig -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy def load_pdfcredential_settings(): @@ -16,9 +16,9 @@ def load_pdfcredential_settings(): from .api.v2 import serializers param_tools.registry.add( - "global", app_settings.ParametersForm, ugettext_lazy("PDF credentials")) + "global", app_settings.ParametersForm, gettext_lazy("PDF credentials")) param_tools.registry.add2( - "global", "pdfcredentials", ugettext_lazy("PDF Credentials"), + "global", "pdfcredentials", gettext_lazy("PDF Credentials"), app_settings.PDF_CREDENTIALS_PARAMETERS_STRUCT, serializers.PDFCredentialsSettingsSerializer, True) diff --git a/modoboa/pdfcredentials/constants.py b/modoboa/pdfcredentials/constants.py index c0a407a9c..0dd979ccc 100644 --- a/modoboa/pdfcredentials/constants.py +++ b/modoboa/pdfcredentials/constants.py @@ -1,10 +1,10 @@ """PDF credentials constants.""" -from django.utils.translation import ugettext_lazy +from django.utils.translation import gettext_lazy CONNECTION_SECURITY_MODES = [ - ("none", ugettext_lazy("None")), + ("none", gettext_lazy("None")), ("starttls", "STARTTLS"), ("tls", "TLS") ] diff --git a/modoboa/pdfcredentials/documents.py b/modoboa/pdfcredentials/documents.py index adaf9b572..edc2bc973 100644 --- a/modoboa/pdfcredentials/documents.py +++ b/modoboa/pdfcredentials/documents.py @@ -13,7 +13,7 @@ from reportlab.platypus import ( ) from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.parameters import tools as param_tools diff --git a/modoboa/pdfcredentials/handlers.py b/modoboa/pdfcredentials/handlers.py index c364e98e7..ba8e1ae53 100644 --- a/modoboa/pdfcredentials/handlers.py +++ b/modoboa/pdfcredentials/handlers.py @@ -5,7 +5,7 @@ import os from django.urls import reverse from django.db.models import signals from django.dispatch import receiver -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import signals as admin_signals from modoboa.core import models as core_models diff --git a/modoboa/pdfcredentials/lib.py b/modoboa/pdfcredentials/lib.py index 2fdeeb8fc..363703855 100644 --- a/modoboa/pdfcredentials/lib.py +++ b/modoboa/pdfcredentials/lib.py @@ -11,7 +11,7 @@ from urllib.parse import quote from django.conf import settings from django.utils.encoding import force_bytes, smart_bytes -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.lib.exceptions import InternalError from modoboa.parameters import tools as param_tools diff --git a/modoboa/pdfcredentials/views.py b/modoboa/pdfcredentials/views.py index 7fe1b7d8e..d4485c85b 100644 --- a/modoboa/pdfcredentials/views.py +++ b/modoboa/pdfcredentials/views.py @@ -3,7 +3,7 @@ import os from django.http import HttpResponse -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from django.contrib.auth.decorators import ( login_required, permission_required diff --git a/modoboa/policyd/core.py b/modoboa/policyd/core.py index f598271b2..58b1bfedf 100644 --- a/modoboa/policyd/core.py +++ b/modoboa/policyd/core.py @@ -15,7 +15,7 @@ from django.db import connections from django.template.loader import render_to_string from django.utils import timezone from django.utils import translation -from django.utils.translation import ugettext as _, ugettext_lazy +from django.utils.translation import gettext as _, gettext_lazy from modoboa.admin import constants as admin_constants from modoboa.admin import models as admin_models @@ -102,8 +102,8 @@ def create_alarm(ltype, name): async def notify_limit_reached(ltype, name): """Send a notification to super admins about item.""" ltype_translations = { - "account": ugettext_lazy("account"), - "domain": ugettext_lazy("domain") + "account": gettext_lazy("account"), + "domain": gettext_lazy("domain") } # We're going to execute sync code so we need an executor executor = concurrent.futures.ThreadPoolExecutor(max_workers=3) diff --git a/modoboa/relaydomains/api/v1/serializers.py b/modoboa/relaydomains/api/v1/serializers.py index 26cfbede1..c4eab23a7 100644 --- a/modoboa/relaydomains/api/v1/serializers.py +++ b/modoboa/relaydomains/api/v1/serializers.py @@ -2,7 +2,7 @@ import json -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from rest_framework import serializers diff --git a/modoboa/relaydomains/handlers.py b/modoboa/relaydomains/handlers.py index 14102bdd4..a901052a4 100644 --- a/modoboa/relaydomains/handlers.py +++ b/modoboa/relaydomains/handlers.py @@ -2,7 +2,7 @@ from django.db.models import signals from django.dispatch import receiver -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import models as admin_models, signals as admin_signals from modoboa.core import signals as core_signals diff --git a/modoboa/relaydomains/lib.py b/modoboa/relaydomains/lib.py index 41d28eb40..aa4f816a8 100644 --- a/modoboa/relaydomains/lib.py +++ b/modoboa/relaydomains/lib.py @@ -1,6 +1,6 @@ """Internal library.""" -from django.utils.translation import ugettext as _ +from django.utils.translation import gettext as _ from modoboa.admin import models as admin_models from modoboa.lib.exceptions import BadRequest diff --git a/modoboa/relaydomains/transport.py b/modoboa/relaydomains/transport.py index 8c1c77aeb..a357f2b52 100644 --- a/modoboa/relaydomains/transport.py +++ b/modoboa/relaydomains/transport.py @@ -1,6 +1,6 @@ """Transport backend definition.""" -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from modoboa.transport import backends diff --git a/modoboa/transport/backends.py b/modoboa/transport/backends.py index b6923b16d..ab18bfaeb 100644 --- a/modoboa/transport/backends.py +++ b/modoboa/transport/backends.py @@ -2,7 +2,7 @@ from django import forms from django.core import validators -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from modoboa.lib import validators as lib_validators diff --git a/modoboa/transport/models.py b/modoboa/transport/models.py index e92166f21..6356293b7 100644 --- a/modoboa/transport/models.py +++ b/modoboa/transport/models.py @@ -4,7 +4,7 @@ import jsonfield from reversion import revisions as reversion from django.db import models -from django.utils.translation import ugettext_lazy as _ +from django.utils.translation import gettext_lazy as _ from . import backends diff --git a/requirements.txt b/requirements.txt index 68564dcdf..6e6ef39b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -django<4.0 +django>4.0,<5.0 django-ckeditor==6.3.0 django-phonenumber-field[phonenumbers]==7.1.0 django-reversion==5.0.4 From 5ae013210082a94f079919a5fe20723292e85859 Mon Sep 17 00:00:00 2001 From: Spitap Date: Fri, 28 Apr 2023 13:41:41 +0200 Subject: [PATCH 02/11] updated workflow, update docker --- .github/workflows/modoboa.yml | 2 +- postgresql-requirements.txt | 2 +- test_project/test_project/urls.py | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/modoboa.yml b/.github/workflows/modoboa.yml index 7422e1eec..05a9d26b9 100644 --- a/.github/workflows/modoboa.yml +++ b/.github/workflows/modoboa.yml @@ -66,7 +66,7 @@ jobs: strategy: matrix: database: ['postgres', 'mysql'] - python-version: [3.7, 3.8, 3.9, '3.10'] + python-version: [3.8, 3.9, '3.10'] fail-fast: false steps: diff --git a/postgresql-requirements.txt b/postgresql-requirements.txt index 78c082246..726a08b3e 100644 --- a/postgresql-requirements.txt +++ b/postgresql-requirements.txt @@ -1 +1 @@ -psycopg2-binary>=2.8,<2.9 +psycopg[binary]>=3.1 diff --git a/test_project/test_project/urls.py b/test_project/test_project/urls.py index 136bd8a16..7e9306eed 100644 --- a/test_project/test_project/urls.py +++ b/test_project/test_project/urls.py @@ -1,7 +1,8 @@ from __future__ import unicode_literals -from django.conf.urls import include, url +from django.conf.urls import include +from django.urls import re_path urlpatterns = [ - url(r"", include("modoboa.urls")), + re_path(r"", include("modoboa.urls")), ] From f56d01296cf231696f89372b3f1dab2202fb75e8 Mon Sep 17 00:00:00 2001 From: Spitap Date: Fri, 28 Apr 2023 14:01:08 +0200 Subject: [PATCH 03/11] Updated postgres to 12 --- .github/workflows/modoboa.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/modoboa.yml b/.github/workflows/modoboa.yml index 05a9d26b9..cacf20a0e 100644 --- a/.github/workflows/modoboa.yml +++ b/.github/workflows/modoboa.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest services: postgres: - image: postgres:11 + image: postgres:12 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres From e51e6451c1fd7bdde5aa98237a7b03bc6aa399b0 Mon Sep 17 00:00:00 2001 From: Spitap Date: Sun, 30 Apr 2023 13:48:26 +0200 Subject: [PATCH 04/11] Fixed m2m relationship on fresh domain instance Co-Authored-By: Antoine Nguyen --- .github/workflows/modoboa.yml | 2 +- modoboa/admin/models/domain.py | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/modoboa.yml b/.github/workflows/modoboa.yml index cacf20a0e..39d8be9ba 100644 --- a/.github/workflows/modoboa.yml +++ b/.github/workflows/modoboa.yml @@ -97,7 +97,7 @@ jobs: pip install -r mysql-requirements.txt echo "DB=mysql" >> $GITHUB_ENV - name: Test with pytest - if: ${{ matrix.python-version != '3.8' || matrix.database != 'postgres' }} + if: ${{ matrix.database != 'postgres' }} run: | python ./tests.py cd test_project diff --git a/modoboa/admin/models/domain.py b/modoboa/admin/models/domain.py index dd997b9a6..3cc25bf90 100644 --- a/modoboa/admin/models/domain.py +++ b/modoboa/admin/models/domain.py @@ -313,7 +313,8 @@ class Domain(mixins.MessageLimitMixin, AdminObject): def save(self, *args, **kwargs): """Store current data if domain is renamed.""" - if self.oldname != self.name: + # We check that the instance exists to use m2m relationship + if self.pk and self.oldname != self.name: self.old_mail_homes = { mb.id: mb.mail_home for mb in self.mailbox_set.all() } From 8cf7ec91a29cd86324a69e15d5514dc7b4f45669 Mon Sep 17 00:00:00 2001 From: Spitap Date: Sun, 30 Apr 2023 14:28:51 +0200 Subject: [PATCH 05/11] Updated time management --- .github/workflows/modoboa.yml | 1 - modoboa/dmarc/lib.py | 9 ++------- modoboa/dmarc/views.py | 2 +- modoboa/maillog/management/commands/logparser.py | 2 +- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/modoboa.yml b/.github/workflows/modoboa.yml index 39d8be9ba..6c2a4c66a 100644 --- a/.github/workflows/modoboa.yml +++ b/.github/workflows/modoboa.yml @@ -97,7 +97,6 @@ jobs: pip install -r mysql-requirements.txt echo "DB=mysql" >> $GITHUB_ENV - name: Test with pytest - if: ${{ matrix.database != 'postgres' }} run: | python ./tests.py cd test_project diff --git a/modoboa/dmarc/lib.py b/modoboa/dmarc/lib.py index 9ae04c019..ee9e9aa63 100644 --- a/modoboa/dmarc/lib.py +++ b/modoboa/dmarc/lib.py @@ -14,7 +14,6 @@ import tldextract from defusedxml.ElementTree import fromstring from dns import resolver, reversename import magic -import pytz.exceptions import six from django.db import transaction @@ -128,11 +127,7 @@ def import_report(content): print(f"Report skipped because of malformed data (empty {attr})") return value = setattr(report, "policy_{}".format(attr), node.text) - try: - report.save() - except (pytz.exceptions.AmbiguousTimeError): - print("Report skipped because of invalid date.") - return + report.save() for record in root.findall("record"): import_record(record, report) @@ -223,7 +218,7 @@ def week_range(year, weeknumber): "{}-{}-{}".format(year, weeknumber, 1), fmt) end_week = datetime.datetime.strptime( "{}-{}-{}".format(year, weeknumber, 0), fmt) - return tz.localize(start_week), tz.localize(end_week) + return start_week.replace(tzinfo=tz), end_week.replace(tzinfo=tz) def insert_record(target: dict, record, name: str) -> None: diff --git a/modoboa/dmarc/views.py b/modoboa/dmarc/views.py index 37c6ba8b4..45dad1161 100644 --- a/modoboa/dmarc/views.py +++ b/modoboa/dmarc/views.py @@ -45,7 +45,7 @@ def week_range(year, weeknumber): "{}-{}-{}".format(year, weeknumber, 1), fmt) end_week = datetime.datetime.strptime( "{}-{}-{}".format(year, weeknumber, 0), fmt) - return tz.localize(start_week), tz.localize(end_week) + return start_week.replace(tzinfo=tz), end_week.replace(tzinfo=tz) class DomainReportView( diff --git a/modoboa/maillog/management/commands/logparser.py b/modoboa/maillog/management/commands/logparser.py index 4a4380ff9..734722cfb 100644 --- a/modoboa/maillog/management/commands/logparser.py +++ b/modoboa/maillog/management/commands/logparser.py @@ -524,7 +524,7 @@ class LogParser: last_message = models.Maillog.objects.last() cur_dt = datetime.fromtimestamp(self.orig_ts) tz = timezone.get_current_timezone() - cur_dt = tz.localize(cur_dt) + cur_dt = cur_dt.replace(tzinfo=tz) condition = ( last_message and ( cur_dt < last_message.date or From 511933218291180177b72620810e5323a3d17f36 Mon Sep 17 00:00:00 2001 From: Spitap Date: Sun, 30 Apr 2023 14:58:11 +0200 Subject: [PATCH 06/11] Fixed typo --- modoboa/core/password_hashers/advanced.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modoboa/core/password_hashers/advanced.py b/modoboa/core/password_hashers/advanced.py index 899b860d6..721c54f6f 100644 --- a/modoboa/core/password_hashers/advanced.py +++ b/modoboa/core/password_hashers/advanced.py @@ -40,7 +40,7 @@ class BLFCRYPTHasher(PasswordHasher): # rounds = parameters.get_global_parameter("rounds_number") # To get around this, I use the default of 12. rounds = 12 - return bcrypt.hash.using(rounds=rounds).hash(clearvalue) + return bcrypt.using(rounds=rounds).hash(clearvalue) def verify(self, clearvalue, hashed_value): return bcrypt.verify(clearvalue, hashed_value) From 47305ac2e38c21ee1f697b786b202697afe1d596 Mon Sep 17 00:00:00 2001 From: Spitap Date: Sun, 30 Apr 2023 15:19:14 +0200 Subject: [PATCH 07/11] Updated doc --- doc/installation.rst | 14 +++++++------- doc/upgrade.rst | 10 ++++++++++ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/doc/installation.rst b/doc/installation.rst index 17aa1aace..38577a051 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -9,12 +9,12 @@ You will need a Server to perform well with at least: * CPU: 2 * RAM: 2GB * Disk: 10GB -* Python 3 +* Python 3.8+ .. note:: **👀 Heads up for modoboa versions 1.15 and later** - - Python 2 support has been dropped with modoboa version 1.15. - If you still have Python 2 installed on your system either uninstall it + + Python 2 support has been dropped with modoboa version 1.15. + If you still have Python 2 installed on your system either uninstall it or force modoboa user to run with Python 3. Recommended way @@ -35,13 +35,13 @@ postfix, dovecot, amavis and more) on one machine. To use it, just run the following commands in your terminal: -.. sourcecode:: bash +.. sourcecode:: bash > git clone https://github.com/modoboa/modoboa-installer > cd modoboa-installer > sudo ./run.py - - + + if you get this warning - '/usr/bin/env: ‘python’: No such file or directory', do make sure sure python is installed on your server. Sometimes python is installed but the installer can't detect it or which python version to run, especially on a debian based system. Then run this command first. .. sourcecode:: bash diff --git a/doc/upgrade.rst b/doc/upgrade.rst index 9a7a29999..ce2bc3571 100644 --- a/doc/upgrade.rst +++ b/doc/upgrade.rst @@ -108,6 +108,16 @@ Rebuild Virtual Environment Specific instructions ********************* +2.1.2 +===== + +.. note:: + This version has not been released yet. + +* Django has been updated to 4.2LTS. Please upgrade all your extensions alongside modoboa. +* Support for Python 3.7 has been dropped, minimum Python version is now 3.8. +* Support for Postgres 11 has been dropped, minimum Postgres version is now 12. + 2.1.0 ===== From 15ef67207a1c99fa79b4b13d00e7a1f1553483ac Mon Sep 17 00:00:00 2001 From: Spitap Date: Thu, 4 May 2023 08:17:06 +0200 Subject: [PATCH 08/11] Updated pyproject --- pyproject.toml | 52 +------------------------------------------------- 1 file changed, 1 insertion(+), 51 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index af4b3f9f8..24352bf6d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ build-backend = "setuptools.build_meta" name = "modoboa" dynamic = [ "version", + "dependencies", "optional-dependencies" ] authors = [ @@ -30,57 +31,6 @@ classifiers = [ ] keywords = ["email"] license = {file = "LICENSE"} -dependencies = [ - "django<4.0", - "django-ckeditor==6.3.0", - "django-phonenumber-field[phonenumbers]==7.1.0", - "django-reversion==5.0.4", - "django-xforwardedfor-middleware==2.0", - "django-otp==1.1.6", - "django-filter", - "django-rename-app==0.1.5", - - "dj-database-url", - - "djangorestframework>=3.11,<3.15", - "drf-spectacular", - "uritemplate", - "djangorestframework-simplejwt==5.2.2", - - "passlib~=1.7.4", - "bcrypt", # Requires libffi-dev and python-dev - - "asgiref", - "dnspython==2.3.0", - "feedparser==6.0.10", - "gevent==22.10.2", - "jsonfield==3.1.0", - "Pillow", # Optional dependency for django-ckeditor - "progressbar33==2.4", - "python-dateutil", - "cryptography", - "pytz", - "requests", - "lxml", - "chardet", - "ovh", - "oath", - "redis", - "rrdtool>=0.1.10", - "qrcode", - - "aiosmtplib", - "aioredis==2.0.1", - - # PDF credentials - "reportlab", - - # DMARC - "tldextract>=2.0.2", - "defusedxml>=0.6.0", - "python-magic>=0.4.24", -] - [project.scripts] modoboa-cli = "modoboa:modoboa_admin" From cd03079bbf287ddb375ca95dca12cc0334773101 Mon Sep 17 00:00:00 2001 From: Spitap Date: Thu, 4 May 2023 08:31:23 +0200 Subject: [PATCH 09/11] Updated doc --- doc/upgrade.rst | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/upgrade.rst b/doc/upgrade.rst index ce2bc3571..723b132c4 100644 --- a/doc/upgrade.rst +++ b/doc/upgrade.rst @@ -108,7 +108,7 @@ Rebuild Virtual Environment Specific instructions ********************* -2.1.2 +2.1.5 ===== .. note:: @@ -118,6 +118,13 @@ Specific instructions * Support for Python 3.7 has been dropped, minimum Python version is now 3.8. * Support for Postgres 11 has been dropped, minimum Postgres version is now 12. +If you use Postgresql, you need to install pyscopg3+: + +.. sourcecode:: bash + + pip install psycopg[binary]>=3.1 + + 2.1.0 ===== From b600d83a2d56ba60f459a4bc0341462369a5e82f Mon Sep 17 00:00:00 2001 From: Spitap Date: Tue, 9 May 2023 13:16:38 +0200 Subject: [PATCH 10/11] updated doc --- doc/upgrade.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/upgrade.rst b/doc/upgrade.rst index 723b132c4..1a1222062 100644 --- a/doc/upgrade.rst +++ b/doc/upgrade.rst @@ -108,7 +108,7 @@ Rebuild Virtual Environment Specific instructions ********************* -2.1.5 +2.2.0 ===== .. note:: From 92bf82a371d0377bdcf2e0c9ed568e0eaca6d72b Mon Sep 17 00:00:00 2001 From: Spitap Date: Tue, 9 May 2023 13:25:34 +0200 Subject: [PATCH 11/11] Don't run test w/o cov on 3.10 postgres --- .github/workflows/modoboa.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/modoboa.yml b/.github/workflows/modoboa.yml index 6c2a4c66a..edeaf3677 100644 --- a/.github/workflows/modoboa.yml +++ b/.github/workflows/modoboa.yml @@ -97,6 +97,7 @@ jobs: pip install -r mysql-requirements.txt echo "DB=mysql" >> $GITHUB_ENV - name: Test with pytest + if: ${{ matrix.python-version != '3.10' || matrix.database != 'postgres' }} run: | python ./tests.py cd test_project