From d8cb58ada87519a60d083810aa2000884fb68bf4 Mon Sep 17 00:00:00 2001 From: AP Jama Date: Sat, 5 Aug 2023 12:33:06 +0100 Subject: [PATCH] added change that checks permissions when displaying url for recent changes --- .../contrib/admin/templates/admin/index.html | 4 +-- django/contrib/admin/templatetags/log.py | 17 ++++++++++- tests/admin_utils/test_logentry.py | 28 ++++++++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/django/contrib/admin/templates/admin/index.html b/django/contrib/admin/templates/admin/index.html index 899727a4ba..dd97e79cb3 100644 --- a/django/contrib/admin/templates/admin/index.html +++ b/django/contrib/admin/templates/admin/index.html @@ -31,10 +31,10 @@ {% for entry in admin_log %}
  • {% if entry.is_addition %}{% translate 'Added:' %}{% elif entry.is_change %}{% translate 'Changed:' %}{% elif entry.is_deletion %}{% translate 'Deleted:' %}{% endif %} - {% if entry.is_deletion or not entry.get_admin_url %} + {% if entry.is_deletion or not entry.url %} {{ entry.object_repr }} {% else %} - {{ entry.object_repr }} + {{ entry.object_repr }} {% endif %}
    {% if entry.content_type %} diff --git a/django/contrib/admin/templatetags/log.py b/django/contrib/admin/templatetags/log.py index 55b2c46fa5..856e8f0eeb 100644 --- a/django/contrib/admin/templatetags/log.py +++ b/django/contrib/admin/templatetags/log.py @@ -19,7 +19,22 @@ class AdminLogNode(template.Node): if not user_id.isdigit(): user_id = context[self.user].pk entries = entries.filter(user__pk=user_id) - context[self.varname] = entries[: int(self.limit)] + filtered_context = entries.select_related("content_type", "user")[ + : int(self.limit) + ] + for entry in filtered_context: + content_type = entry.content_type + if not content_type: + entry.url = entry.get_admin_url() + continue + user = entry.user + view_permission_name = f"{content_type.app_label}.view_{content_type.model}" + user_has_permission = user.has_perm(view_permission_name) + if user_has_permission: + entry.url = entry.get_admin_url() + else: + entry.url = None + context[self.varname] = filtered_context return "" diff --git a/tests/admin_utils/test_logentry.py b/tests/admin_utils/test_logentry.py index 20bbcccb1c..a64adc1d56 100644 --- a/tests/admin_utils/test_logentry.py +++ b/tests/admin_utils/test_logentry.py @@ -3,7 +3,7 @@ from datetime import datetime from django.contrib.admin.models import ADDITION, CHANGE, DELETION, LogEntry from django.contrib.admin.utils import quote -from django.contrib.auth.models import User +from django.contrib.auth.models import User, Permission from django.contrib.contenttypes.models import ContentType from django.test import TestCase, override_settings from django.urls import reverse @@ -351,6 +351,32 @@ class LogEntryTests(TestCase): counted_presence_after = response.content.count(should_contain) self.assertEqual(counted_presence_before - 1, counted_presence_after) + def test_recent_actions_user_lacks_view_permission(self): + # No permission to view articles. Log is a span with no link. + response = self.client.get(reverse("admin:index")) + should_contain = """Article""" + self.assertContains(response, should_contain) + + # Add permission to view articles. Log is a link. + logentry = LogEntry.objects.get(content_type__model__iexact="article") + view_permission_name = f"{logentry.content_type.app_label}.view_{logentry.content_type.model}" + view_article_permission = Permission.objects.create( + name=f"Can view {logentry.content_type.model}", + content_type=logentry.content_type, + codename=view_permission_name, + ) + self.user.user_permissions.add(view_article_permission) + + response = self.client.get(reverse("admin:index")) + expected_log_entry_link = reverse( + "admin:admin_utils_article_change", args=(quote(self.a1.pk),) + ) + should_contain = """%s""" % ( + escape(expected_log_entry_link), + escape(repr(self.a1)), + ) + self.assertContains(response, should_contain) + def test_proxy_model_content_type_is_used_for_log_entries(self): """ Log entries for proxy models should have the proxy model's contenttype