Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge remote-tracking branch 'upstream/master'

  • Loading branch information...
commit 1d02e161e6794c47eb93332f5d2f076bd0c39897 2 parents b22e805 + 54a4c80
Roger Boardman authored February 10, 2012
11  docs/develop/supported-versions.rst
Source Rendered
@@ -6,3 +6,14 @@ Supported versions
6 6
 ``django-guardian`` supports Python 2.6/2.7 and Django 1.2+. Also, we support
7 7
 ``django-grappelli`` 2.3.5.
8 8
 
  9
+Rules
  10
+-----
  11
+
  12
+1. We would support both Python 2.7 and Python 2.6 (until Django drops support
  13
+   for 2.6, if ever).
  14
+2. We would support **two latest Django stable versions**. In example: once
  15
+   Django 1.4 would become final, we are dropping support for Django 1.2 as
  16
+   two last stable versions would be 1.3 and 1.4.
  17
+3. Support for ``django-grappelli`` is somewhat experimental. Nevertheless,
  18
+   our intention is **to support django-grappelli last stable version**.
  19
+
2  guardian/backends.py
@@ -46,7 +46,7 @@ def has_perm(self, user_obj, perm, obj=None):
46 46
             user_obj = User.objects.get(pk=settings.ANONYMOUS_USER_ID)
47 47
 
48 48
         # Do not check any further if user is not active
49  
-        if user_obj.is_active is not True:
  49
+        if not user_obj.is_active:
50 50
             return False
51 51
 
52 52
         if len(perm.split('.')) > 1:
10  guardian/decorators.py
@@ -30,6 +30,12 @@ def permission_required(perm, lookup_variables=None, **kwargs):
30 30
       login page, response with status code 403 is returned (
31 31
       ``django.http.HttpResponseForbidden`` instance or rendered template -
32 32
       see :setting:`GUARDIAN_RENDER_403`). Defaults to ``False``.
  33
+    :param accept_global_perms: if set to ``True``, then *object level
  34
+      permission* would be required **only if user does NOT have global
  35
+      permission** for target *model*. If turned on, makes this decorator
  36
+      like an extension over standard
  37
+      ``django.contrib.admin.decorators.permission_required`` as it would
  38
+      check for global permissions first. Defaults to ``False``.
33 39
 
34 40
     Examples::
35 41
 
@@ -53,6 +59,7 @@ def my_view(request, username, group_name):
53 59
     login_url = kwargs.pop('login_url', settings.LOGIN_URL)
54 60
     redirect_field_name = kwargs.pop('redirect_field_name', REDIRECT_FIELD_NAME)
55 61
     return_403 = kwargs.pop('return_403', False)
  62
+    accept_global_perms = kwargs.pop('accept_global_perms', False)
56 63
 
57 64
     # Check if perm is given as string in order not to decorate
58 65
     # view function itself which makes debugging harder
@@ -95,7 +102,8 @@ def _wrapped_view(request, *args, **kwargs):
95 102
 
96 103
             # Handles both original and with object provided permission check
97 104
             # as ``obj`` defaults to None
98  
-            if not request.user.has_perm(perm, obj):
  105
+            has_perm = accept_global_perms and request.user.has_perm(perm)
  106
+            if not has_perm and not request.user.has_perm(perm, obj):
99 107
                 if return_403:
100 108
                     if guardian_settings.RENDER_403:
101 109
                         try:
32  guardian/fixtures/tests.json
... ...
@@ -1,5 +1,21 @@
1 1
 [
2 2
     {
  3
+        "pk": 1, 
  4
+        "model": "auth.group", 
  5
+        "fields": {
  6
+            "name": "admins", 
  7
+            "permissions": []
  8
+        }
  9
+    },
  10
+    {
  11
+        "pk": 2,
  12
+        "model": "auth.group", 
  13
+        "fields": {
  14
+            "name": "jackGroup", 
  15
+            "permissions": []
  16
+        }
  17
+    },
  18
+    {
3 19
         "pk": -1, 
4 20
         "model": "auth.user", 
5 21
         "fields": {
@@ -34,21 +50,5 @@
34 50
             "email": "", 
35 51
             "date_joined": "2010-05-28 04:02:34"
36 52
         }
37  
-    }, 
38  
-    {
39  
-        "pk": 1, 
40  
-        "model": "auth.group", 
41  
-        "fields": {
42  
-            "name": "admins", 
43  
-            "permissions": []
44  
-        }
45  
-    },
46  
-    {
47  
-        "pk": 2,
48  
-        "model": "auth.group", 
49  
-        "fields": {
50  
-            "name": "jackGroup", 
51  
-            "permissions": []
52  
-        }
53 53
     }
54 54
 ]
4  guardian/tests/admin_test.py
@@ -353,7 +353,7 @@ def test_user_can_acces_owned_objects_only_unless_superuser(self):
353 353
 
354 354
 class GrappelliGuardedModelAdminTests(TestCase):
355 355
 
356  
-    org_settings = copy.copy(settings)
  356
+    org_installed_apps = copy.copy(settings.INSTALLED_APPS)
357 357
 
358 358
     def _get_gma(self, attrs=None, name=None, model=None):
359 359
         """
@@ -370,7 +370,7 @@ def setUp(self):
370 370
         settings.INSTALLED_APPS = ['grappelli'] + list(settings.INSTALLED_APPS)
371 371
 
372 372
     def tearDown(self):
373  
-        globals()['settings'] = copy.copy(self.org_settings)
  373
+        settings.INSTALLED_APPS = self.org_installed_apps
374 374
 
375 375
     def test_get_obj_perms_manage_template(self):
376 376
         gma = self._get_gma()
90  guardian/tests/decorators_test.py
@@ -20,8 +20,8 @@ class PermissionRequiredTest(TestCase):
20 20
 
21 21
     def setUp(self):
22 22
         self.anon = AnonymousUser()
23  
-        self.user = User.objects.get(username='jack')
24  
-        self.group = Group.objects.get(name='jackGroup')
  23
+        self.user = User.objects.get_or_create(username='jack')[0]
  24
+        self.group = Group.objects.get_or_create(name='jackGroup')[0]
25 25
 
26 26
     def _get_request(self, user=None):
27 27
         if user is None:
@@ -169,6 +169,92 @@ def show_user(request, username):
169 169
             else:
170 170
                 self.fail("Wrong arguments given but GuardianError not raised")
171 171
 
  172
+    def test_user_has_no_access(self):
  173
+
  174
+        request = self._get_request()
  175
+
  176
+        @permission_required_or_403('auth.change_user')
  177
+        def dummy_view(request):
  178
+            return HttpResponse('dummy_view')
  179
+        self.assertEqual(dummy_view(request).status_code, 403)
  180
+
  181
+    def test_user_has_access(self):
  182
+
  183
+        perm = 'auth.change_user'
  184
+        joe, created = User.objects.get_or_create(username='joe')
  185
+        assign(perm, self.user, obj=joe)
  186
+
  187
+        request = self._get_request(self.user)
  188
+
  189
+        @permission_required_or_403(perm, (
  190
+            'auth.User', 'username', 'username'))
  191
+        def dummy_view(request, username):
  192
+            return HttpResponse('dummy_view')
  193
+        response = dummy_view(request, username='joe')
  194
+        self.assertEqual(response.status_code, 200)
  195
+        self.assertEqual(response.content, 'dummy_view')
  196
+
  197
+    def test_user_has_obj_access_even_if_we_also_check_for_global(self):
  198
+
  199
+        perm = 'auth.change_user'
  200
+        joe, created = User.objects.get_or_create(username='joe')
  201
+        assign(perm, self.user, obj=joe)
  202
+
  203
+        request = self._get_request(self.user)
  204
+
  205
+        @permission_required_or_403(perm, (
  206
+            'auth.User', 'username', 'username'), accept_global_perms=True)
  207
+        def dummy_view(request, username):
  208
+            return HttpResponse('dummy_view')
  209
+        response = dummy_view(request, username='joe')
  210
+        self.assertEqual(response.status_code, 200)
  211
+        self.assertEqual(response.content, 'dummy_view')
  212
+
  213
+    def test_user_has_no_obj_perm_access(self):
  214
+
  215
+        perm = 'auth.change_user'
  216
+        joe, created = User.objects.get_or_create(username='joe')
  217
+
  218
+        request = self._get_request(self.user)
  219
+
  220
+        @permission_required_or_403(perm, (
  221
+            'auth.User', 'username', 'username'))
  222
+        def dummy_view(request, username):
  223
+            return HttpResponse('dummy_view')
  224
+        response = dummy_view(request, username='joe')
  225
+        self.assertEqual(response.status_code, 403)
  226
+
  227
+    def test_user_has_global_perm_access_but_flag_not_set(self):
  228
+
  229
+        perm = 'auth.change_user'
  230
+        joe, created = User.objects.get_or_create(username='joe')
  231
+        assign(perm, self.user)
  232
+
  233
+        request = self._get_request(self.user)
  234
+
  235
+        @permission_required_or_403(perm, (
  236
+            'auth.User', 'username', 'username'))
  237
+        def dummy_view(request, username):
  238
+            return HttpResponse('dummy_view')
  239
+        response = dummy_view(request, username='joe')
  240
+        self.assertEqual(response.status_code, 403)
  241
+
  242
+    def test_user_has_global_perm_access(self):
  243
+
  244
+        perm = 'auth.change_user'
  245
+        joe, created = User.objects.get_or_create(username='joe')
  246
+        assign(perm, self.user)
  247
+
  248
+        request = self._get_request(self.user)
  249
+
  250
+        @permission_required_or_403(perm, (
  251
+            'auth.User', 'username', 'username'), accept_global_perms=True)
  252
+        def dummy_view(request, username):
  253
+            return HttpResponse('dummy_view')
  254
+        response = dummy_view(request, username='joe')
  255
+        self.assertEqual(response.status_code, 200)
  256
+        self.assertEqual(response.content, 'dummy_view')
  257
+
172 258
     def test_model_lookup(self):
173 259
 
174 260
         request = self._get_request(self.user)
15  guardian/testsettings.py
@@ -35,5 +35,18 @@
35 35
 TEMPLATE_DIRS = (
36 36
     os.path.join(os.path.dirname(__file__), 'tests', 'templates'),
37 37
 )
38  
-print TEMPLATE_DIRS
  38
+
  39
+# Database specific
  40
+
  41
+if os.environ.get('GUARDIAN_TEST_DB_BACKEND') == 'mysql':
  42
+    DATABASES['default']['ENGINE'] = 'django.db.backends.mysql'
  43
+    DATABASES['default']['NAME'] = 'guardian_test'
  44
+    DATABASES['default']['TEST_NAME'] = 'guardian_test'
  45
+    DATABASES['default']['USER'] = os.environ.get('USER', 'root')
  46
+
  47
+if os.environ.get('GUARDIAN_TEST_DB_BACKEND') == 'postgresql':
  48
+    DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
  49
+    DATABASES['default']['NAME'] = 'guardian'
  50
+    DATABASES['default']['TEST_NAME'] = 'guardian_test'
  51
+    DATABASES['default']['USER'] = os.environ.get('USER', 'postgres')
39 52
 
27  tox.ini
@@ -8,6 +8,7 @@ envlist =
8 8
     py27-grappelli,
9 9
     py27-django12,
10 10
     py27-django12-grappelli,
  11
+    docs,
11 12
 
12 13
 [testenv]
13 14
 commands = python setup.py test
@@ -15,6 +16,25 @@ deps =
15 16
     django==1.3.1
16 17
     mock==0.7.2
17 18
 
  19
+[testenv:mysql]
  20
+setenv =
  21
+    GUARDIAN_TEST_DB_BACKEND=mysql
  22
+commands = python setup.py test
  23
+deps = 
  24
+    django==1.3.1
  25
+    mock==0.7.2
  26
+    MySQL-python==1.2.3
  27
+
  28
+[testenv:postgresql]
  29
+setenv =
  30
+    GUARDIAN_TEST_DB_BACKEND=postgresql
  31
+commands = python setup.py test
  32
+deps = 
  33
+    django==1.3.1
  34
+    mock==0.7.2
  35
+    psycopg2==2.4.1
  36
+# psycopg2==2.4.2 has troubles with test runner, see: https://code.djangoproject.com/ticket/16250
  37
+
18 38
 [testenv:py26-grappelli]
19 39
 basepython = python2.6
20 40
 deps = 
@@ -55,3 +75,10 @@ deps =
55 75
     mock==0.7.2
56 76
     django-grappelli==2.3.5
57 77
 
  78
+[testenv:docs]
  79
+changedir = docs
  80
+deps =
  81
+    sphinx
  82
+commands =
  83
+    sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
  84
+

0 notes on commit 1d02e16

Please sign in to comment.
Something went wrong with that request. Please try again.