diff --git a/frontend/vue.config.js b/frontend/vue.config.js index 3ceebaec0..c0e75e1bc 100644 --- a/frontend/vue.config.js +++ b/frontend/vue.config.js @@ -5,7 +5,7 @@ module.exports = { target: process.env.DOCKER == "yes" ? "http://api:8000/" - : "http://localhost:8000", + : "http://127.0.0.1:8000", }, }, }, diff --git a/modoboa/core/api/v2/serializers.py b/modoboa/core/api/v2/serializers.py index 7afaff798..f766fd6ce 100644 --- a/modoboa/core/api/v2/serializers.py +++ b/modoboa/core/api/v2/serializers.py @@ -159,6 +159,7 @@ class CoreGlobalParametersSerializer(serializers.Serializer): send_statistics = serializers.BooleanField(default=True) # Misc settings + enable_inactive_accounts = serializers.BooleanField(default=True) inactive_account_threshold = serializers.IntegerField(default=30) top_notifications_check_interval = serializers.IntegerField(default=30) log_maximum_age = serializers.IntegerField(default=365) diff --git a/modoboa/core/api/v2/tests.py b/modoboa/core/api/v2/tests.py index 4caae77f7..079437e92 100644 --- a/modoboa/core/api/v2/tests.py +++ b/modoboa/core/api/v2/tests.py @@ -59,6 +59,7 @@ CORE_SETTINGS = { "send_new_versions_email": False, "new_versions_email_rcpt": "postmaster@yourdomain.test", "send_statistics": True, + "enable_inactive_accounts": True, "inactive_account_threshold": 30, "top_notifications_check_interval": 30, "log_maximum_age": 365, diff --git a/modoboa/core/app_settings.py b/modoboa/core/app_settings.py index 5a1fcdc5a..46e83ee7d 100644 --- a/modoboa/core/app_settings.py +++ b/modoboa/core/app_settings.py @@ -455,6 +455,14 @@ class GeneralParametersForm(param_forms.AdminParametersForm): sep3 = SeparatorField(label=ugettext_lazy("Miscellaneous")) + enable_inactive_accounts = YesNoField( + label=_("Enable inactive account tracking"), + initial=True, + help_text=_("Allow the administrator to set a threshold (in days) " + "beyond which an account is considered inactive " + "if the user hasn't logged in") + ) + inactive_account_threshold = forms.IntegerField( label=_("Inactive account threshold"), initial=30, @@ -518,6 +526,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm): "send_new_versions_email": "check_new_versions=True", "new_versions_email_rcpt": "check_new_versions=True", "sms_provider": "sms_password_recovery=True", + "inactive_account_threshold": "enable_inactive_accounts=True" } def __init__(self, *args, **kwargs): @@ -1070,8 +1079,17 @@ GLOBAL_PARAMETERS_STRUCT = collections.OrderedDict([ ("misc", { "label": ugettext_lazy("Miscellaneous"), "params": collections.OrderedDict([ + ("enable_inactive_accounts", { + "label": ugettext_lazy("Enable inactive account tracking"), + "help_text": ugettext_lazy( + "Allow the administrator to set a threshold (in days) " + "beyond which an account is considered inactive " + "if the user hasn't logged in" + ), + }), ("inactive_account_threshold", { "label": ugettext_lazy("Inactive account threshold"), + "display": "enable_inactive_accounts=true", "help_text": ugettext_lazy( "An account with a last login date greater than this " "threshold (in days) will be considered as inactive" diff --git a/modoboa/core/management/commands/clean_inactive_accounts.py b/modoboa/core/management/commands/clean_inactive_accounts.py index eb5e58778..2c48e4754 100644 --- a/modoboa/core/management/commands/clean_inactive_accounts.py +++ b/modoboa/core/management/commands/clean_inactive_accounts.py @@ -43,6 +43,12 @@ class Command(BaseCommand): def handle(self, *args, **options): """Command entry point.""" + if not param_tools.get_global_parameter( + "enable_inactive_accounts"): + if options["verbose"]: + print("Inactive accounts detection is disabled.", + file=self.stdout) + return inactive_account_threshold = param_tools.get_global_parameter( "inactive_account_threshold") qset = models.User.objects.filter( diff --git a/modoboa/core/tests/test_core.py b/modoboa/core/tests/test_core.py index b0b476bc2..ef7b99688 100644 --- a/modoboa/core/tests/test_core.py +++ b/modoboa/core/tests/test_core.py @@ -11,7 +11,7 @@ from django.test import TestCase from django.urls import reverse from django.utils import timezone -from modoboa.lib.tests import ModoTestCase +from modoboa.lib.tests import ModoTestCase, SimpleModoTestCase from .. import factories, mocks, models @@ -44,7 +44,7 @@ class AuthenticationTestCase(ModoTestCase): self.assertTrue(response.url.endswith(reverse("core:dashboard"))) -class ManagementCommandsTestCase(TestCase): +class ManagementCommandsTestCase(SimpleModoTestCase): """Test management commands.""" def test_change_default_admin(self): @@ -84,6 +84,15 @@ class ManagementCommandsTestCase(TestCase): "clean_inactive_accounts", "--verbose", "--dry-run", stdout=out) self.assertIn("user1@domain.test", out.getvalue()) + # Disable account account threshold + self.set_global_parameter("enable_inactive_accounts", False) + out = StringIO() + management.call_command( + "clean_inactive_accounts", "--verbose", stdout=out) + self.assertIn("Inactive accounts detection is disabled.", + out.getvalue()) + + self.set_global_parameter("enable_inactive_accounts", True) management.call_command("clean_inactive_accounts", "--silent") account.refresh_from_db() self.assertFalse(account.is_active) diff --git a/modoboa/core/tests/test_views.py b/modoboa/core/tests/test_views.py index 5920fac6d..d2d5572ef 100644 --- a/modoboa/core/tests/test_views.py +++ b/modoboa/core/tests/test_views.py @@ -60,6 +60,7 @@ SETTINGS_SAMPLE = { "core-default_password": "Toto1000", "limits-deflt_user_quota_limit": "0", "core-hide_features_widget": "False", + "core-enable_inactive_accounts": "True", "core-inactive_account_threshold": "30", "admin-domains_must_have_authorized_mx": False, "core-random_password_length": "8", diff --git a/modoboa/lib/tests/__init__.py b/modoboa/lib/tests/__init__.py index eda6d56bf..f37024fab 100644 --- a/modoboa/lib/tests/__init__.py +++ b/modoboa/lib/tests/__init__.py @@ -52,6 +52,9 @@ class ParametersMixin(object): self.localconfig.parameters.set_values(parameters, app=app) self.localconfig.save() +class SimpleModoTestCase(ParametersMixin, TestCase): + """Simple class to add parameters editing.""" + class ModoTestCase(ParametersMixin, TestCase): """All test cases must inherit from this one.""" diff --git a/modoboa/parameters/tools.py b/modoboa/parameters/tools.py index cda90ba1e..54e3eaff5 100644 --- a/modoboa/parameters/tools.py +++ b/modoboa/parameters/tools.py @@ -63,7 +63,7 @@ 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"] diff --git a/modoboa/pdfcredentials/api/v2/views.py b/modoboa/pdfcredentials/api/v2/views.py index d92955ac4..5d2345fce 100644 --- a/modoboa/pdfcredentials/api/v2/views.py +++ b/modoboa/pdfcredentials/api/v2/views.py @@ -9,6 +9,7 @@ from rest_framework import permissions from rest_framework.views import APIView from modoboa.admin.models import Domain +from modoboa.lib.throttle import UserLesserDdosUser from .serializers import GetAccountCredentialsSerializer @@ -22,6 +23,7 @@ class PDFCredentialView(APIView): ) serializer_class = GetAccountCredentialsSerializer + throttle_classes = [UserLesserDdosUser] def get_queryset(self): """Filter queryset based on current user."""