Merge pull request #2986 from modoboa/django-42

Migrate to Django 4.2
This commit is contained in:
Antoine Nguyen
2023-05-09 14:51:35 +02:00
committed by GitHub
128 changed files with 767 additions and 803 deletions
+3 -3
View File
@@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:11
image: postgres:12
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
@@ -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:
@@ -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.python-version != '3.10' || matrix.database != 'postgres' }}
run: |
python ./tests.py
cd test_project
+7 -7
View File
@@ -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 <your domain>
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
+17
View File
@@ -108,6 +108,23 @@ Rebuild Virtual Environment
Specific instructions
*********************
2.2.0
=====
.. 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.
If you use Postgresql, you need to install pyscopg3+:
.. sourcecode:: bash
pip install psycopg[binary]>=3.1
2.1.0
=====
+7 -7
View File
@@ -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:
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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] = ""
+1 -1
View File
@@ -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
+91 -91
View File
@@ -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)
+1 -1
View File
@@ -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",
+23 -23
View File
@@ -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):
+7 -7
View File
@@ -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(
+22 -22
View File
@@ -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
+2 -2
View File
@@ -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"})
+5 -5
View File
@@ -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")
)
+7 -7
View File
@@ -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"
)
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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:
@@ -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"]))()
@@ -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
@@ -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
@@ -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:
+9 -9
View File
@@ -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)
)
+18 -17
View File
@@ -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)
@@ -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()
}
@@ -339,7 +340,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 +398,7 @@ class Domain(mixins.MessageLimitMixin, AdminObject):
result = [
[
"domain",
force_text(self.name),
force_str(self.name),
self.quota,
self.default_mailbox_quota,
self.enabled
+9 -9
View File
@@ -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
+9 -9
View File
@@ -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)
+15 -24
View File
@@ -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"])
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
+2 -2
View File
@@ -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"))
}
+6 -6
View File
@@ -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):
+2 -2
View File
@@ -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")
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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)
)
+2 -2
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+9 -9
View File
@@ -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)
+1 -1
View File
@@ -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
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -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)
+1 -1
View File
@@ -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 "
+10 -10
View File
@@ -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"
+1 -1
View File
@@ -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
+3 -2
View File
@@ -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
+8 -8
View File
@@ -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"})
)
+4 -4
View File
@@ -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()
@@ -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
@@ -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"),
),
]
+19 -21
View File
@@ -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)
+2 -2
View File
@@ -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()]
+3 -3
View File
@@ -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.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)
+3 -3
View File
@@ -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.
+5 -5
View File
@@ -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
+19 -30
View File
@@ -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()
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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"
@@ -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")
]
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+3 -3
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+5 -10
View File
@@ -14,14 +14,13 @@ import tldextract
from defusedxml.ElementTree import fromstring
from dns import resolver, reversename
import magic
import pytz.exceptions
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 +56,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 ""
@@ -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:
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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()
+2 -2
View File
@@ -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
@@ -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(
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+3 -3
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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")
+3 -3
View File
@@ -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):
+1 -1
View File
@@ -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
+5 -5
View File
@@ -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:"):
+1 -1
View File
@@ -4,7 +4,7 @@
"""
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
class ModoboaException(Exception):
+4 -4
View File
@@ -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):
+3 -3
View File
@@ -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"
+1 -1
View File
@@ -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
+10 -6
View File
@@ -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)}
)
+2 -2
View File
@@ -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",
+2 -2
View File
@@ -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 "<h5%s>%s</h5>" % (visirule(field), smart_text(field.label))
return "<h5%s>%s</h5>" % (visirule(field), smart_str(field.label))
configure_field_classes(field)
context = {
"field": field, "help_display_mode": help_display_mode,
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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
+2 -2
View File
@@ -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)
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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():
+1 -1
View File
@@ -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", {
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
+1 -1
View File
@@ -4,7 +4,7 @@
"""
from django.utils.translation import ugettext as _
from django.utils.translation import gettext as _
from modoboa.lib.exceptions import ModoboaException

Some files were not shown because too many files have changed in this diff Show More