diff --git a/django/contrib/admin/util.py b/django/contrib/admin/util.py
index 61182a6..6e01bdc 100644
a
|
b
|
def get_deleted_objects(objs, opts, user, admin_site, using):
|
116 | 116 | None, (quote(obj._get_pk_val()),)) |
117 | 117 | p = '%s.%s' % (opts.app_label, |
118 | 118 | opts.get_delete_permission()) |
119 | | if not user.has_perm(p): |
| 119 | if not user.has_perm(p, obj): |
120 | 120 | perms_needed.add(opts.verbose_name) |
121 | 121 | # Display a link to the admin page. |
122 | 122 | return mark_safe(u'%s: <a href="%s">%s</a>' % |
… |
… |
def reverse_field_path(model, path):
|
361 | 361 | for piece in pieces: |
362 | 362 | field, model, direct, m2m = parent._meta.get_field_by_name(piece) |
363 | 363 | # skip trailing data field if extant: |
364 | | if len(reversed_path) == len(pieces)-1: # final iteration |
| 364 | if len(reversed_path) == len(pieces) - 1: # final iteration |
365 | 365 | try: |
366 | 366 | get_model_from_relation(field) |
367 | 367 | except NotRelationField: |
diff --git a/tests/regressiontests/admin_util/models.py b/tests/regressiontests/admin_util/models.py
index 0e81df3..6253641 100644
a
|
b
|
|
1 | 1 | from django.db import models |
| 2 | from django.contrib.auth.models import User |
2 | 3 | |
3 | 4 | |
4 | 5 | class Article(models.Model): |
… |
… |
class Article(models.Model):
|
17 | 18 | return "nothing" |
18 | 19 | test_from_model_with_override.short_description = "not What you Expect" |
19 | 20 | |
| 21 | |
20 | 22 | class Count(models.Model): |
21 | 23 | num = models.PositiveSmallIntegerField() |
22 | 24 | parent = models.ForeignKey('self', null=True) |
… |
… |
class Count(models.Model):
|
24 | 26 | def __unicode__(self): |
25 | 27 | return unicode(self.num) |
26 | 28 | |
| 29 | |
27 | 30 | class Event(models.Model): |
28 | 31 | date = models.DateTimeField(auto_now_add=True) |
29 | 32 | |
| 33 | |
30 | 34 | class Location(models.Model): |
31 | 35 | event = models.OneToOneField(Event, verbose_name='awesome event') |
32 | 36 | |
| 37 | |
33 | 38 | class Guest(models.Model): |
34 | 39 | event = models.OneToOneField(Event) |
35 | 40 | name = models.CharField(max_length=255) |
36 | 41 | |
37 | 42 | class Meta: |
38 | 43 | verbose_name = "awesome guest" |
| 44 | |
| 45 | |
| 46 | class PrivilegedUser(User): |
| 47 | special_usernames = ['special'] |
| 48 | |
| 49 | def has_perm(self, perm, obj=None): |
| 50 | if obj and obj.username in self.special_usernames: |
| 51 | return True |
| 52 | return False |
diff --git a/tests/regressiontests/admin_util/tests.py b/tests/regressiontests/admin_util/tests.py
index 8113f2e..b1c9503 100644
a
|
b
|
from django.conf import settings
|
6 | 6 | from django.contrib import admin |
7 | 7 | from django.contrib.admin import helpers |
8 | 8 | from django.contrib.admin.util import (display_for_field, label_for_field, |
9 | | lookup_field, NestedObjects) |
| 9 | lookup_field, NestedObjects, get_deleted_objects) |
10 | 10 | from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE |
11 | 11 | from django.contrib.sites.models import Site |
| 12 | from django.contrib.auth.models import User |
12 | 13 | from django.db import models, DEFAULT_DB_ALIAS |
13 | 14 | from django import forms |
14 | 15 | from django.test import TestCase |
15 | | from django.utils import unittest |
16 | 16 | from django.utils.formats import localize |
17 | 17 | from django.utils.safestring import mark_safe |
18 | 18 | |
19 | | from .models import Article, Count, Event, Location |
| 19 | from .models import Article, Count, Event, Location, PrivilegedUser |
20 | 20 | |
21 | 21 | |
22 | 22 | class NestedObjectsTests(TestCase): |
… |
… |
class NestedObjectsTests(TestCase):
|
70 | 70 | # Should not require additional queries to populate the nested graph. |
71 | 71 | self.assertNumQueries(2, self._collect, 0) |
72 | 72 | |
73 | | class UtilTests(unittest.TestCase): |
| 73 | class UtilTests(TestCase): |
| 74 | urls = 'regressiontests.admin_util.urls' |
| 75 | |
74 | 76 | def test_values_from_lookup_field(self): |
75 | 77 | """ |
76 | 78 | Regression test for #12654: lookup_field |
… |
… |
class UtilTests(unittest.TestCase):
|
218 | 220 | ) |
219 | 221 | self.assertEqual( |
220 | 222 | label_for_field("test_from_model", Article, |
221 | | model_admin = MockModelAdmin, |
222 | | return_attr = True |
| 223 | model_admin=MockModelAdmin, |
| 224 | return_attr=True |
223 | 225 | ), |
224 | 226 | ("not Really the Model", MockModelAdmin.test_from_model) |
225 | 227 | ) |
… |
… |
class UtilTests(unittest.TestCase):
|
266 | 268 | # safestring should not be escaped |
267 | 269 | class MyForm(forms.Form): |
268 | 270 | text = forms.CharField(label=mark_safe('<i>text</i>')) |
269 | | cb = forms.BooleanField(label=mark_safe('<i>cb</i>')) |
| 271 | cb = forms.BooleanField(label=mark_safe('<i>cb</i>')) |
270 | 272 | |
271 | 273 | form = MyForm() |
272 | 274 | self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), |
… |
… |
class UtilTests(unittest.TestCase):
|
277 | 279 | # normal strings needs to be escaped |
278 | 280 | class MyForm(forms.Form): |
279 | 281 | text = forms.CharField(label='&text') |
280 | | cb = forms.BooleanField(label='&cb') |
| 282 | cb = forms.BooleanField(label='&cb') |
281 | 283 | |
282 | 284 | form = MyForm() |
283 | 285 | self.assertEqual(helpers.AdminField(form, 'text', is_first=False).label_tag(), |
284 | 286 | '<label for="id_text" class="required inline">&text:</label>') |
285 | 287 | self.assertEqual(helpers.AdminField(form, 'cb', is_first=False).label_tag(), |
286 | 288 | '<label for="id_cb" class="vCheckboxLabel required inline">&cb</label>') |
| 289 | |
| 290 | def test_get_deleted_objects_has_perm(self): |
| 291 | |
| 292 | class MockAdminSite: |
| 293 | name = 'admin-ns' |
| 294 | _registry = [User] |
| 295 | |
| 296 | privileged_user = PrivilegedUser() |
| 297 | |
| 298 | # privileged_user don't have permission to modify all users, |
| 299 | # but have permission to user with username 'test' |
| 300 | # get_deleted_objects have to pass object for privileges check |
| 301 | obj = User(username='special') |
| 302 | obj.save() |
| 303 | (deleted_objects, perms_needed, protected) = get_deleted_objects( |
| 304 | [obj], None, privileged_user, MockAdminSite(), None) |
| 305 | self.assertFalse(obj._meta.verbose_name in perms_needed) |
| 306 | |
| 307 | obj = User(username='common') |
| 308 | obj.save() |
| 309 | (deleted_objects, perms_needed, protected) = get_deleted_objects( |
| 310 | [obj], None, privileged_user, MockAdminSite(), None) |
| 311 | self.assertTrue(obj._meta.verbose_name in perms_needed) |
diff --git a/tests/regressiontests/admin_util/urls.py b/tests/regressiontests/admin_util/urls.py
new file mode 100644
index 0000000..22f4717
-
|
+
|
|
| 1 | from __future__ import absolute_import |
| 2 | |
| 3 | from django.conf.urls import patterns, url, include |
| 4 | |
| 5 | |
| 6 | class URLObject(object): |
| 7 | def __init__(self, app_name, namespace): |
| 8 | self.app_name = app_name |
| 9 | self.namespace = namespace |
| 10 | |
| 11 | def urls(self): |
| 12 | return patterns('', |
| 13 | url(r'^inner/(\d+)/$', 'empty_view', name='auth_user_change'), |
| 14 | ), self.app_name, self.namespace |
| 15 | urls = property(urls) |
| 16 | |
| 17 | testobj1 = URLObject('testapp', 'admin-ns') |
| 18 | |
| 19 | urlpatterns = patterns('regressiontests.admin_util.urls', |
| 20 | (r'^test1/', include(testobj1.urls)), |
| 21 | ) |