From fe79982b84dc8560c812e8b2b603c9cd9c246ef2 Mon Sep 17 00:00:00 2001 From: Antoine Nguyen Date: Wed, 6 Aug 2025 13:27:32 +0200 Subject: [PATCH] Allow null values for empty optional fields. Probably due to a recent change in DRF... fix #3631 --- modoboa/admin/api/v2/serializers.py | 4 +-- modoboa/core/api/v2/serializers.py | 49 ++++++++++++++++++++--------- modoboa/core/app_settings.py | 2 +- 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/modoboa/admin/api/v2/serializers.py b/modoboa/admin/api/v2/serializers.py index f41e729d8..e369916f4 100644 --- a/modoboa/admin/api/v2/serializers.py +++ b/modoboa/admin/api/v2/serializers.py @@ -221,9 +221,9 @@ class AdminGlobalParametersSerializer(serializers.Serializer): enable_dkim_checks = serializers.BooleanField(default=True) enable_dmarc_checks = serializers.BooleanField(default=True) enable_autoconfig_checks = serializers.BooleanField(default=True) - custom_dns_server = serializers.IPAddressField(allow_blank=True) + custom_dns_server = serializers.IPAddressField(allow_blank=True, allow_null=True) enable_dnsbl_checks = serializers.BooleanField(default=True) - dkim_keys_storage_dir = serializers.CharField(allow_blank=True) + dkim_keys_storage_dir = serializers.CharField(allow_blank=True, allow_null=True) dkim_default_key_length = serializers.ChoiceField( default=2048, choices=constants.DKIM_KEY_LENGTHS ) diff --git a/modoboa/core/api/v2/serializers.py b/modoboa/core/api/v2/serializers.py index f7ae10682..745c88216 100644 --- a/modoboa/core/api/v2/serializers.py +++ b/modoboa/core/api/v2/serializers.py @@ -76,8 +76,12 @@ class CoreGlobalParametersSerializer(serializers.Serializer): default_password = serializers.CharField(default="ChangeMe1!") random_password_length = serializers.IntegerField(min_value=8, default=8) allow_special_characters = serializers.BooleanField(default=False) - update_password_url = serializers.URLField(required=False, allow_blank=True) - password_recovery_msg = serializers.CharField(required=False, allow_blank=True) + update_password_url = serializers.URLField( + required=False, allow_blank=True, allow_null=True + ) + password_recovery_msg = serializers.CharField( + required=False, allow_blank=True, allow_null=True + ) sms_password_recovery = serializers.BooleanField(default=False) sms_provider = serializers.ChoiceField( choices=constants.SMS_BACKENDS, required=False, allow_null=True @@ -87,7 +91,9 @@ class CoreGlobalParametersSerializer(serializers.Serializer): ldap_server_address = serializers.CharField(default="localhost") ldap_server_port = serializers.IntegerField(default=389) ldap_enable_secondary_server = serializers.BooleanField(default=False) - ldap_secondary_server_address = serializers.CharField(required=False) + ldap_secondary_server_address = serializers.CharField( + required=False, allow_blank=True, allow_null=True + ) ldap_secondary_server_port = serializers.IntegerField(default=389, required=False) ldap_secured = serializers.ChoiceField( choices=constants.LDAP_SECURE_MODES, default="none" @@ -109,9 +115,11 @@ class CoreGlobalParametersSerializer(serializers.Serializer): choices=constants.LDAP_AUTH_METHODS, default="searchbind", ) - ldap_bind_dn = serializers.CharField(default="", required=False, allow_blank=True) + ldap_bind_dn = serializers.CharField( + default="", required=False, allow_blank=True, allow_null=True + ) ldap_bind_password = serializers.CharField( - default="", required=False, allow_blank=True + default="", required=False, allow_blank=True, allow_null=True ) ldap_search_base = serializers.CharField( default="", required=False, allow_blank=True @@ -124,15 +132,21 @@ class CoreGlobalParametersSerializer(serializers.Serializer): ) # LDAP sync settings - ldap_sync_bind_dn = serializers.CharField(required=False, allow_blank=True) - ldap_sync_bind_password = serializers.CharField(required=False, allow_blank=True) + ldap_sync_bind_dn = serializers.CharField( + required=False, allow_blank=True, allow_null=True + ) + ldap_sync_bind_password = serializers.CharField( + required=False, allow_blank=True, allow_null=True + ) ldap_enable_sync = serializers.BooleanField(default=False) ldap_sync_delete_remote_account = serializers.BooleanField(default=False) ldap_sync_account_dn_template = serializers.CharField( - required=False, allow_blank=True + required=False, allow_blank=True, allow_null=True ) ldap_enable_import = serializers.BooleanField(default=False) - ldap_import_search_base = serializers.CharField(required=False, allow_blank=True) + ldap_import_search_base = serializers.CharField( + required=False, allow_blank=True, allow_null=True + ) ldap_import_search_filter = serializers.CharField(default="(cn=*)", required=False) ldap_import_username_attr = serializers.CharField(default="cn") ldap_dovecot_sync = serializers.BooleanField(default=False) @@ -141,7 +155,9 @@ class CoreGlobalParametersSerializer(serializers.Serializer): ) # Dashboard settings - custom_welcome_message = serializers.CharField(required=False, allow_blank=True) + custom_welcome_message = serializers.CharField( + required=False, allow_blank=True, allow_null=True + ) rss_feed_url = serializers.URLField( allow_blank=True, required=False, allow_null=True ) @@ -162,7 +178,9 @@ class CoreGlobalParametersSerializer(serializers.Serializer): enable_api_communication = serializers.BooleanField(default=True) check_new_versions = serializers.BooleanField(default=True) send_new_versions_email = serializers.BooleanField(default=False) - new_versions_email_rcpt = lib_fields.DRFEmailFieldUTF8(required=False) + new_versions_email_rcpt = lib_fields.DRFEmailFieldUTF8( + required=False, allow_null=True + ) send_statistics = serializers.BooleanField(default=True) # Misc settings @@ -195,10 +213,11 @@ class CoreGlobalParametersSerializer(serializers.Serializer): return value def validate_ldap_sync_account_dn_template(self, value): - try: - value % {"user": "toto"} - except (KeyError, ValueError): - raise serializers.ValidationError(_("Invalid syntax")) from None + if value: + try: + value % {"user": "toto"} + except (KeyError, ValueError): + raise serializers.ValidationError(_("Invalid syntax")) from None return value def validate_ldap_search_filter(self, value): diff --git a/modoboa/core/app_settings.py b/modoboa/core/app_settings.py index 0ebb254a6..e919d9a07 100644 --- a/modoboa/core/app_settings.py +++ b/modoboa/core/app_settings.py @@ -649,7 +649,7 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict( "new_versions_email_rcpt", { "label": gettext_lazy("Recipient"), - "display": "check_new_versions=true", + "display": "send_new_versions_email=true", "help_text": gettext_lazy( "Recipient of new versions notification emails." ),