diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 73733c293..7dd8409a8 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -30,10 +30,10 @@ jobs:
- 3306:3306
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
@@ -43,7 +43,7 @@ jobs:
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
@@ -71,7 +71,7 @@ jobs:
DB_PORT: 3306
- name: Upload coverage data
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: coverage-data
path: ".coverage.*"
@@ -101,10 +101,10 @@ jobs:
--health-retries 5
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
@@ -114,7 +114,7 @@ jobs:
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
@@ -140,7 +140,7 @@ jobs:
DB_PORT: 5432
- name: Upload coverage data
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: coverage-data
path: ".coverage.*"
@@ -154,10 +154,10 @@ jobs:
python-version: ['3.7', '3.8', '3.9', '3.10']
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
@@ -167,7 +167,7 @@ jobs:
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
@@ -187,7 +187,7 @@ jobs:
DB_NAME: ":memory:"
- name: Upload coverage data
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: coverage-data
path: ".coverage.*"
@@ -197,8 +197,8 @@ jobs:
runs-on: "ubuntu-latest"
needs: [sqlite, mysql, postgres]
steps:
- - uses: actions/checkout@v2
- - uses: actions/setup-python@v2
+ - uses: actions/checkout@v3
+ - uses: actions/setup-python@v4
with:
# Use latest, so it understands all syntax.
python-version: "3.10"
@@ -206,7 +206,7 @@ jobs:
- run: python -m pip install --upgrade coverage
- name: Download coverage data.
- uses: actions/download-artifact@v2
+ uses: actions/download-artifact@v3
with:
name: coverage-data
@@ -217,7 +217,7 @@ jobs:
python -m coverage report
- name: Upload HTML report if check failed.
- uses: actions/upload-artifact@v2
+ uses: actions/upload-artifact@v3
with:
name: html-report
path: htmlcov
@@ -229,10 +229,10 @@ jobs:
fail-fast: false
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
- uses: actions/setup-python@v2
+ uses: actions/setup-python@v4
with:
python-version: 3.8
@@ -242,7 +242,7 @@ jobs:
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
- uses: actions/cache@v2
+ uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 2a0e179ad..36baad66d 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -7,20 +7,20 @@ repos:
- id: trailing-whitespace
- id: mixed-line-ending
- repo: https://github.com/pycqa/flake8
- rev: 4.0.1
+ rev: 5.0.4
hooks:
- id: flake8
- repo: https://github.com/pycqa/doc8
- rev: 0.11.2
+ rev: v1.0.0
hooks:
- id: doc8
- repo: https://github.com/asottile/pyupgrade
- rev: v2.34.0
+ rev: v2.37.3
hooks:
- id: pyupgrade
args: [--py37-plus]
- repo: https://github.com/adamchainz/django-upgrade
- rev: 1.7.0
+ rev: 1.8.0
hooks:
- id: django-upgrade
args: [--target-version, "3.2"]
@@ -43,7 +43,7 @@ repos:
- id: prettier
types_or: [javascript, css]
- repo: https://github.com/pre-commit/mirrors-eslint
- rev: v8.18.0
+ rev: v8.22.0
hooks:
- id: eslint
files: \.js?$
@@ -51,7 +51,7 @@ repos:
args:
- --fix
- repo: https://github.com/psf/black
- rev: 22.3.0
+ rev: 22.6.0
hooks:
- id: black
language_version: python3
diff --git a/README.rst b/README.rst
index 2c1ba9730..c7ea51bd6 100644
--- a/README.rst
+++ b/README.rst
@@ -44,8 +44,8 @@ Here's a screenshot of the toolbar in action:
In addition to the built-in panels, a number of third-party panels are
contributed by the community.
-The current stable version of the Debug Toolbar is 3.5.0. It works on
-Django ≥ 3.2.
+The current stable version of the Debug Toolbar is 3.6.0. It works on
+Django ≥ 3.2.4.
Documentation, including installation and configuration instructions, is
available at https://django-debug-toolbar.readthedocs.io/.
diff --git a/debug_toolbar/__init__.py b/debug_toolbar/__init__.py
index c9834b8e3..17f1f9e69 100644
--- a/debug_toolbar/__init__.py
+++ b/debug_toolbar/__init__.py
@@ -4,7 +4,7 @@
# Do not use pkg_resources to find the version but set it here directly!
# see issue #1446
-VERSION = "3.5.0"
+VERSION = "3.6.0"
# Code that discovers files or modules in INSTALLED_APPS imports this module.
urls = "debug_toolbar.urls", APP_NAME
diff --git a/debug_toolbar/decorators.py b/debug_toolbar/decorators.py
index 2abfb22f9..8114b05d7 100644
--- a/debug_toolbar/decorators.py
+++ b/debug_toolbar/decorators.py
@@ -1,6 +1,6 @@
import functools
-from django.http import Http404, HttpResponseBadRequest
+from django.http import Http404
def require_show_toolbar(view):
@@ -15,21 +15,3 @@ def inner(request, *args, **kwargs):
return view(request, *args, **kwargs)
return inner
-
-
-def signed_data_view(view):
- """Decorator that handles unpacking a signed data form"""
-
- @functools.wraps(view)
- def inner(request, *args, **kwargs):
- from debug_toolbar.forms import SignedDataForm
-
- data = request.GET if request.method == "GET" else request.POST
- signed_form = SignedDataForm(data)
- if signed_form.is_valid():
- return view(
- request, *args, verified_data=signed_form.verified_data(), **kwargs
- )
- return HttpResponseBadRequest("Invalid signature")
-
- return inner
diff --git a/debug_toolbar/forms.py b/debug_toolbar/forms.py
index 3c7a45a07..1263c3aff 100644
--- a/debug_toolbar/forms.py
+++ b/debug_toolbar/forms.py
@@ -21,7 +21,6 @@ class PanelForm(forms.Form):
panel_form = PanelForm(signed_form.verified_data)
if panel_form.is_valid():
# Success
- Or wrap the FBV with ``debug_toolbar.decorators.signed_data_view``
"""
salt = "django_debug_toolbar"
diff --git a/debug_toolbar/panels/history/panel.py b/debug_toolbar/panels/history/panel.py
index 596bcfb4a..2e637083a 100644
--- a/debug_toolbar/panels/history/panel.py
+++ b/debug_toolbar/panels/history/panel.py
@@ -24,7 +24,7 @@ def get_headers(self, request):
observe_request = self.toolbar.get_observe_request()
store_id = getattr(self.toolbar, "store_id")
if store_id and observe_request(request):
- headers["DJDT-STORE-ID"] = store_id
+ headers["djdt-store-id"] = store_id
return headers
@property
diff --git a/debug_toolbar/panels/sql/utils.py b/debug_toolbar/panels/sql/utils.py
index be607cec6..0fbba3e90 100644
--- a/debug_toolbar/panels/sql/utils.py
+++ b/debug_toolbar/panels/sql/utils.py
@@ -69,7 +69,7 @@ def simplify(sql):
def contrasting_color_generator():
"""
- Generate constrasting colors by varying most significant bit of RGB first,
+ Generate contrasting colors by varying most significant bit of RGB first,
and then vary subsequent bits systematically.
"""
diff --git a/debug_toolbar/panels/sql/views.py b/debug_toolbar/panels/sql/views.py
index 49ffee515..fabca7a57 100644
--- a/debug_toolbar/panels/sql/views.py
+++ b/debug_toolbar/panels/sql/views.py
@@ -2,15 +2,27 @@
from django.template.loader import render_to_string
from django.views.decorators.csrf import csrf_exempt
-from debug_toolbar.decorators import require_show_toolbar, signed_data_view
+from debug_toolbar.decorators import require_show_toolbar
+from debug_toolbar.forms import SignedDataForm
from debug_toolbar.panels.sql.forms import SQLSelectForm
+def get_signed_data(request):
+ """Unpack a signed data form, if invalid returns None"""
+ data = request.GET if request.method == "GET" else request.POST
+ signed_form = SignedDataForm(data)
+ if signed_form.is_valid():
+ return signed_form.verified_data()
+ return None
+
+
@csrf_exempt
@require_show_toolbar
-@signed_data_view
-def sql_select(request, verified_data):
+def sql_select(request):
"""Returns the output of the SQL SELECT statement"""
+ verified_data = get_signed_data(request)
+ if not verified_data:
+ return HttpResponseBadRequest("Invalid signature")
form = SQLSelectForm(verified_data)
if form.is_valid():
@@ -35,9 +47,11 @@ def sql_select(request, verified_data):
@csrf_exempt
@require_show_toolbar
-@signed_data_view
-def sql_explain(request, verified_data):
+def sql_explain(request):
"""Returns the output of the SQL EXPLAIN on the given query"""
+ verified_data = get_signed_data(request)
+ if not verified_data:
+ return HttpResponseBadRequest("Invalid signature")
form = SQLSelectForm(verified_data)
if form.is_valid():
@@ -71,9 +85,11 @@ def sql_explain(request, verified_data):
@csrf_exempt
@require_show_toolbar
-@signed_data_view
-def sql_profile(request, verified_data):
+def sql_profile(request):
"""Returns the output of running the SQL and getting the profiling statistics"""
+ verified_data = get_signed_data(request)
+ if not verified_data:
+ return HttpResponseBadRequest("Invalid signature")
form = SQLSelectForm(verified_data)
if form.is_valid():
diff --git a/debug_toolbar/panels/templates/views.py b/debug_toolbar/panels/templates/views.py
index 8d6d634d3..134b3d476 100644
--- a/debug_toolbar/panels/templates/views.py
+++ b/debug_toolbar/panels/templates/views.py
@@ -3,7 +3,7 @@
from django.template import Origin, TemplateDoesNotExist
from django.template.engine import Engine
from django.template.loader import render_to_string
-from django.utils.safestring import mark_safe
+from django.utils.html import format_html, mark_safe
from debug_toolbar.decorators import require_show_toolbar
@@ -50,12 +50,11 @@ def template_source(request):
from pygments import highlight
from pygments.formatters import HtmlFormatter
from pygments.lexers import HtmlDjangoLexer
-
+ except ModuleNotFoundError:
+ source = format_html("{}
", source)
+ else:
source = highlight(source, HtmlDjangoLexer(), HtmlFormatter())
source = mark_safe(source)
- source.pygmentized = True
- except ImportError:
- pass
content = render_to_string(
"debug_toolbar/panels/template_source.html",
diff --git a/debug_toolbar/static/debug_toolbar/js/toolbar.js b/debug_toolbar/static/debug_toolbar/js/toolbar.js
index 860c72110..1c06be7fa 100644
--- a/debug_toolbar/static/debug_toolbar/js/toolbar.js
+++ b/debug_toolbar/static/debug_toolbar/js/toolbar.js
@@ -264,8 +264,13 @@ const djdt = {
const origOpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function () {
this.addEventListener("load", function () {
- let store_id = this.getResponseHeader("djdt-store-id");
- if (store_id !== null) {
+ // Chromium emits a "Refused to get unsafe header" uncatchable warning
+ // when the header can't be fetched. While it doesn't impede execution
+ // it's worrisome to developers.
+ if (
+ this.getAllResponseHeaders().indexOf("djdt-store-id") >= 0
+ ) {
+ let store_id = this.getResponseHeader("djdt-store-id");
store_id = encodeURIComponent(store_id);
const dest = `${sidebar_url}?store_id=${store_id}`;
slowjax(dest).then(function (data) {
diff --git a/debug_toolbar/templates/debug_toolbar/panels/template_source.html b/debug_toolbar/templates/debug_toolbar/panels/template_source.html
index 229ea83e4..397c44b24 100644
--- a/debug_toolbar/templates/debug_toolbar/panels/template_source.html
+++ b/debug_toolbar/templates/debug_toolbar/panels/template_source.html
@@ -5,10 +5,6 @@
{{ template_name }}
{{ source }}
- {% else %}
- {{ source }}
- {% endif %}
+ {{ source }}