Merge branch 'master' into patch-1

This commit is contained in:
Antoine Nguyen
2022-09-17 11:02:30 +02:00
committed by GitHub
23 changed files with 190 additions and 217 deletions
+1
View File
@@ -13,6 +13,7 @@ modoboa.iml
.tox
.eggs/
modoboa_test
bin/instance
.coverage
./build/
dist/
+2 -2
View File
@@ -6,7 +6,7 @@
Modoboa is a mail hosting and management platform including a modern
and simplified Web User Interface. It provides useful components such
as an administration panel or a webmail.
as an administration panel and webmail.
Modoboa integrates with well known software such as `Postfix
<http://postfix.org/>`_ or `Dovecot <http://dovecot.org/>`_. A SQL
@@ -53,7 +53,7 @@ If you want to try out Modoboa, check out our `demo installation <https://demo.m
Getting help
************
If you have any question, you can use the following ways to get help:
If you have any questions, you can get help through the following platforms:
* `Discord <https://discord.gg/WuQ3v3PXGR>`_
* Mailing list: join the `modoboa-users <https://groups.google.com/forum/#!forum/modoboa-users>`_ group on Google Groups
+28 -6
View File
@@ -147,11 +147,22 @@ MySQL users
default_pass_scheme = CRYPT
password_query = SELECT email AS user, password FROM core_user WHERE email='%Lu' and is_active=1
password_query = \
SELECT email AS user, password \
FROM core_user u \
INNER JOIN admin_mailbox mb ON u.id=mb.user_id \
INNER JOIN admin_domain dom ON mb.domain_id=dom.id \
WHERE u.email='%L{user}' AND u.is_active=1 AND dom.enabled=1
user_query = SELECT '<mailboxes storage directory>/%Ld/%Ln' AS home, <uid> as uid, <gid> as gid, concat('*:bytes=', mb.quota, 'M') AS quota_rule FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.address='%Ln' AND dom.name='%Ld'
user_query = \
SELECT '<mailboxes storage directory>/%Ld/%Ln' AS home, \
<uid> as uid, <gid> as gid, CONCAT('*:bytes=', mb.quota, 'M') AS quota_rule \
FROM admin_mailbox mb \
INNER JOIN admin_domain dom ON mb.domain_id=dom.id \
INNER JOIN core_user u ON mb.user_id=u.id \
WHERE mb.address='%L{username}' AND dom.name='%L{domain}' AND u.is_active=1 AND dom.enabled=1
iterate_query = SELECT email AS user FROM core_user
iterate_query = SELECT email AS user FROM core_user WHERE is_active
.. _dovecot_pg_queries:
@@ -166,11 +177,22 @@ PostgreSQL users
default_pass_scheme = CRYPT
password_query = SELECT email AS user, password FROM core_user u INNER JOIN admin_mailbox mb ON u.id=mb.user_id INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE u.email='%Lu' AND u.is_active AND dom.enabled
password_query = \
SELECT email AS user, password \
FROM core_user u \
INNER JOIN admin_mailbox mb ON u.id=mb.user_id \
INNER JOIN admin_domain dom ON mb.domain_id=dom.id \
WHERE u.email='%L{user}' AND u.is_active AND dom.enabled
user_query = SELECT '<mailboxes storage directory>/%Ld/%Ln' AS home, <uid> as uid, <gid> as gid, '*:bytes=' || mb.quota || 'M' AS quota_rule FROM admin_mailbox mb INNER JOIN admin_domain dom ON mb.domain_id=dom.id WHERE mb.address='%Ln' AND dom.name='%Ld'
user_query = \
SELECT '<mailboxes storage directory>/%Ld/%Ln' AS home, \
<uid> as uid, <gid> as gid, CONCAT('*:bytes=', mb.quota, 'M') AS quota_rule \
FROM admin_mailbox mb \
INNER JOIN admin_domain dom ON mb.domain_id=dom.id \
INNER JOIN core_user u ON mb.user_id=u.id \
WHERE mb.address='%L{username}' AND dom.name='%L{domain}' AND u.is_active AND dom.enabled
iterate_query = SELECT email AS user FROM core_user
iterate_query = SELECT email AS user FROM core_user WHERE is_active
SQLite users
------------
+12
View File
@@ -235,11 +235,23 @@ following content inside:
0 0 * * * modoboa $PYTHON $INSTANCE/manage.py clearsessions
# Logs table cleanup
0 0 * * * modoboa $PYTHON $INSTANCE/manage.py cleanlogs
# Logs parsing
*/15 * * * * root $PYTHON $INSTANCE/manage.py logparser &> /dev/null
0 * * * * modoboa $PYTHON $INSTANCE/manage.py update_statistics
# DNSBL checks
*/30 * * * * modoboa $PYTHON $INSTANCE/manage.py modo check_mx
# Public API communication
0 * * * * modoboa $PYTHON $INSTANCE/manage.py communicate_with_public_api
.. hint:: **🥵 potential high load configuration**
Please note that above crontab might not be ideal on high load systems.
If you receive a fairly high amount of emails per day, you may want to
run modoboas logparser tasks *once per night*.
This has the down side that the statistic graph and message log within
the UI are updated once per day only.
.. _policy_daemon:
Policy daemon
+1 -1
View File
@@ -1 +1 @@
docutils<0.19
docutils<0.20
+1 -1
View File
@@ -247,7 +247,7 @@ export default {
created () {
parameters.getApplications().then(response => {
response.data.forEach(item => {
this.mainMenuItems[4].children.push({
this.mainMenuItems[5].children.push({
text: item.label,
to: { name: 'ParametersEdit', params: { app: item.name } }
})
@@ -84,7 +84,8 @@ export default {
active: 0,
structure: [],
parameters: {},
formErrors: {}
formErrors: {},
label: ''
}
},
computed: {
@@ -93,15 +94,7 @@ export default {
return result
},
title () {
let result = this.$gettext('Settings: ')
if (this.$route.params.app === 'core') {
result += this.$gettext('General')
} else if (this.$route.params.app === 'admin') {
result += this.$gettext('Administration')
} else if (this.$route.params.app === 'limits') {
result += this.$gettext('Limitations')
}
return result
return this.$gettext('Settings: ' + this.label)
}
},
created () {
@@ -118,7 +111,8 @@ export default {
this.structure = response.data
})
parameters.getApplication(app).then(response => {
this.parameters = response.data
this.parameters = response.data.params
this.label = response.data.label
})
},
display (element) {
+12 -12
View File
@@ -2415,9 +2415,9 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.6:
node-releases "^1.1.71"
buffer-from@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
version "1.1.2"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer-indexof@^1.0.0:
version "1.1.1"
@@ -8577,9 +8577,9 @@ shebang-regex@^3.0.0:
integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
shell-quote@^1.6.1:
version "1.7.2"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
version "1.7.3"
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==
shelljs@^0.8.3:
version "0.8.5"
@@ -8711,9 +8711,9 @@ source-map-resolve@^0.5.0:
urix "^0.1.0"
source-map-support@^0.5.13, source-map-support@~0.5.12:
version "0.5.19"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
version "0.5.21"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
dependencies:
buffer-from "^1.0.0"
source-map "^0.6.0"
@@ -9179,9 +9179,9 @@ terser-webpack-plugin@^1.4.3, terser-webpack-plugin@^1.4.4:
worker-farm "^1.7.0"
terser@^4.1.2:
version "4.8.0"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==
version "4.8.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f"
integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==
dependencies:
commander "^2.20.0"
source-map "~0.6.1"
+2 -1
View File
@@ -94,6 +94,7 @@ class AdminParametersForm(param_forms.AdminParametersForm):
custom_dns_server = GenericIPAddressField(
label=ugettext_lazy("Custom DNS server"),
required=False,
initial="",
help_text=ugettext_lazy(
"Use a custom DNS server instead of local server configuration"
)
@@ -341,7 +342,7 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([
)
}),
("enable_autoconfig_checks", {
"label": ugettext_lazy("Enable SPF checks"),
"label": ugettext_lazy("Enable autoconfig checks"),
"help_text": ugettext_lazy(
"Check if every domain has a valid records for "
"autoconfiguration"
+7 -3
View File
@@ -13,6 +13,7 @@ from modoboa.lib import fields as lib_fields
from ... import constants
from ... import models
from ... import sms_backends
from ... import app_settings
class CoreGlobalParametersSerializer(serializers.Serializer):
@@ -44,7 +45,7 @@ class CoreGlobalParametersSerializer(serializers.Serializer):
required=False, allow_blank=True)
sms_password_recovery = serializers.BooleanField(default=False)
sms_provider = serializers.ChoiceField(
choices=constants.SMS_BACKENDS, required=False)
choices=constants.SMS_BACKENDS, required=False, allow_null=True)
# LDAP settings
ldap_server_address = serializers.CharField(default="localhost")
@@ -106,7 +107,8 @@ class CoreGlobalParametersSerializer(serializers.Serializer):
)
# Dashboard settings
rss_feed_url = serializers.URLField(allow_blank=True)
rss_feed_url = serializers.URLField(
allow_blank=True, required=False, allow_null=True)
hide_features_widget = serializers.BooleanField(default=False)
# Notification settings
@@ -126,7 +128,7 @@ class CoreGlobalParametersSerializer(serializers.Serializer):
log_maximum_age = serializers.IntegerField(default=365)
items_per_page = serializers.IntegerField(default=30)
default_top_redirection = serializers.ChoiceField(
default="user", choices=[""])
default="user", choices=[("user", _("User profile"))], required=False)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
@@ -134,6 +136,8 @@ class CoreGlobalParametersSerializer(serializers.Serializer):
for field, definition in sms_backend_fields.items():
self.fields[field] = definition["type"](
**definition["attrs"])
# Choices serializer for default_top_redirection field
self.fields["default_top_redirection"].choices = app_settings.enabled_applications()
def validate_ldap_user_dn_template(self, value):
try:
+1 -1
View File
@@ -58,7 +58,7 @@ CORE_SETTINGS = {
"top_notifications_check_interval": 30,
"log_maximum_age": 365,
"items_per_page": 30,
"default_top_redirection": ""
"default_top_redirection": "user"
}
+9 -3
View File
@@ -75,19 +75,25 @@ class OVHBackend(SMSBackend):
"sms_ovh_application_key": {
"type": serializers.CharField,
"attrs": {
"required": False
"required": False,
"allow_blank": True,
"allow_null": True,
}
},
"sms_ovh_application_secret": {
"type": serializers.CharField,
"attrs": {
"required": False
"required": False,
"allow_blank": True,
"allow_null": True,
}
},
"sms_ovh_consumer_key": {
"type": serializers.CharField,
"attrs": {
"required": False
"required": False,
"allow_blank": True,
"allow_null": True,
}
}
}
-2
View File
@@ -253,8 +253,6 @@ class Email(object):
)
mail_text = lxml.html.tostring(
cleaner.clean_html(html), encoding="unicode")
with open("/tmp/output.txt", "w") as fp:
fp.write(mail_text)
return smart_text(mail_text)
def _map_cid(self, url):
+83 -164
View File
@@ -1,24 +1,26 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
#
#
# Translators:
# Antoine Nguyen <tonio@ngyn.org>, 2016-2017,2020
# Christophe CHAUVET <christophe.chauvet@gmail.com>, 2018
# Icarus Flight, 2022
# Jan-Philipp Sprung, 2021
# Jorg722, 2019
msgid ""
msgstr ""
"Project-Id-Version: Modoboa\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-11-05 15:36+0100\n"
"PO-Revision-Date: 2020-11-05 15:49+0100\n"
"Last-Translator: Antoine Nguyen <tonio@ngyn.org>\n"
"PO-Revision-Date: 2011-07-01 08:15+0000\n"
"Last-Translator: Icarus Flight, 2022\n"
"Language-Team: French (http://www.transifex.com/tonio/modoboa/language/fr/)\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Language: fr\n"
"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;\n"
#: core/app_settings.py:26
msgid "User profile"
@@ -46,8 +48,7 @@ msgstr "Méthode de chiffrement par défaut"
#: core/app_settings.py:56
msgid "Scheme used to crypt mailbox passwords"
msgstr ""
"Méthode utilisée pour chiffrer les mots de passe des boites aux lettres"
msgstr "Méthode utilisée pour chiffrer les mots de passe des boites aux lettres"
#: core/app_settings.py:60
msgid "Rounds"
@@ -57,9 +58,7 @@ msgstr "Tours"
msgid ""
"Number of rounds to use (only used by sha256crypt and sha512crypt). Must be "
"between 1000 and 999999999, inclusive."
msgstr ""
"Nombre de tours à utiliser (sha256crypt et sha512crypt uniquement). Doit "
"être compris entre 1000 et 999999999 inclue."
msgstr "Nombre de tours à utiliser (sha256crypt et sha512crypt uniquement). Doit être compris entre 1000 et 999999999 inclue."
#: core/app_settings.py:69
msgid "Update password scheme at login"
@@ -67,9 +66,7 @@ msgstr "Mettre à jour la méthode de chiffrement du mot de passe à la connexio
#: core/app_settings.py:72
msgid "Update user password at login to use the default password scheme"
msgstr ""
"Mise à jour du mot de passe utilisateur lors d'une connexion pour utiliser "
"la méthode de chiffrement par défaut"
msgstr "Mise à jour du mot de passe utilisateur lors d'une connexion pour utiliser la méthode de chiffrement par défaut"
#: core/app_settings.py:77
msgid "Default password"
@@ -96,10 +93,7 @@ msgid ""
"The URL of an external page where users will be able to update their "
"password. It applies only to non local users, ie. those automatically "
"created after a successful external authentication (LDAP, SMTP)."
msgstr ""
"L'URL d'une page externe où les utilisateurs pourront mettre à jour leur mot "
"de passe. Elle s'applique uniquement aux utilisateurs non locaux, c'est à "
"dire ceux créés après une authentification externe réussie (LDAP, SMTP)."
msgstr "L'URL d'une page externe où les utilisateurs pourront mettre à jour leur mot de passe. Elle s'applique uniquement aux utilisateurs non locaux, c'est à dire ceux créés après une authentification externe réussie (LDAP, SMTP)."
#: core/app_settings.py:104
msgid "Password recovery announcement"
@@ -107,9 +101,7 @@ msgstr "Annonce pour la récupération de mot de passe"
#: core/app_settings.py:109
msgid "A temporary message that will be displayed on the reset password page."
msgstr ""
"Un message temporaire qui sera affiché sur la page de récupération de mot de "
"passe"
msgstr "Un message temporaire qui sera affiché sur la page de récupération de mot de passe"
#: core/app_settings.py:115
msgid "Enable password recovery by SMS"
@@ -117,9 +109,7 @@ msgstr "Activer la récupération de mot de passe par SMS"
#: core/app_settings.py:118
msgid "Enable password recovery by SMS for users who filled a phone number."
msgstr ""
"Activer la récupération de mot de passe par SMS pour les utilisateurs ayant "
"renseigné un numéro de téléphone"
msgstr "Activer la récupération de mot de passe par SMS pour les utilisateurs ayant renseigné un numéro de téléphone"
#: core/app_settings.py:124
msgid "SMS provider"
@@ -127,8 +117,7 @@ msgstr "Fournisseur SMS"
#: core/app_settings.py:127
msgid "Choose a provider to send password recovery SMS"
msgstr ""
"Choisir un fournisseur pour envoyer les SMS de récupération de mot de passe"
msgstr "Choisir un fournisseur pour envoyer les SMS de récupération de mot de passe"
#: core/app_settings.py:133
msgid "LDAP settings"
@@ -157,9 +146,7 @@ msgstr "Activer le serveur secondaire (secours)"
#: core/app_settings.py:152
msgid ""
"Enable a secondary LDAP server which will be used if the primary one fails"
msgstr ""
"Activer un serveur LDAP secondaire qui sera utilisé si le principal est en "
"échec"
msgstr "Activer un serveur LDAP secondaire qui sera utilisé si le principal est en échec"
#: core/app_settings.py:158
msgid "Secondary server address"
@@ -199,12 +186,9 @@ msgstr "Groupes administrateurs"
#: core/app_settings.py:190
msgid ""
"Members of those LDAP Posix groups will be created as domain administrators. "
"Use ';' characters to separate groups."
msgstr ""
"Les membres de ces groupes LDAP (Posix) seront créés en tant "
"qu'administrateurs de domaine. Utiliser des caractères ';' pour séparer les "
"groupes."
"Members of those LDAP Posix groups will be created as domain administrators."
" Use ';' characters to separate groups."
msgstr "Les membres de ces groupes LDAP (Posix) seront créés en tant qu'administrateurs de domaine. Utiliser des caractères ';' pour séparer les groupes."
#: core/app_settings.py:197
msgid "Group type"
@@ -220,9 +204,7 @@ msgstr "Base de recherche des groupes"
#: core/app_settings.py:209
msgid "The distinguished name of the search base used to find groups"
msgstr ""
"Le nom distinctif de la base de recherche utilisée pour rechercher les "
"groupes"
msgstr "Le nom distinctif de la base de recherche utilisée pour rechercher les groupes"
#: core/app_settings.py:215
msgid "Password attribute"
@@ -260,9 +242,7 @@ msgstr "ND de connexion"
msgid ""
"The distinguished name to use when binding to the LDAP server. Leave empty "
"for an anonymous bind"
msgstr ""
"Le nom distinctif à utiliser pour les connections au serveur LDAP. Laisser "
"vide pour une connexion anonyme"
msgstr "Le nom distinctif à utiliser pour les connections au serveur LDAP. Laisser vide pour une connexion anonyme"
#: core/app_settings.py:243 core/app_settings.py:297
msgid "Bind password"
@@ -270,9 +250,7 @@ msgstr "Mot de passe de connexion"
#: core/app_settings.py:246 core/app_settings.py:300
msgid "The password to use when binding to the LDAP server (with 'Bind DN')"
msgstr ""
"Le mot de passe à utiliser pour les connections au serveur LDAP (avec 'ND de "
"connexion')"
msgstr "Le mot de passe à utiliser pour les connections au serveur LDAP (avec 'ND de connexion')"
#: core/app_settings.py:254 core/app_settings.py:346
msgid "Users search base"
@@ -280,9 +258,7 @@ msgstr "Base de recherche des utilisateurs"
#: core/app_settings.py:257 core/app_settings.py:349
msgid "The distinguished name of the search base used to find users"
msgstr ""
"Le nom distinctif de la base de recherche utilisée pour rechercher les "
"utilisateurs"
msgstr "Le nom distinctif de la base de recherche utilisée pour rechercher les utilisateurs"
#: core/app_settings.py:263 core/app_settings.py:355
msgid "Search filter"
@@ -292,9 +268,7 @@ msgstr "Filtre de recherche"
msgid ""
"An optional filter string (e.g. '(objectClass=person)'). In order to be "
"valid, it must be enclosed in parentheses."
msgstr ""
"Un filtre de recherche optionel (ex. '(objectClass=person)'). Pour être "
"valide, il doit être entouré de parenthèses."
msgstr "Un filtre de recherche optionel (ex. '(objectClass=person)'). Pour être valide, il doit être entouré de parenthèses."
#: core/app_settings.py:273
msgid "User DN template"
@@ -305,9 +279,7 @@ msgstr "Modèle de nom distinctif utilisateur"
msgid ""
"The template used to construct a user's DN. It should contain one "
"placeholder (ie. %(user)s)"
msgstr ""
"Le modèle utilisé pour construire le nom distinctif d'un utilisateur. Il "
"doit contenir un espace réservé (ex. %(user)s)"
msgstr "Le modèle utilisé pour construire le nom distinctif d'un utilisateur. Il doit contenir un espace réservé (ex. %(user)s)"
#: core/app_settings.py:284
msgid "LDAP synchronization settings"
@@ -320,9 +292,7 @@ msgstr "Activer l'export LDAP"
#: core/app_settings.py:311
msgid ""
"Enable automatic synchronization between local database and LDAP directory"
msgstr ""
"Activer la synchronisation automatique entre la base de données locale et "
"l'annuaire LDAP"
msgstr "Activer la synchronisation automatique entre la base de données locale et l'annuaire LDAP"
#: core/app_settings.py:317
msgid "Delete remote LDAP account when local account is deleted"
@@ -332,9 +302,7 @@ msgstr "Supprimer un compte LDAP distant lorsqu'un compte local est supprimé"
msgid ""
"Delete remote LDAP account when local account is deleted, otherwise it will "
"be disabled."
msgstr ""
"Supprimer un compte LDAP distant lorsqu'un compte local supprimé, autrement "
"il sera désactivé."
msgstr "Supprimer un compte LDAP distant lorsqu'un compte local supprimé, autrement il sera désactivé."
#: core/app_settings.py:327
msgid "Account DN template"
@@ -345,9 +313,7 @@ msgstr "Modèle des DN de compte"
msgid ""
"The template used to construct an account's DN. It should contain one "
"placeholder (ie. %(user)s)"
msgstr ""
"Le modèle utilisé pour construite un DN de compte (nom unique). Il doit "
"contenir un emplacement (c'est à dire 1%(user)s)"
msgstr "Le modèle utilisé pour construite un DN de compte (nom unique). Il doit contenir un emplacement (c'est à dire 1%(user)s)"
#: core/app_settings.py:337
msgid "Enable import from LDAP"
@@ -355,9 +321,7 @@ msgstr "Activer l'import LDAP"
#: core/app_settings.py:340
msgid "Enable account synchronization from LDAP directory to local database"
msgstr ""
"Activer la synchronisation des comptes entre un annuaire LDAP et la base de "
"données locale"
msgstr "Activer la synchronisation des comptes entre un annuaire LDAP et la base de données locale"
#: core/app_settings.py:365
msgid "Username attribute"
@@ -365,8 +329,7 @@ msgstr "Attribut nom d'utilisateur"
#: core/app_settings.py:368
msgid "The name of the LDAP attribute where the username can be found."
msgstr ""
"Le nom de l'attribut LDAP dans lequel le nom d'utilisateur peut être trouvé."
msgstr "Le nom de l'attribut LDAP dans lequel le nom d'utilisateur peut être trouvé."
#: core/app_settings.py:373
msgid "Enable Dovecot LDAP sync"
@@ -374,9 +337,7 @@ msgstr "Activer la synchronisation LDAP pour Dovecot"
#: core/app_settings.py:376
msgid "LDAP authentication settings will be applied to Dovecot configuration."
msgstr ""
"Les paramètres d'authentification LDAP seront appliqués à la configuration "
"de Dovecot."
msgstr "Les paramètres d'authentification LDAP seront appliqués à la configuration de Dovecot."
#: core/app_settings.py:382
msgid "Dovecot LDAP config file"
@@ -385,9 +346,7 @@ msgstr "Fichier de configuration Dovecot pour LDAP"
#: core/app_settings.py:386
msgid ""
"Location of the configuration file which contains Dovecot LDAP settings."
msgstr ""
"Emplacement du fichier de configuration qui contient les paramètres LDAP de "
"Dovecot"
msgstr "Emplacement du fichier de configuration qui contient les paramètres LDAP de Dovecot"
#: core/app_settings.py:391 core/templates/core/dashboard.html:5
msgid "Dashboard"
@@ -399,9 +358,7 @@ msgstr "Flux RSS personnalisé"
#: core/app_settings.py:397
msgid "Display custom RSS feed to resellers and domain administrators"
msgstr ""
"Afficher un flux RSS personnalisé aux revendeurs et administrateurs de "
"domaine"
msgstr "Afficher un flux RSS personnalisé aux revendeurs et administrateurs de domaine"
#: core/app_settings.py:402
msgid "Hide features widget"
@@ -409,9 +366,7 @@ msgstr "Masquer le widget des fonctionnalités"
#: core/app_settings.py:405
msgid "Hide features widget for resellers and domain administrators"
msgstr ""
"Masquer le widget des fonctionnalités pour les revendeurs et les "
"administrateurs de domaine"
msgstr "Masquer le widget des fonctionnalités pour les revendeurs et les administrateurs de domaine"
#: core/app_settings.py:409
msgid "Notifications"
@@ -451,9 +406,7 @@ msgstr "Envoyer un email quand de nouvelles versions sont trouvées"
#: core/app_settings.py:439
msgid "Send an email to notify admins about new versions"
msgstr ""
"Envoyer un email pour notifier les administrateurs à propos des nouvelles "
"versions"
msgstr "Envoyer un email pour notifier les administrateurs à propos des nouvelles versions"
#: core/app_settings.py:443
msgid "Recipient"
@@ -469,9 +422,7 @@ msgstr "Envoyer des statistiques"
#: core/app_settings.py:454
msgid "Send statistics to Modoboa public API (counters and used extensions)"
msgstr ""
"Envoyer des statistiques à l'API publique de Modoboa (compteurs et "
"extensions utilisées)"
msgstr "Envoyer des statistiques à l'API publique de Modoboa (compteurs et extensions utilisées)"
#: core/app_settings.py:458
msgid "Miscellaneous"
@@ -483,11 +434,9 @@ msgstr "Seuil des comptes inactifs"
#: core/app_settings.py:464
msgid ""
"An account with a last login date greater than this threshold (in days) will "
"be considered as inactive"
msgstr ""
"Un compte avec une date de dernière connexion antérieure à ce seuil sera "
"considéré comme inactif"
"An account with a last login date greater than this threshold (in days) will"
" be considered as inactive"
msgstr "Un compte avec une date de dernière connexion antérieure à ce seuil sera considéré comme inactif"
#: core/app_settings.py:470
msgid "Top notifications check interval"
@@ -519,8 +468,7 @@ msgstr "Redirection par défaut"
#: core/app_settings.py:494
msgid "The default redirection used when no application is specified"
msgstr ""
"La redirection appliquée par défaut quand aucune application n'est spécifiée"
msgstr "La redirection appliquée par défaut quand aucune application n'est spécifiée"
#: core/app_settings.py:548 core/app_settings.py:556 core/app_settings.py:564
msgid "Invalid syntax"
@@ -543,10 +491,7 @@ msgid ""
"You have USE_TZ set to False, this may result in issues during transitions "
"between summer/winter time (ie the same local time occuring twice due to "
"clock change)."
msgstr ""
"Vous avez défini USE_TZ à False, ce qui peut entraîner des problèmes lors "
"des transitions entre l'heure d'été et l'heure d'hiver (c.-à-d. La même "
"heure locale se produisant deux fois en raison d'un changement d'horloge)."
msgstr "Vous avez défini USE_TZ à False, ce qui peut entraîner des problèmes lors des transitions entre l'heure d'été et l'heure d'hiver (c.-à-d. La même heure locale se produisant deux fois en raison d'un changement d'horloge)."
#: core/checks/settings_checks.py:9
msgid "Set `USE_TZ = True` in settings.py"
@@ -622,7 +567,7 @@ msgstr "Code incorrect"
#: core/forms.py:163
msgid "This code is invalid"
msgstr "Ce code est incorrect"
msgstr "Ce code n'est pas valide"
#: core/handlers.py:36
msgid "added"
@@ -700,8 +645,7 @@ msgstr "Une adresse e-mail alternative ou de secours."
#: core/models.py:126
msgid "Failed to update password: LDAP module not installed"
msgstr ""
"Echec de la mise à jour du mot de passe : le module LDAP n'est pas installé"
msgstr "Echec de la mise à jour du mot de passe : le module LDAP n'est pas installé"
#: core/models.py:155
msgid "account"
@@ -734,38 +678,40 @@ msgid "Password must contain at least {} digit."
msgid_plural "Password must contain at least {} digits."
msgstr[0] "Le mot de passe doit contenir au moins {} chiffre."
msgstr[1] "Le mot de passe doit contenir au moins {} chiffres."
msgstr[2] "Le mot de passe doit contenir au moins {} chiffres."
#: core/password_validation.py:34
msgid "Password must contain at least {} lowercase letter."
msgid_plural "Password must contain at least {} lowercase letters."
msgstr[0] "Le mot de passe doit contenir au moins {} minuscule."
msgstr[1] "Le mot de passe doit contenir au moins {} minuscules."
msgstr[2] "Le mot de passe doit contenir au moins {} minuscules."
#: core/password_validation.py:45
msgid "Password must contain at least {} uppercase letter."
msgid_plural "Password must contain at least {} uppercase letters."
msgstr[0] "Le mot de passe doit contenir au moins {} majuscule."
msgstr[1] "Le mot de passe doit contenir au moins {} majuscules."
msgstr[2] "Le mot de passe doit contenir au moins {} majuscules."
#: core/password_validation.py:57
msgid "Password must contain at least {} special character."
msgid_plural "Password must contain at least {} special characters."
msgstr[0] "Le mot de passe doit contenir au moins {} caractère spécial."
msgstr[1] "Le mot de passe doit contenir au moins {} caractères spéciaux."
msgstr[2] "Le mot de passe doit contenir au moins {} caractères spéciaux."
#: core/password_validation.py:65
msgid "Your password must contain a combination of different character types."
msgstr ""
"Votre mot de passe doit contenir une combinaison de différents types de "
"caractère."
msgstr "Votre mot de passe doit contenir une combinaison de différents types de caractère."
#: core/serializers.py:15
msgid "Invalid PIN code"
msgstr "Code PIN incorrect"
msgstr "Code PIN non valide"
#: core/serializers.py:21
msgid "2FA is already enabled"
msgstr "La 2FA est déjà activée"
msgstr "2FA est déjà activf"
#: core/sms_backends/ovh.py:19
msgid "API endpoint"
@@ -835,9 +781,7 @@ msgstr "Dernières nouvelles"
msgid ""
"Visit the <a href=\"https://modoboa.org/blog/\" target=\"_blank\">official "
"weblog</a> for more information."
msgstr ""
"Visitez le <a href=\"https://modoboa.org/blog/\" target=\"_blank\">blog "
"officiel</a> pour plus d'information."
msgstr "Visitez le <a href=\"https://modoboa.org/blog/\" target=\"_blank\">blog officiel</a> pour plus d'information."
#: core/templates/core/api_access.html:3
msgid "API access"
@@ -850,11 +794,9 @@ msgstr "Contrôlez votre accès à l'API de Modoboa"
#: core/templates/core/api_access.html:7
#, python-format
msgid ""
"A documentation of the API is available <strong><a href=\"%(url)s\" target="
"\"_blank\">here</a></strong>."
msgstr ""
"Une documentation de l'API est disponible <strong><a href=\"%(url)s\" target="
"\"_blank\">ici</a></strong>."
"A documentation of the API is available <strong><a href=\"%(url)s\" "
"target=\"_blank\">here</a></strong>."
msgstr "Une documentation de l'API est disponible <strong><a href=\"%(url)s\" target=\"_blank\">ici</a></strong>."
#: core/templates/core/api_access.html:14
msgid "API access token"
@@ -884,8 +826,7 @@ msgstr "Une ou plusieurs mises à jour sont disponibles!"
#: core/templates/core/information.html:6
msgid "Check the following list to find the component(s) that can be updated."
msgstr ""
"Consulter la liste suivante pour trouver le(s) composant(s) concerné(s)."
msgstr "Consulter la liste suivante pour trouver le(s) composant(s) concerné(s)."
#: core/templates/core/information.html:10
msgid "Applications"
@@ -951,12 +892,9 @@ msgid ""
msgid_plural ""
"\n"
" The following updates are available:\n"
msgstr[0] ""
"\n"
"La mise à jour suivante est disponible :\n"
msgstr[1] ""
"\n"
"Les mises à jour suivantes sont disponibles :\n"
msgstr[0] "\nLa mise à jour suivante est disponible :\n"
msgstr[1] "\nLes mises à jour suivantes sont disponibles :\n"
msgstr[2] "\nLes mises à jour suivantes sont disponibles :\n"
#: core/templates/core/parameters.html:2 core/templatetags/core_tags.py:71
msgid "Parameters"
@@ -1010,13 +948,13 @@ msgstr "Sécurité"
#: core/templates/core/user_security.html:6
msgid "Two-Factor authentication"
msgstr "Authentification à double facteur"
msgstr "Authentification à deux facteurs"
#: core/templates/core/user_security.html:17
msgid ""
"Install a soft token authenticator like FreeOTP or Google Authenticator from "
"your application repository and use that app to scan this QR code."
msgstr "Installer une application de génération de mots de passe à usage unique comme FreeOTP ou Google Athenticator depuis votre magasin d'applications et utiliser le pour scanner ce code QR."
"Install a soft token authenticator like FreeOTP or Google Authenticator from"
" your application repository and use that app to scan this QR code."
msgstr "Installez une application d'authentification par jetons comme FreeOTP ou Google Authenticator à partir de votre appstore et utilisez-la pour scanner ce QR code."
#: core/templates/core/user_security.html:25
msgid "Pin code"
@@ -1024,12 +962,12 @@ msgstr "Code PIN"
#: core/templates/core/user_security.html:28
msgid "Register"
msgstr "Enregistrer"
msgstr "Enregistrement"
#: core/templates/core/user_security.html:33
msgid ""
"Congratulations! Two-Factor Authentication is now enabled for your account."
msgstr "Félicitations ! L'authentification à double facteur est activée pour votre compte."
msgstr "Félicitations ! L'authentification à deux facteurs est maintenant activée pour votre compte."
#: core/templates/core/user_security.html:38
#: core/templates/core/user_security.html:89
@@ -1038,34 +976,35 @@ msgid ""
"access to your account, in case you lose your phone for example. Make sure "
"to save them in a safe place, otherwise you won't be able to access your "
"account anymore."
msgstr "Les codes de récuparation suivants peuvent être utilisés une fois chacun pour récupérer l'accès à votre compte, par exemple si vous perdez votre téléphone. Assurez vous de les sauvegarder dans un endroit sûr, autrement vous ne pourrez plus accéder à votre compte."
msgstr "Les codes de récupération suivants peuvent être utilisés une fois chacun pour vous permettre de récupérer un accès à votre compte, au cas où vous perdriez votre téléphone par exemple. Assurez-vous de les conserver dans un lieu sûr, autrement vous ne serez définitivement plus en mesure d'accéder à votre compte."
#: core/templates/core/user_security.html:53
msgid "Two-Factor Authentication is enabled for your account."
msgstr "L'authentication à double facteur est activée pour votre compte."
msgstr "L'authentification à deux facteurs est activée pour votre compte."
#: core/templates/core/user_security.html:58
msgid "Disable 2FA"
msgstr "Désactiver la 2FA"
msgstr "Désactiver authentification à 2 facteurs."
#: core/templates/core/user_security.html:61
msgid "Reset recovery codes"
msgstr "Réinitialiser les codes de récupération"
msgstr "Réinitialiser les codes de récupération."
#: core/templates/core/user_security.html:65
msgid ""
"Two-Factor Authentication (2FA) is not yet activated for your account. "
"Enabling this feature will increase your account's security."
msgstr "L'authentification à double facteur (2FA) n'est pas encore activée pour votre compte. Activer cette fonctionnalité améliorera la sécurité de votre compte."
msgstr "L'authentification à 2 facteurs n'est pas encore activée pour votre compte. Activer cette fonctionnalité renforcera la sécurité de votre compte."
#: core/templates/core/user_security.html:73
msgid "Enable 2FA"
msgstr "Activer la 2FA"
msgstr "Activer authentification à 2 facteurs."
#: core/templates/core/user_security.html:83
#: core/templates/core/user_security.html:99
#: templates/common/generic_modal.html:6 templates/common/generic_modal.html:13
#: templates/common/wizard_forms.html:6 templates/common/wizard_forms.html:27
#: templates/common/generic_modal.html:6
#: templates/common/generic_modal.html:13 templates/common/wizard_forms.html:6
#: templates/common/wizard_forms.html:27
msgid "Close"
msgstr "Fermer"
@@ -1075,7 +1014,7 @@ msgstr "Nouveaux codes de récupération"
#: core/templates/core/user_security.html:88
msgid "Here are your new recovery codes. "
msgstr "Voici vos nouveaux codes de récupération."
msgstr "Vous trouverez ici vos nouveaux codes de récupération."
#: core/templatetags/core_tags.py:34
msgid "Modoboa"
@@ -1100,14 +1039,12 @@ msgstr "Paramètres enregistrés"
#: core/views/auth.py:61
#, python-format
msgid "Password scheme mismatch. Updating %s password"
msgstr ""
"La méthode de chiffrement du mot de passe diffère. Mise à jour du mot de "
"passe de %s"
msgstr "La méthode de chiffrement du mot de passe diffère. Mise à jour du mot de passe de %s"
#: core/views/auth.py:68
#, python-format
msgid "Password hash parameter missmatch. Updating %s password"
msgstr ""
msgstr "Le paramètre de hash du mot de passe ne correspond pas. Mise à jour %s du mot de passe"
#: core/views/auth.py:84
#, python-format
@@ -1116,9 +1053,7 @@ msgstr "Utiliseur '%s' connecté avec succès"
#: core/views/auth.py:92
msgid "Your username and password didn't match. Please try again."
msgstr ""
"Votre nom d'utilisateur et mot de passe ne correspondent pas. Veuillez "
"réessayer."
msgstr "Votre nom d'utilisateur et mot de passe ne correspondent pas. Veuillez réessayer."
#: core/views/auth.py:127
msgid "User '{}' successfully logged out"
@@ -1126,9 +1061,7 @@ msgstr "Utilisateur '{}' déconnecté avec succès"
#: core/views/auth.py:172 core/views/auth.py:227
msgid "Please use the following code to recover your Modoboa password: {}"
msgstr ""
"Veuillez utiliser le code suivant pour récupérer votre mot de passe "
"Modoboa : {}"
msgstr "Veuillez utiliser le code suivant pour récupérer votre mot de passe Modoboa : {}"
#: core/views/user.py:60
msgid "Profile updated"
@@ -1144,7 +1077,7 @@ msgstr "Accès mis à jour"
#: core/viewsets.py:52
msgid "2FA is not enabled"
msgstr "La 2FA n'est pas activée"
msgstr "Authentification 2 facteurs non activée"
#: lib/db_utils.py:23
#, python-format
@@ -1265,9 +1198,7 @@ msgstr "Mot de passe oublié ?"
msgid ""
"Your password has been set. You may go ahead and <a href=\"%(url)s\">sign "
"in</a> now."
msgstr ""
"Votre mot de passe a été défini. Vous pouvez continuer et vous <a href="
"\"%(url)s\">connecter </a> dès maintenant."
msgstr "Votre mot de passe a été défini. Vous pouvez continuer et vous <a href=\"%(url)s\">connecter </a> dès maintenant."
#: templates/registration/password_reset_confirm.html:7
msgid "Change password"
@@ -1277,10 +1208,7 @@ msgstr "Changer le mot de passe"
msgid ""
"The password reset link was invalid, possibly because it has already been "
"used. Please request a new password reset."
msgstr ""
"Le lien de réinitialisation du mot de passe était invalide, probablement "
"parce qu'il a déjà été utilisé. Merci de demander une nouvelle "
"réinitialisation de mot de passe."
msgstr "Le lien de réinitialisation du mot de passe était invalide, probablement parce qu'il a déjà été utilisé. Merci de demander une nouvelle réinitialisation de mot de passe."
#: templates/registration/password_reset_confirm_code.html:20
msgid "Enter the code you've just received by SMS"
@@ -1296,29 +1224,20 @@ msgid ""
"exists with the email you entered. You should receive them shortly.</p> "
"<p>If you don't receive an email, please make sure you've entered your "
"primary address, and check your spam folder.</p>"
msgstr ""
"<p>Nous vous avons envoyé par email les instructions pour définir votre mot "
"de passe, pour peu qu'un compte avec l'email que vous avez renseigné existe. "
"Vous devriez les recevoir rapidement.</p><p>Si vous ne recevez pas d'email, "
"merci de vérifier que vous avez renseigné votre adresse principale et de "
"vérifier votre dossier spam.</p>"
msgstr "<p>Nous vous avons envoyé par email les instructions pour définir votre mot de passe, pour peu qu'un compte avec l'email que vous avez renseigné existe. Vous devriez les recevoir rapidement.</p><p>Si vous ne recevez pas d'email, merci de vérifier que vous avez renseigné votre adresse principale et de vérifier votre dossier spam.</p>"
#: templates/registration/password_reset_email.html:4
#, python-format
msgid ""
"To initiate the password reset process for your %(username)s Modoboa "
"account, click the link below:"
msgstr ""
"Pour initier la procédure de réinitialisation du mot de passe de votre "
"compte Modoboa %(username)s, cliquez sur le lien ci-dessous :"
msgstr "Pour initier la procédure de réinitialisation du mot de passe de votre compte Modoboa %(username)s, cliquez sur le lien ci-dessous :"
#: templates/registration/password_reset_email.html:10
msgid ""
"If clicking the link above doesn't work, please copy and paste the URL in a "
"new browser window instead."
msgstr ""
"Si cliquer sur lien ci-dessous ne fonctionne pas, merci de copier / coller "
"cette URL dans une nouvelle fenêtre navigateur à la place."
msgstr "Si cliquer sur lien ci-dessous ne fonctionne pas, merci de copier / coller cette URL dans une nouvelle fenêtre navigateur à la place."
#: templates/registration/password_reset_email.html:14
msgid "Sincerely, The Modoboa Team."
+7
View File
@@ -34,3 +34,10 @@ class StructureSerializer(serializers.Serializer):
name = serializers.CharField()
display = serializers.CharField(help_text="Display rule")
parameters = ParameterSerializer(many=True)
class AppParametersSerializer(serializers.Serializer):
"""Serializer for application parameters."""
label = serializers.CharField()
params = serializers.DictField()
+7 -2
View File
@@ -36,14 +36,19 @@ class ParametersViewSet(viewsets.ViewSet):
description='A registered application name',
type=str, required=True
),
]
],
responses=serializers.AppParametersSerializer
)
def retrieve(self, request, pk: str):
"""Return all parameters for given app."""
parameters = request.localconfig.parameters.get_values_dict(pk)
serializer = tools.registry.get_serializer_class("global", pk)(
parameters)
return response.Response(serializer.data)
result = serializers.AppParametersSerializer({
"label": tools.registry.get_label("global", pk),
"params": serializer.data
})
return response.Response(result.data)
@extend_schema(
parameters=[
+3
View File
@@ -63,6 +63,9 @@ class Registry(object):
result = [{"name": key, "label": value["label"]}
for key, value in self._registry2[level].items()]
return result
def get_label(self, level, app):
return self._registry2[level][app]["label"]
def get_forms(self, level, *args, **kwargs):
"""Return form instances for all app of the given level."""
@@ -34,7 +34,7 @@ class Command(BaseCommand):
"""Entry point."""
loop = asyncio.get_event_loop()
coro = asyncio.start_server(
core.new_connection, options["host"], options["port"], loop=loop
core.new_connection, options["host"], options["port"]
)
server = loop.run_until_complete(coro)
+2 -2
View File
@@ -177,7 +177,7 @@ TwocolsNav.prototype = {
startTFASetup: function (evt) {
evt.preventDefault();
$.ajax({
url: '/api/v1/account/tfa/setup/',
url: window.root_url + '/api/v1/account/tfa/setup/',
type: 'post',
contentType: 'application/json'
}).done(function (resp) {
@@ -191,7 +191,7 @@ TwocolsNav.prototype = {
pin_code: $('#pin-code').val()
};
$.ajax({
url: '/api/v1/account/tfa/setup/check/',
url: window.root_url + '/api/v1/account/tfa/setup/check/',
type: 'post',
global: false,
data: JSON.stringify(data),
+1
View File
@@ -87,6 +87,7 @@
<script src="{% static 'js/top_notifications.js' %}" type="text/javascript"></script>
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script type="text/javascript">
var root_url = "{% url 'core:root' %}".replace(/\/$/, "");
var top_notifications;
var userLang = "{{ LANGUAGE_CODE }}";
+1 -1
View File
@@ -1 +1 @@
mysqlclient<2.1.1
mysqlclient<2.1.2
+3 -3
View File
@@ -1,7 +1,7 @@
django<4.0
django-ckeditor==6.3.0
django-phonenumber-field[phonenumbers]==6.1.0
django-reversion==5.0.0
django-phonenumber-field[phonenumbers]==7.0.0
django-reversion==5.0.2
django-xforwardedfor-middleware==2.0
django-otp==1.1.3
django-filter
@@ -19,7 +19,7 @@ bcrypt # Requires libffi-dev and python-dev
asgiref
dnspython==2.2.1
feedparser==6.0.10
greenlet==1.1.2
greenlet==1.1.3
gevent==21.12.0
jsonfield==3.1.0
Pillow # Optional dependency for django-ckeditor
+1 -1
View File
@@ -1,6 +1,6 @@
argon2-cffi>=16.1.0
factory-boy<3.3.0
httmock==1.4.0
testfixtures==6.18.5
testfixtures==7.0.0
tox
asynctest