Ticket #5457: full_diff

File full_diff, 9.0 KB (added by Florian Apolloner, 17 years ago)

full diff including docs and tests (I hope everything works, as I am really tired now XD)

Line 
1Index: django/contrib/auth/backends.py
2===================================================================
3--- django/contrib/auth/backends.py (revision 6184)
4+++ django/contrib/auth/backends.py (working copy)
5@@ -1,3 +1,4 @@
6+from django.db import connection, models
7 from django.contrib.auth.models import User
8
9 class ModelBackend:
10@@ -14,6 +15,51 @@
11 except User.DoesNotExist:
12 return None
13
14+ def get_group_permissions(self, user_obj):
15+ "Returns a list of permission strings that this user has through his/her groups."
16+ if not hasattr(user_obj, '_group_perm_cache'):
17+ cursor = connection.cursor()
18+ # The SQL below works out to the following, after DB quoting:
19+ # cursor.execute("""
20+ # SELECT ct."app_label", p."codename"
21+ # FROM "auth_permission" p, "auth_group_permissions" gp, "auth_user_groups" ug, "django_content_type" ct
22+ # WHERE p."id" = gp."permission_id"
23+ # AND gp."group_id" = ug."group_id"
24+ # AND ct."id" = p."content_type_id"
25+ # AND ug."user_id" = %s, [self.id])
26+ qn = connection.ops.quote_name
27+ sql = """
28+ SELECT ct.%s, p.%s
29+ FROM %s p, %s gp, %s ug, %s ct
30+ WHERE p.%s = gp.%s
31+ AND gp.%s = ug.%s
32+ AND ct.%s = p.%s
33+ AND ug.%s = %%s""" % (
34+ qn('app_label'), qn('codename'),
35+ qn('auth_permission'), qn('auth_group_permissions'),
36+ qn('auth_user_groups'), qn('django_content_type'),
37+ qn('id'), qn('permission_id'),
38+ qn('group_id'), qn('group_id'),
39+ qn('id'), qn('content_type_id'),
40+ qn('user_id'),)
41+ cursor.execute(sql, [user_obj.id])
42+ user_obj._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
43+ return user_obj._group_perm_cache
44+
45+ def get_all_permissions(self, user_obj):
46+ if not hasattr(user_obj, '_perm_cache'):
47+ user_obj._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in user_obj.user_permissions.select_related()])
48+ user_obj._perm_cache.update(self.get_group_permissions(user_obj))
49+ return user_obj._perm_cache
50+
51+ def has_perm(self, user_obj, perm):
52+ return perm in self.get_all_permissions(user_obj)
53+
54+ def has_module_perms(self, user_obj, app_label):
55+ return bool(len([p for p in self.get_all_permissions(user_obj) if p[:p.index('.')] == app_label]))
56+
57+
58+
59 def get_user(self, user_id):
60 try:
61 return User.objects.get(pk=user_id)
62Index: django/contrib/auth/models.py
63===================================================================
64--- django/contrib/auth/models.py (revision 6184)
65+++ django/contrib/auth/models.py (working copy)
66@@ -1,3 +1,4 @@
67+from django.contrib.auth import get_backends
68 from django.core import validators
69 from django.core.exceptions import ImproperlyConfigured
70 from django.db import connection, models
71@@ -177,49 +178,41 @@
72 return self.password != UNUSABLE_PASSWORD
73
74 def get_group_permissions(self):
75- "Returns a list of permission strings that this user has through his/her groups."
76- if not hasattr(self, '_group_perm_cache'):
77- cursor = connection.cursor()
78- # The SQL below works out to the following, after DB quoting:
79- # cursor.execute("""
80- # SELECT ct."app_label", p."codename"
81- # FROM "auth_permission" p, "auth_group_permissions" gp, "auth_user_groups" ug, "django_content_type" ct
82- # WHERE p."id" = gp."permission_id"
83- # AND gp."group_id" = ug."group_id"
84- # AND ct."id" = p."content_type_id"
85- # AND ug."user_id" = %s, [self.id])
86- qn = connection.ops.quote_name
87- sql = """
88- SELECT ct.%s, p.%s
89- FROM %s p, %s gp, %s ug, %s ct
90- WHERE p.%s = gp.%s
91- AND gp.%s = ug.%s
92- AND ct.%s = p.%s
93- AND ug.%s = %%s""" % (
94- qn('app_label'), qn('codename'),
95- qn('auth_permission'), qn('auth_group_permissions'),
96- qn('auth_user_groups'), qn('django_content_type'),
97- qn('id'), qn('permission_id'),
98- qn('group_id'), qn('group_id'),
99- qn('id'), qn('content_type_id'),
100- qn('user_id'),)
101- cursor.execute(sql, [self.id])
102- self._group_perm_cache = set(["%s.%s" % (row[0], row[1]) for row in cursor.fetchall()])
103- return self._group_perm_cache
104+ """
105+ Returns a list of permission strings that this user has through his/her groups.
106+ This method queries the available backends.
107+ """
108+ group_permissions = set([])
109+ for backend in get_backends():
110+ # Backend does not support this method, so skip it
111+ if not hasattr(backend, "get_group_permissions"): continue
112+ group_permissions.update(backend.get_group_permissions(self))
113+ return group_permissions
114
115 def get_all_permissions(self):
116- if not hasattr(self, '_perm_cache'):
117- self._perm_cache = set([u"%s.%s" % (p.content_type.app_label, p.codename) for p in self.user_permissions.select_related()])
118- self._perm_cache.update(self.get_group_permissions())
119- return self._perm_cache
120+ permissions = set([])
121+ for backend in get_backends():
122+ # Backend does not support this method, so skip it
123+ if not hasattr(backend, "get_all_permissions"): continue
124+ permissions.update(backend.get_all_permissions(self))
125+ return permissions
126
127 def has_perm(self, perm):
128- "Returns True if the user has the specified permission."
129+ """
130+ Returns True if the user has the specified permission.
131+ This method queries the available backends and stops on
132+ the first "True".
133+ """
134 if not self.is_active:
135 return False
136 if self.is_superuser:
137 return True
138- return perm in self.get_all_permissions()
139+ for backend in get_backends():
140+ # Backend does not support this method, so skip it
141+ if not hasattr(backend, "has_perm"): continue
142+ if backend.has_perm(self, perm):
143+ return True
144+ return False
145
146 def has_perms(self, perm_list):
147 "Returns True if the user has each of the specified permissions."
148@@ -229,12 +222,21 @@
149 return True
150
151 def has_module_perms(self, app_label):
152- "Returns True if the user has any permissions in the given app label."
153+ """
154+ Returns True if the user has any permissions in the given app label.
155+ This method queries the available backends and stops on
156+ the first "True".
157+ """
158 if not self.is_active:
159 return False
160 if self.is_superuser:
161 return True
162- return bool(len([p for p in self.get_all_permissions() if p[:p.index('.')] == app_label]))
163+ for backend in get_backends():
164+ # Backend does not support this method, so skip it
165+ if not hasattr(backend, "has_module_perms"): continue
166+ if backend.has_module_perms(self, app_label):
167+ return True
168+ return False
169
170 def get_and_delete_messages(self):
171 messages = []
172Index: docs/authentication.txt
173===================================================================
174--- docs/authentication.txt (revision 6184)
175+++ docs/authentication.txt (working copy)
176@@ -1041,3 +1041,26 @@
177 return User.objects.get(pk=user_id)
178 except User.DoesNotExist:
179 return None
180+
181+Optionally the Backend allows you to specify any of the permission methods of
182+the ``User`` object (except from ``has_perms`` which calls ``has_perm`` for each
183+perm in the list, and ``has_perm`` can be specified in the backend).
184+This will allow your backend to handle the permissions, if one backend return
185+``True`` in a permission check, the user will have the permission.
186+
187+Here is an sample implementation for ``has_perm`` extending the above exmaple::
188+
189+ # The permission functions all take the user_obj as first (besides the self of
190+ # the backend, of course) argument and the rest
191+ # is as you would call it with ``User.*``
192+ def has_perm(self, user_obj, perm):
193+ # we give the user admin the right to do everything.
194+ if user_obj.username == "admin":
195+ return True
196+ else:
197+ return False
198+
199+A full implementation can be found in ``django/contrib/auth/backends.py`` _, which is the
200+default backend and queries the ``auth_permission``-table most of the time.
201+
202+.. _django/contrib/auth/backends.py: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/backends.py
Back to Top