Repository: jazzband/django-axes
Pull request #1074 (2023-06-08 12:57:23)

chore(deps): bump sphinx-rtd-theme from 1.2.0 to 1.2.2
Bumps [sphinx-rtd-theme](https://github.com/readthedocs/sphinx_rtd_theme) from 1.2.0 to 1.2.2.
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/readthedocs/sphinx_rtd_theme/blob/master/docs/changelog.rst">sphinx-rtd-theme's changelog</a>.</em></p>
<blockquote>
<h1>1.2.2</h1>
<h2>Fixes</h2>
<ul>
<li>Require <code>sphinxcontrib-jquery&gt;=4,&lt;5</code> (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1446">#1446</a>)</li>
</ul>
<h2>Added</h2>
<ul>
<li>Styling for <code>:menuselection:</code> (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1426">#1426</a>)</li>
</ul>
<p>.. _release-1.2.1:</p>
<h1>1.2.1</h1>
<h2>Fixes</h2>
<ul>
<li>Load jQuery correctly when using latest sphinxcontrib-jquery release (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1448">#1448</a>)</li>
</ul>
<p>.. _release-1.2.0:</p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/9899ee4ee2f547f81e51297dc12317f018e62fdd"><code>9899ee4</code></a> Release 1.2.2 (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1484">#1484</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/2442ab9ffdb8910f8484362cc8dfd165ca3ffb15"><code>2442ab9</code></a> Remove version logic on sphinxcontrib-jquery, require &gt;=4,&lt;5 (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1446">#1446</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/cd6b429f875999ee48bd914da5369422aa55dd8f"><code>cd6b429</code></a> :menuselection: style (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1426">#1426</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/2107797b002848b3336694541b14ffa2367afc2c"><code>2107797</code></a> Contributing updates (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1478">#1478</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/72691f502500c8fc0c0d22422d0919bc628ddf5f"><code>72691f5</code></a> Release 1.2.1 (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1474">#1474</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/d836ff798cb5032b9d32eccc9a86b69bed256975"><code>d836ff7</code></a> Docs: Typo in recommended pinning (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1476">#1476</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/4d6de11137333ede9842d535aa08b753dcb7f1b0"><code>4d6de11</code></a> Add a call to add_js_files (sphinxcontrib.query) (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1448">#1448</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/03a86b803cf7cf281748ef94345ba7c35953952a"><code>03a86b8</code></a> fixed type-o in note on automatic index generation (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1458">#1458</a>)</li>
<li><a href="https://github.com/readthedocs/sphinx_rtd_theme/commit/ee64d37ac95fcfe7a1e53d7ab72e09704606261e"><code>ee64d37</code></a> Bump to next alpha for development (<a href="https://redirect.github.com/readthedocs/sphinx_rtd_theme/issues/1433">#1433</a>)</li>
<li>See full diff in <a href="https://github.com/readthedocs/sphinx_rtd_theme/compare/1.2.0...1.2.2">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=sphinx-rtd-theme&package-manager=pip&previous-version=1.2.0&new-version=1.2.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/.github/ISSUE_TEMPLATES/bug_report.md b/.github/ISSUE_TEMPLATES/bug_report.md
new file mode 100644
index 0000000..261a642
--- /dev/null
+++ b/.github/ISSUE_TEMPLATES/bug_report.md
@@ -0,0 +1,32 @@
+---
+name: Bug report
+about: Create a report to help us improve django-axes
+title: 'BUG: Short description of the problem'
+labels: 'bug'
+assignees: ''
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. 
+2. 
+3. 
+4.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Your environment**
+python version:
+django version:
+django-axes version:
+Operating system:
+
+**Additional context**
+Add any other context about the problem here.
+
+**Possible implementation**
+Not obligatory, but suggest an idea for implementing addition or change
diff --git a/.github/ISSUE_TEMPLATES/feature_request.md b/.github/ISSUE_TEMPLATES/feature_request.md
new file mode 100644
index 0000000..77f1005
--- /dev/null
+++ b/.github/ISSUE_TEMPLATES/feature_request.md
@@ -0,0 +1,19 @@
+---
+name: Feature request
+about: Suggest an idea for django-axes
+title: 'FEATURE REQUEST: Short description of requested feature'
+labels: 'feature request'
+assignees: ''
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 0000000..94a1759
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,19 @@
+# What does this PR do?
+
+<!--
+Congratulations! You've made it this far! You're not quite done yet though.
+
+Please replace this with a description of the change and which issue is fixed (if applicable). Please also include relevant motivation and context. List any dependencies (if any) that are required for this change.
+
+Once you're done, someone will review your PR shortly. They may suggest changes to make the code even better.
+-->
+
+<!-- Remove if not applicable -->
+
+Fixes # (issue)
+
+
+## Before submitting
+- [ ] This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
+- [ ] Did you make sure to update the documentation with your changes?
+- [ ] Did you write any new necessary tests?
diff --git a/axes/checks.py b/axes/checks.py
index 65fb79f..8b6b0f4 100644
--- a/axes/checks.py
+++ b/axes/checks.py
@@ -21,6 +21,7 @@ class Messages:
     )
     BACKEND_INVALID = "You do not have 'axes.backends.AxesStandaloneBackend' or a subclass in your settings.AUTHENTICATION_BACKENDS."
     SETTING_DEPRECATED = "You have a deprecated setting {deprecated_setting} configured in your project settings"
+    CALLABLE_INVALID = "{callable_setting} is not a valid callable."
 
 
 class Hints:
@@ -28,6 +29,7 @@ class Hints:
     MIDDLEWARE_INVALID = None
     BACKEND_INVALID = "AxesModelBackend was renamed to AxesStandaloneBackend in django-axes version 5.0."
     SETTING_DEPRECATED = None
+    CALLABLE_INVALID = None
 
 
 class Codes:
@@ -35,6 +37,7 @@ class Codes:
     MIDDLEWARE_INVALID = "axes.W002"
     BACKEND_INVALID = "axes.W003"
     SETTING_DEPRECATED = "axes.W004"
+    CALLABLE_INVALID = "axes.W005"
 
 
 @register(Tags.security, Tags.caches, Tags.compatibility)
@@ -153,3 +156,49 @@ def axes_deprecation_check(app_configs, **kwargs):  # pylint: disable=unused-arg
             pass
 
     return warnings
+
+
+@register
+def axes_conf_check(app_configs, **kwargs):  # pylint: disable=unused-argument
+    warnings = []
+
+    callable_settings = [
+        "AXES_CLIENT_IP_CALLABLE",
+        "AXES_CLIENT_STR_CALLABLE",
+        "AXES_LOCKOUT_CALLABLE",
+        "AXES_USERNAME_CALLABLE",
+        "AXES_WHITELIST_CALLABLE",
+        "AXES_COOLOFF_TIME",
+        "AXES_LOCKOUT_PARAMETERS",
+    ]
+
+    for callable_setting in callable_settings:
+        value = getattr(settings, callable_setting)
+        if not is_valid_callable(value):
+            warnings.append(
+                Warning(
+                    msg=Messages.CALLABLE_INVALID.format(
+                        callable_setting=callable_setting
+                    ),
+                    hint=Hints.CALLABLE_INVALID,
+                    id=Codes.CALLABLE_INVALID,
+                )
+            )
+
+    return warnings
+
+
+def is_valid_callable(value) -> bool:
+    if value is None:
+        return True
+
+    if callable(value):
+        return True
+
+    if isinstance(value, str):
+        try:
+            import_string(value)
+        except ImportError:
+            return False
+
+    return True
diff --git a/docs/2_installation.rst b/docs/2_installation.rst
index 21dc0dc..e1d6a15 100644
--- a/docs/2_installation.rst
+++ b/docs/2_installation.rst
@@ -120,7 +120,7 @@ To keep old behaviour with the new flag, configure the following:
 #. If you used ``settings.AXES_LOCK_OUT_BY_USER_OR_IP``, use ``settings.AXES_LOCKOUT_PARAMETERS = ["username", "ip_address"]``, and
 #. If you used ``settings.AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP``, use ``settings.AXES_LOCKOUT_PARAMETERS = [["username", "ip_address"]]``,
 #. If you used ``settings.AXES_USE_USER_AGENT``, add ``"user_agent"`` to your list(s) of lockout parameters.
-    #. ``settings.AXES_USE_USER_AGENT`` would become ``settings.AXES_LOCKOUT_PARAMETERS = ["ip_address", "user_agent"]``
+    #. ``settings.AXES_USE_USER_AGENT`` would become ``settings.AXES_LOCKOUT_PARAMETERS = [["ip_address", "user_agent"]]``
     #. ``settings.AXES_USE_USER_AGENT`` with ``settings.AXES_ONLY_USER_FAILURES`` would become ``settings.AXES_LOCKOUT_PARAMETERS = [["username", "user_agent"]]``
     #. ``settings.AXES_USE_USER_AGENT`` with ``settings.AXES_LOCK_OUT_BY_USER_OR_IP`` would become ``settings.AXES_LOCKOUT_PARAMETERS = [["ip_address", "user_agent"], "username"]``
     #. ``settings.AXES_USE_USER_AGENT`` with ``settings.AXES_LOCK_OUT_BY_COMBINATION_USER_AND_IP`` would become ``settings.AXES_LOCKOUT_PARAMETERS = [["ip_address", "user_agent", "username"]]``
diff --git a/requirements.txt b/requirements.txt
index 7c4c941..7e59721 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,5 +1,5 @@
 -e .
 -r requirements-qa.txt
 -r requirements-test.txt
-sphinx_rtd_theme==1.2.0
+sphinx_rtd_theme==1.2.2
 tox==4.5.1


Test patch:
diff --git a/requirements-test.txt b/requirements-test.txt
index fc04b11..085cc91 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -1,7 +1,7 @@
 -e .
 django-ipware>=3
 coverage==7.2.5
-pytest==7.3.1
+pytest==7.3.2
 pytest-cov==4.0.0
 pytest-django==4.5.2
 pytest-subtests==0.11.0
diff --git a/tests/test_checks.py b/tests/test_checks.py
index 1ccad7c..b9ed5f6 100644
--- a/tests/test_checks.py
+++ b/tests/test_checks.py
@@ -110,3 +110,22 @@ class DeprecatedSettingsTestCase(AxesTestCase):
     def test_deprecated_success_access_log_flag(self):
         warnings = run_checks()
         self.assertEqual(warnings, [self.disable_success_access_log_warning])
+
+
+class ConfCheckTestCase(AxesTestCase):
+    @override_settings(AXES_USERNAME_CALLABLE="module.not_defined")
+    def test_invalid_import_path(self):
+        warnings = run_checks()
+        warning = Warning(
+            msg=Messages.CALLABLE_INVALID.format(
+                callable_setting="AXES_USERNAME_CALLABLE"
+            ),
+            hint=Hints.CALLABLE_INVALID,
+            id=Codes.CALLABLE_INVALID,
+        )
+        self.assertEqual(warnings, [warning])
+
+    @override_settings(AXES_COOLOFF_TIME=lambda: 1)
+    def test_valid_callable(self):
+        warnings = run_checks()
+        self.assertEqual(warnings, [])