From dc98a7b2e39080a9de05a7659dab289f86edb945 Mon Sep 17 00:00:00 2001 From: Hasan Ramezani Date: Mon, 11 Apr 2022 11:52:37 +0200 Subject: [PATCH] Allow float values for AXES_COOLOFF_TIME(#868). --- axes/helpers.py | 2 ++ docs/4_configuration.rst | 7 +++++-- tests/test_helpers.py | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/axes/helpers.py b/axes/helpers.py index 18a3aa8..a6466f7 100644 --- a/axes/helpers.py +++ b/axes/helpers.py @@ -59,6 +59,8 @@ def get_cool_off() -> Optional[timedelta]: if isinstance(cool_off, int): return timedelta(hours=cool_off) + if isinstance(cool_off, float): + return timedelta(minutes=cool_off * 60) if isinstance(cool_off, str): return import_string(cool_off)() if callable(cool_off): diff --git a/docs/4_configuration.rst b/docs/4_configuration.rst index 8d2b552..a021775 100644 --- a/docs/4_configuration.rst +++ b/docs/4_configuration.rst @@ -28,9 +28,12 @@ The following ``settings.py`` options are available for customizing Axes behavio Default: ``True`` * ``AXES_COOLOFF_TIME``: If set, defines a period of inactivity after which old failed login attempts will be cleared. - Can be set to a Python timedelta object, an integer, a callable, + Can be set to a Python timedelta object, an integer, a float, a callable, or a string path to a callable which takes no arguments. - If an integer, will be interpreted as a number of hours. + If an integer or float, will be interpreted as a number of hours: + ``AXES_COOLOFF_TIME = 2`` 2 hours + ``AXES_COOLOFF_TIME = 2.0`` 2 hours, 120 minutes + ``AXES_COOLOFF_TIME = 1.7`` 1.7 houts, 102 minutes, 6120 seconds Default: ``None`` * ``AXES_ONLY_ADMIN_SITE``: If ``True``, lock is only enabled for admin site. Admin site is determined by checking request path against the path of ``"admin:index"`` view. diff --git a/tests/test_helpers.py b/tests/test_helpers.py index e17937c..f17bee0 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -670,6 +670,18 @@ class AxesCoolOffTestCase(AxesTestCase): def test_get_cool_off_int(self): self.assertEqual(get_cool_off(), timedelta(hours=2)) + @override_settings(AXES_COOLOFF_TIME=2.0) + def test_get_cool_off_int(self): + self.assertEqual(get_cool_off(), timedelta(minutes=120)) + + @override_settings(AXES_COOLOFF_TIME=0.25) + def test_get_cool_off_int(self): + self.assertEqual(get_cool_off(), timedelta(minutes=15)) + + @override_settings(AXES_COOLOFF_TIME=1.7) + def test_get_cool_off_int(self): + self.assertEqual(get_cool_off(), timedelta(seconds=6120)) + @override_settings(AXES_COOLOFF_TIME=lambda: timedelta(seconds=30)) def test_get_cool_off_callable(self): self.assertEqual(get_cool_off(), timedelta(seconds=30))