Ticket #15915: 15915_patch.diff

File 15915_patch.diff, 5.2 KB (added by desh, 4 years ago)

Initial patch with test

Line 
1Index: django/contrib/auth/tests/permissions.py
2===================================================================
3--- django/contrib/auth/tests/permissions.py    (revision 16342)
4+++ django/contrib/auth/tests/permissions.py    (working copy)
5@@ -6,16 +6,21 @@
6 from django.contrib.auth.management import create_permissions
7 from django.contrib.auth import models as auth_models
8 from django.contrib.contenttypes import models as contenttypes_models
9-from django.core.management import call_command
10+from django.core.management import call_command, CommandError
11 from django.test import TestCase
12 
13 
14 class TestAuthPermissions(TestCase):
15+
16+    def setUp(self):
17+        self._original_user_permissions = auth_models.User._meta.permissions
18+
19     def tearDown(self):
20         # These tests mess with content types, but content type lookups
21         # are cached, so we need to make sure the effects of this test
22         # are cleaned up.
23         contenttypes_models.ContentType.objects.clear_cache()
24+        auth_models.User._meta.permissions = self._original_user_permissions
25 
26     def test_permission_register_order(self):
27         """Test that the order of registered permissions doesn't break"""
28@@ -33,6 +38,34 @@
29         call_command('loaddata', 'test_permissions.json',
30                      verbosity=0, commit=False, stderr=stderr)
31         self.assertEqual(stderr.getvalue(), '')
32+
33+    def test_permission_duplicates_checking(self):
34+        """Test that we show proper error message if we are trying to
35+        create duplicate permissions.
36+        """
37+        auth_models.User._meta.permissions = [
38+           ('change_user', 'Can edit user (duplicate)')]
39+        self.assertRaisesRegexp(CommandError,
40+            'The permission codename change_user clashes with a builtin '
41+            'for model auth.User.',
42+            create_permissions, auth_models, [], verbosity=0)
43+
44+        auth_models.User._meta.permissions = [
45+            ('my_custom_permission', 'Some permission'),
46+            ('other_one', 'Some other permission'),
47+            ('my_custom_permission', 'Some permission with duplicate code'),
48+        ]
49+        self.assertRaisesRegexp(CommandError,
50+            'The permission codename is duplicated for model auth.User: '
51+            'my_custom_permission',
52+            create_permissions, auth_models, [], verbosity=0)
53+
54+        # should not raise anything
55+        auth_models.User._meta.permissions = [
56+            ('my_custom_permission', 'Some permission'),
57+            ('other_one', 'Some other permission'),
58+        ]
59+        create_permissions(auth_models, [], verbosity=0)
60Index: django/contrib/auth/management/__init__.py
61===================================================================
62--- django/contrib/auth/management/__init__.py  (revision 16342)
63+++ django/contrib/auth/management/__init__.py  (working copy)
64@@ -7,23 +7,52 @@
65 from django.contrib.auth import models as auth_app
66 from django.db.models import get_models, signals
67 from django.contrib.auth.models import User
68+from django.core.management.base import CommandError
69 
70 
71+def _check_permissions_clashing(custom, builtin, ctype):
72+    "Raises CommandError if there are duplicate permissions."
73+    pool = set()
74+    builtin_codenames = set(p[0] for p in builtin)
75+    for codename, _name in custom:
76+        if codename in pool:
77+            raise CommandError(
78+                "The permission codename is duplicated for model %s.%s: %s" %
79+                (ctype.app_label, ctype.model_class().__name__, codename))
80+        elif codename in builtin_codenames:
81+            raise CommandError(
82+                "The permission codename %s clashes with a builtin for model "
83+                "%s.%s." %
84+                (codename, ctype.app_label, ctype.model_class().__name__))
85+        pool.add(codename)
86+
87+
88 def _get_permission_codename(action, opts):
89     return u'%s_%s' % (action, opts.object_name.lower())
90 
91 
92-def _get_all_permissions(opts):
93-    "Returns (codename, name) for all permissions in the given opts."
94+def _get_builtin_permissions(opts):
95+    "Returns (codename, name) for all autogenerated permissions."
96     perms = []
97     for action in ('add', 'change', 'delete'):
98-        perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
99-    return perms + list(opts.permissions)
100+        perms.append(
101+            (_get_permission_codename(action, opts),
102+             u'Can %s %s' % (action, opts.verbose_name_raw)))
103+    return perms
104 
105 
106+def _get_all_permissions(opts, ctype):
107+    "Returns (codename, name) for all permissions in the given opts."
108+    builtin = _get_builtin_permissions(opts)
109+    custom = list(opts.permissions)
110+    _check_permissions_clashing(custom, builtin, ctype)
111+    return builtin + custom
112+
113+
114 def create_permissions(app, created_models, verbosity, **kwargs):
115     from django.contrib.contenttypes.models import ContentType
116 
117@@ -34,7 +63,7 @@
118     for klass in app_models:
119         ctype = ContentType.objects.get_for_model(klass)
120         ctypes.add(ctype)
121-        for perm in _get_all_permissions(klass._meta):
122+        for perm in _get_all_permissions(klass._meta, ctype):
123             searched_perms.append((ctype, perm))
124 
125     # Find all the Permissions that have a context_type for a model we're
Back to Top