import json
import logging
from django.contrib import admin
from django.shortcuts import redirect, render
from django.urls import reverse
from django.utils.translation import gettext_lazy
from .forms import FlagRequestForm
from .models import Request
logger = logging.getLogger(__name__)
[docs]class TruncatedPathFilter(admin.SimpleListFilter):
title = "path"
parameter_name = "path"
[docs] def lookups(self, request, model_admin):
paths = model_admin.model.objects.order_by("path").values_list("path", flat=True).distinct()
truncated_paths = {path if len(path) < 40 else path[:40] + "..." for path in paths}
truncated_paths = sorted(truncated_paths)
return zip(truncated_paths, gettext_lazy(truncated_paths))
[docs] def queryset(self, request, queryset):
if self.value():
if self.value().endswith("..."):
return queryset.filter(path__startswith=self.value()[:-3])
return queryset.filter(path=self.value())
return queryset
[docs]class TruncatedUserAgentFilter(admin.SimpleListFilter):
title = "user agent"
parameter_name = "user_agent"
[docs] def lookups(self, request, model_admin):
paths = model_admin.model.objects.order_by("user_agent").values_list("user_agent", flat=True).distinct()
truncated_paths = {path if len(path) < 40 else path[:40] + "..." for path in paths}
truncated_paths = sorted(truncated_paths)
return zip(truncated_paths, gettext_lazy(truncated_paths))
[docs] def queryset(self, request, queryset):
if self.value():
if self.value().endswith("..."):
return queryset.filter(user_agent__startswith=self.value()[:-3])
return queryset.filter(user_agent=self.value())
return queryset
[docs]class MethodFilter(admin.SimpleListFilter):
title = "method"
parameter_name = "method"
methods = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]
[docs] def lookups(self, request, model_admin):
return zip(self.methods, gettext_lazy(self.methods))
[docs] def queryset(self, request, queryset):
if self.value():
return queryset.filter(method=self.value())
return queryset
[docs]class PathFilter(admin.SimpleListFilter):
title = "path"
parameter_name = "path"
url_paths = [
"index",
"login",
"logout",
"eighth_signup",
"eighth_admin_dashboard",
"view_announcements",
"request_announcement",
"bus",
"calendar",
"user_profile",
"events",
"enrichment",
"printing",
"send_feedback",
"signage_display",
]
url_paths_looked_up = []
[docs] def lookups(self, request, model_admin):
# from ...urls import urlpatterns
# urlpatterns = [url for url in urlpatterns]
# return list(zip(urlpatterns, gettext_lazy(urlpatterns)))
if not self.url_paths_looked_up:
for path in self.url_paths:
try:
self.url_paths_looked_up.append(reverse(path))
except Exception as e:
logger.exception("Failed to lookup path: %s: %s", path, e)
return zip(self.url_paths_looked_up, gettext_lazy(self.url_paths_looked_up))
[docs] def queryset(self, request, queryset):
if self.value():
return queryset.filter(path__startswith=self.value())
return queryset
[docs]class RequestAdmin(admin.ModelAdmin):
[docs] def truncated_path(self):
return self.path[:80] + "..." if len(self.path) > 80 else self.path # pylint: disable=no-member
truncated_path.short_description = "Path"
list_per_page = 500
list_display = (
"timestamp",
"ip",
"user",
truncated_path,
"method",
"flag",
# "user_agent"
)
list_filter = (
"flag",
"timestamp",
MethodFilter,
PathFilter,
# "method",
# "user",
# "ip",
# TruncatedPathFilter,
# TruncatedUserAgentFilter,
)
search_fields = (
"user__username",
"ip",
"path",
"flag",
"method",
"user_agent",
"request",
)
exclude = ("request",)
readonly_fields = (
"ip",
"path",
"user_agent",
"user",
"method",
"request_json",
)
actions = ["flag_requests"]
[docs] def request_json(self, obj):
return json.dumps(json.loads(obj.request), indent=4, sort_keys=True).replace('\\"', "'")
[docs] @admin.action(description="Flag selected requests for review")
def flag_requests(self, request, queryset):
if "apply" in request.POST:
form = FlagRequestForm(request.POST)
if form.is_valid():
for r in queryset:
r.flag = form.cleaned_data["flag"]
r.save()
return redirect(reverse("admin:logs_request_changelist"))
else:
self.message_user(request, "Invalid form data.", level="ERROR")
return render(request, "logs/admin/flag_request.html", {"form": form})
form = FlagRequestForm(
initial={
"_selected_action": queryset.values_list("pk", flat=True),
"flag": Request.objects.filter(flag__isnull=False).order_by("-timestamp").values_list("flag", flat=True).distinct().first(),
}
)
return render(request, "logs/admin/flag_request.html", {"form": form})
admin.site.register(Request, RequestAdmin)