-
-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support HistoryPanel to capture ajax requests.
This creates a new panel, HistoryPanel which makes use of the Toolbar.store to support a history of the toolbar as requests are made. The interface changes as follows: Panel.is_historical - Indicates that the panel's button and content should be updated when switching between snapshots of the history. Toolbar.store - Will no longer generate a new store_id when the instance already has a value. DEBUG_TOOLBAR_CONFIG.HISTORY_POST_TRUNC_LENGTH - Allows the request's POST content to be truncated in the history panel's content. LoggingPanel and StaticFilesPanel now utilize the ``get_stats`` method to fetch panel data for nav_subtitle. Credit to @djsutho for creating the original third party panel: https://github.com/djsutho/django-debug-toolbar-request-history The core concepts were derived from that package.
- Loading branch information
1 parent
bad48b2
commit 7a4ea58
Showing
23 changed files
with
443 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from debug_toolbar.panels.history.panel import HistoryPanel # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import hashlib | ||
import hmac | ||
|
||
from django import forms | ||
from django.conf import settings | ||
from django.core.exceptions import ValidationError | ||
from django.utils.crypto import constant_time_compare | ||
from django.utils.encoding import force_bytes | ||
|
||
|
||
class HistoryStoreForm(forms.Form): | ||
""" | ||
Validate params | ||
store_id: The key for the store instance to be fetched. | ||
""" | ||
|
||
store_id = forms.CharField(widget=forms.HiddenInput()) | ||
hash = forms.CharField(widget=forms.HiddenInput()) | ||
|
||
def __init__(self, *args, **kwargs): | ||
initial = kwargs.get("initial", None) | ||
|
||
if initial is not None: | ||
initial["hash"] = self.make_hash(initial) | ||
|
||
super().__init__(*args, **kwargs) | ||
|
||
def make_hash(self, data): | ||
m = hmac.new(key=force_bytes(settings.SECRET_KEY), digestmod=hashlib.sha1) | ||
m.update(force_bytes(data["store_id"])) | ||
return m.hexdigest() | ||
|
||
def clean_hash(self): | ||
hash = self.cleaned_data["hash"] | ||
|
||
if not constant_time_compare(hash, self.make_hash(self.data)): | ||
raise ValidationError("Tamper alert") | ||
|
||
return hash |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import json | ||
import logging | ||
from collections import OrderedDict | ||
|
||
from django.conf.urls import url | ||
from django.template.loader import render_to_string | ||
from django.utils import timezone | ||
from django.utils.translation import gettext_lazy as _ | ||
|
||
from debug_toolbar import settings as dt_settings | ||
from debug_toolbar.panels import Panel | ||
from debug_toolbar.panels.history import views | ||
from debug_toolbar.panels.history.forms import HistoryStoreForm | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
CLEANSED_SUBSTITUTE = "********************" | ||
|
||
|
||
class HistoryPanel(Panel): | ||
""" A panel to display History """ | ||
|
||
title = _("History") | ||
nav_title = _("History") | ||
template = "debug_toolbar/panels/history.html" | ||
|
||
@property | ||
def is_historical(self): | ||
"""The HistoryPanel should not be included in the historical panels.""" | ||
return False | ||
|
||
@classmethod | ||
def get_urls(cls): | ||
return [ | ||
url(r"^history_sidebar/$", views.history_sidebar, name="history_sidebar"), | ||
] | ||
|
||
@property | ||
def nav_subtitle(self): | ||
return self.get_stats().get("request_url", "") | ||
|
||
def generate_stats(self, request, response): | ||
cleansed = request.POST.copy() | ||
for k in cleansed: | ||
cleansed[k] = CLEANSED_SUBSTITUTE | ||
self.record_stats( | ||
{ | ||
"request_url": request.get_full_path(), | ||
"request_method": request.method, | ||
"post": json.dumps(cleansed, sort_keys=True, indent=4), | ||
"time": timezone.now(), | ||
} | ||
) | ||
|
||
@property | ||
def content(self): | ||
"""Content of the panel when it's displayed in full screen. | ||
Fetch every store for the toolbar and include it in the template. | ||
""" | ||
stores = OrderedDict() | ||
for id, toolbar in reversed(self.toolbar._store.items()): | ||
stores[id] = { | ||
"toolbar": toolbar, | ||
"form": HistoryStoreForm(initial={"store_id": id}), | ||
} | ||
|
||
return render_to_string( | ||
self.template, | ||
{ | ||
"current_store_id": self.toolbar.store_id, | ||
"stores": stores, | ||
"trunc_length": dt_settings.get_config()["HISTORY_POST_TRUNC_LENGTH"], | ||
}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from django.http import HttpResponseBadRequest, JsonResponse | ||
from django.template.loader import render_to_string | ||
from django.views.decorators.csrf import csrf_exempt | ||
|
||
from debug_toolbar.decorators import require_show_toolbar | ||
from debug_toolbar.panels.history.forms import HistoryStoreForm | ||
from debug_toolbar.toolbar import DebugToolbar | ||
|
||
|
||
@csrf_exempt | ||
@require_show_toolbar | ||
def history_sidebar(request): | ||
"""Returns the selected debug toolbar history snapshot.""" | ||
form = HistoryStoreForm(request.POST or None) | ||
|
||
if form.is_valid(): | ||
store_id = form.cleaned_data["store_id"] | ||
toolbar = DebugToolbar.fetch(store_id) | ||
context = {} | ||
for panel in toolbar.panels: | ||
if not panel.is_historical: | ||
continue | ||
panel_context = {"panel": panel} | ||
context[panel.panel_id] = { | ||
"button": render_to_string( | ||
"debug_toolbar/includes/panel_button.html", panel_context | ||
), | ||
"content": render_to_string( | ||
"debug_toolbar/includes/panel_content.html", panel_context | ||
), | ||
} | ||
return JsonResponse(context) | ||
return HttpResponseBadRequest("Form errors") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
debug_toolbar/templates/debug_toolbar/includes/panel_button.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{% load i18n %} | ||
<li class="djDebugPanelButton djdt-{{ panel.panel_id }}"> | ||
<input type="checkbox" data-cookie="djdt{{ panel.panel_id }}" {% if panel.enabled %}checked title="{% trans "Disable for next and successive requests" %}"{% else %}title="{% trans "Enable for next and successive requests" %}"{% endif %}> | ||
{% if panel.has_content and panel.enabled %} | ||
<a href="#" title="{{ panel.title }}" class="{{ panel.panel_id }}"> | ||
{% else %} | ||
<div class="djdt-contentless{% if not panel.enabled %} djdt-disabled{% endif %}"> | ||
{% endif %} | ||
{{ panel.nav_title }} | ||
{% if panel.enabled %} | ||
{% with panel.nav_subtitle as subtitle %} | ||
{% if subtitle %}<br><small>{{ subtitle }}</small>{% endif %} | ||
{% endwith %} | ||
{% endif %} | ||
{% if panel.has_content and panel.enabled %} | ||
</a> | ||
{% else %} | ||
</div> | ||
{% endif %} | ||
</li> |
Oops, something went wrong.