Browse Source

Refs #30226 -- Added User.get_user_permissions() method.

Added to mirror the existing User.get_group_permissions().
Tobias Bengfort 6 years ago
parent
commit
581a0f4545

+ 8 - 5
django/contrib/auth/backends.py

@@ -15,11 +15,17 @@ class BaseBackend:
     def get_user(self, user_id):
         return None
 
+    def get_user_permissions(self, user_obj, obj=None):
+        return set()
+
     def get_group_permissions(self, user_obj, obj=None):
         return set()
 
     def get_all_permissions(self, user_obj, obj=None):
-        return self.get_group_permissions(user_obj, obj=obj)
+        return {
+            *self.get_user_permissions(user_obj, obj=obj),
+            *self.get_group_permissions(user_obj, obj=obj),
+        }
 
     def has_perm(self, user_obj, perm, obj=None):
         return perm in self.get_all_permissions(user_obj, obj=obj)
@@ -96,10 +102,7 @@ class ModelBackend(BaseBackend):
         if not user_obj.is_active or user_obj.is_anonymous or obj is not None:
             return set()
         if not hasattr(user_obj, '_perm_cache'):
-            user_obj._perm_cache = {
-                *self.get_user_permissions(user_obj),
-                *self.get_group_permissions(user_obj),
-            }
+            user_obj._perm_cache = super().get_all_permissions(user_obj)
         return user_obj._perm_cache
 
     def has_perm(self, user_obj, perm, obj=None):

+ 18 - 10
django/contrib/auth/models.py

@@ -159,11 +159,12 @@ class UserManager(BaseUserManager):
 
 
 # A few helper functions for common logic between User and AnonymousUser.
-def _user_get_all_permissions(user, obj):
+def _user_get_permissions(user, obj, from_name):
     permissions = set()
+    name = 'get_%s_permissions' % from_name
     for backend in auth.get_backends():
-        if hasattr(backend, "get_all_permissions"):
-            permissions.update(backend.get_all_permissions(user, obj))
+        if hasattr(backend, name):
+            permissions.update(getattr(backend, name)(user, obj))
     return permissions
 
 
@@ -233,20 +234,24 @@ class PermissionsMixin(models.Model):
     class Meta:
         abstract = True
 
+    def get_user_permissions(self, obj=None):
+        """
+        Return a list of permission strings that this user has directly.
+        Query all available auth backends. If an object is passed in,
+        return only permissions matching this object.
+        """
+        return _user_get_permissions(self, obj, 'user')
+
     def get_group_permissions(self, obj=None):
         """
         Return a list of permission strings that this user has through their
         groups. Query all available auth backends. If an object is passed in,
         return only permissions matching this object.
         """
-        permissions = set()
-        for backend in auth.get_backends():
-            if hasattr(backend, "get_group_permissions"):
-                permissions.update(backend.get_group_permissions(self, obj))
-        return permissions
+        return _user_get_permissions(self, obj, 'group')
 
     def get_all_permissions(self, obj=None):
-        return _user_get_all_permissions(self, obj)
+        return _user_get_permissions(self, obj, 'all')
 
     def has_perm(self, perm, obj=None):
         """
@@ -403,11 +408,14 @@ class AnonymousUser:
     def user_permissions(self):
         return self._user_permissions
 
+    def get_user_permissions(self, obj=None):
+        return _user_get_permissions(self, obj, 'user')
+
     def get_group_permissions(self, obj=None):
         return set()
 
     def get_all_permissions(self, obj=None):
-        return _user_get_all_permissions(self, obj=obj)
+        return _user_get_permissions(self, obj, 'all')
 
     def has_perm(self, perm, obj=None):
         return _user_has_perm(self, perm, obj=obj)

+ 15 - 2
docs/ref/contrib/auth.txt

@@ -191,6 +191,15 @@ Methods
         :meth:`~django.contrib.auth.models.User.set_unusable_password()` has
         been called for this user.
 
+    .. method:: get_user_permissions(obj=None)
+
+        .. versionadded:: 3.0
+
+        Returns a set of permission strings that the user has directly.
+
+        If ``obj`` is passed in, only returns the user permissions for this
+        specific object.
+
     .. method:: get_group_permissions(obj=None)
 
         Returns a set of permission strings that the user has, through their
@@ -467,14 +476,18 @@ The following backends are available in :mod:`django.contrib.auth.backends`:
     A base class that provides default implementations for all required
     methods. By default, it will reject any user and provide no permissions.
 
+    .. method:: get_user_permissions(user_obj, obj=None)
+
+        Returns an empty set.
+
     .. method:: get_group_permissions(user_obj, obj=None)
 
         Returns an empty set.
 
     .. method:: get_all_permissions(user_obj, obj=None)
 
-        Uses :meth:`get_group_permissions` to get the set of permission strings
-        the ``user_obj`` has.
+        Uses :meth:`get_user_permissions` and :meth:`get_group_permissions` to
+        get the set of permission strings the ``user_obj`` has.
 
     .. method:: has_perm(user_obj, perm, obj=None)
 

+ 4 - 0
docs/releases/3.0.txt

@@ -72,6 +72,10 @@ Minor features
 * Added :class:`~django.contrib.auth.backends.BaseBackend` class to ease
   customization of authentication backends.
 
+* Added :meth:`~django.contrib.auth.models.User.get_user_permissions()` method
+  to mirror the existing
+  :meth:`~django.contrib.auth.models.User.get_group_permissions()` method.
+
 :mod:`django.contrib.contenttypes`
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 

+ 11 - 1
docs/topics/auth/customizing.txt

@@ -180,7 +180,8 @@ Handling authorization in custom backends
 Custom auth backends can provide their own permissions.
 
 The user model will delegate permission lookup functions
-(:meth:`~django.contrib.auth.models.User.get_group_permissions()`,
+(:meth:`~django.contrib.auth.models.User.get_user_permissions()`,
+:meth:`~django.contrib.auth.models.User.get_group_permissions()`,
 :meth:`~django.contrib.auth.models.User.get_all_permissions()`,
 :meth:`~django.contrib.auth.models.User.has_perm()`, and
 :meth:`~django.contrib.auth.models.User.has_module_perms()`) to any
@@ -898,6 +899,15 @@ methods and attributes:
         Boolean. Designates that this user has all permissions without
         explicitly assigning them.
 
+    .. method:: models.PermissionsMixin.get_user_permissions(obj=None)
+
+        .. versionadded:: 3.0
+
+        Returns a set of permission strings that the user has directly.
+
+        If ``obj`` is passed in, only returns the user permissions for this
+        specific object.
+
     .. method:: models.PermissionsMixin.get_group_permissions(obj=None)
 
         Returns a set of permission strings that the user has, through their

+ 13 - 4
tests/auth_tests/test_auth_backends.py

@@ -21,6 +21,9 @@ from .models import (
 
 
 class SimpleBackend(BaseBackend):
+    def get_user_permissions(self, user_obj, obj=None):
+        return ['user_perm']
+
     def get_group_permissions(self, user_obj, obj=None):
         return ['group_perm']
 
@@ -31,13 +34,17 @@ class BaseBackendTest(TestCase):
     def setUpTestData(cls):
         cls.user = User.objects.create_user('test', 'test@example.com', 'test')
 
+    def test_get_user_permissions(self):
+        self.assertEqual(self.user.get_user_permissions(), {'user_perm'})
+
     def test_get_group_permissions(self):
         self.assertEqual(self.user.get_group_permissions(), {'group_perm'})
 
     def test_get_all_permissions(self):
-        self.assertEqual(self.user.get_all_permissions(), {'group_perm'})
+        self.assertEqual(self.user.get_all_permissions(), {'user_perm', 'group_perm'})
 
     def test_has_perm(self):
+        self.assertIs(self.user.has_perm('user_perm'), True)
         self.assertIs(self.user.has_perm('group_perm'), True)
         self.assertIs(self.user.has_perm('other_perm', TestObj()), False)
 
@@ -102,6 +109,7 @@ class BaseModelBackendTest:
         # reloading user to purge the _perm_cache
         user = self.UserModel._default_manager.get(pk=self.user.pk)
         self.assertEqual(user.get_all_permissions(), {'auth.test'})
+        self.assertEqual(user.get_user_permissions(), {'auth.test'})
         self.assertEqual(user.get_group_permissions(), set())
         self.assertIs(user.has_module_perms('Group'), False)
         self.assertIs(user.has_module_perms('auth'), True)
@@ -111,7 +119,8 @@ class BaseModelBackendTest:
         perm = Permission.objects.create(name='test3', content_type=content_type, codename='test3')
         user.user_permissions.add(perm)
         user = self.UserModel._default_manager.get(pk=self.user.pk)
-        self.assertEqual(user.get_all_permissions(), {'auth.test2', 'auth.test', 'auth.test3'})
+        expected_user_perms = {'auth.test2', 'auth.test', 'auth.test3'}
+        self.assertEqual(user.get_all_permissions(), expected_user_perms)
         self.assertIs(user.has_perm('test'), False)
         self.assertIs(user.has_perm('auth.test'), True)
         self.assertIs(user.has_perms(['auth.test2', 'auth.test3']), True)
@@ -121,8 +130,8 @@ class BaseModelBackendTest:
         group.permissions.add(perm)
         user.groups.add(group)
         user = self.UserModel._default_manager.get(pk=self.user.pk)
-        exp = {'auth.test2', 'auth.test', 'auth.test3', 'auth.test_group'}
-        self.assertEqual(user.get_all_permissions(), exp)
+        self.assertEqual(user.get_all_permissions(), {*expected_user_perms, 'auth.test_group'})
+        self.assertEqual(user.get_user_permissions(), expected_user_perms)
         self.assertEqual(user.get_group_permissions(), {'auth.test_group'})
         self.assertIs(user.has_perms(['auth.test3', 'auth.test_group']), True)
 

+ 1 - 0
tests/auth_tests/test_models.py

@@ -333,6 +333,7 @@ class AnonymousUserTests(SimpleTestCase):
         self.assertIs(self.user.is_superuser, False)
         self.assertEqual(self.user.groups.all().count(), 0)
         self.assertEqual(self.user.user_permissions.all().count(), 0)
+        self.assertEqual(self.user.get_user_permissions(), set())
         self.assertEqual(self.user.get_group_permissions(), set())
 
     def test_str(self):