Permalink
Browse files

Merge remote-tracking branch 'upstream/master'

  • Loading branch information...
boardman committed Feb 10, 2012
2 parents b22e805 + 54a4c80 commit 1d02e161e6794c47eb93332f5d2f076bd0c39897
@@ -6,3 +6,14 @@ Supported versions
``django-guardian`` supports Python 2.6/2.7 and Django 1.2+. Also, we support
``django-grappelli`` 2.3.5.
+Rules
+-----
+
+1. We would support both Python 2.7 and Python 2.6 (until Django drops support
+ for 2.6, if ever).
+2. We would support **two latest Django stable versions**. In example: once
+ Django 1.4 would become final, we are dropping support for Django 1.2 as
+ two last stable versions would be 1.3 and 1.4.
+3. Support for ``django-grappelli`` is somewhat experimental. Nevertheless,
+ our intention is **to support django-grappelli last stable version**.
+
View
@@ -46,7 +46,7 @@ def has_perm(self, user_obj, perm, obj=None):
user_obj = User.objects.get(pk=settings.ANONYMOUS_USER_ID)
# Do not check any further if user is not active
- if user_obj.is_active is not True:
+ if not user_obj.is_active:
return False
if len(perm.split('.')) > 1:
View
@@ -30,6 +30,12 @@ def permission_required(perm, lookup_variables=None, **kwargs):
login page, response with status code 403 is returned (
``django.http.HttpResponseForbidden`` instance or rendered template -
see :setting:`GUARDIAN_RENDER_403`). Defaults to ``False``.
+ :param accept_global_perms: if set to ``True``, then *object level
+ permission* would be required **only if user does NOT have global
+ permission** for target *model*. If turned on, makes this decorator
+ like an extension over standard
+ ``django.contrib.admin.decorators.permission_required`` as it would
+ check for global permissions first. Defaults to ``False``.
Examples::
@@ -53,6 +59,7 @@ def my_view(request, username, group_name):
login_url = kwargs.pop('login_url', settings.LOGIN_URL)
redirect_field_name = kwargs.pop('redirect_field_name', REDIRECT_FIELD_NAME)
return_403 = kwargs.pop('return_403', False)
+ accept_global_perms = kwargs.pop('accept_global_perms', False)
# Check if perm is given as string in order not to decorate
# view function itself which makes debugging harder
@@ -95,7 +102,8 @@ def _wrapped_view(request, *args, **kwargs):
# Handles both original and with object provided permission check
# as ``obj`` defaults to None
- if not request.user.has_perm(perm, obj):
+ has_perm = accept_global_perms and request.user.has_perm(perm)
+ if not has_perm and not request.user.has_perm(perm, obj):
if return_403:
if guardian_settings.RENDER_403:
try:
@@ -1,4 +1,20 @@
[
+ {
+ "pk": 1,
+ "model": "auth.group",
+ "fields": {
+ "name": "admins",
+ "permissions": []
+ }
+ },
+ {
+ "pk": 2,
+ "model": "auth.group",
+ "fields": {
+ "name": "jackGroup",
+ "permissions": []
+ }
+ },
{
"pk": -1,
"model": "auth.user",
@@ -34,21 +50,5 @@
"email": "",
"date_joined": "2010-05-28 04:02:34"
}
- },
- {
- "pk": 1,
- "model": "auth.group",
- "fields": {
- "name": "admins",
- "permissions": []
- }
- },
- {
- "pk": 2,
- "model": "auth.group",
- "fields": {
- "name": "jackGroup",
- "permissions": []
- }
}
]
@@ -353,7 +353,7 @@ def test_user_can_acces_owned_objects_only_unless_superuser(self):
class GrappelliGuardedModelAdminTests(TestCase):
- org_settings = copy.copy(settings)
+ org_installed_apps = copy.copy(settings.INSTALLED_APPS)
def _get_gma(self, attrs=None, name=None, model=None):
"""
@@ -370,7 +370,7 @@ def setUp(self):
settings.INSTALLED_APPS = ['grappelli'] + list(settings.INSTALLED_APPS)
def tearDown(self):
- globals()['settings'] = copy.copy(self.org_settings)
+ settings.INSTALLED_APPS = self.org_installed_apps
def test_get_obj_perms_manage_template(self):
gma = self._get_gma()
@@ -20,8 +20,8 @@ class PermissionRequiredTest(TestCase):
def setUp(self):
self.anon = AnonymousUser()
- self.user = User.objects.get(username='jack')
- self.group = Group.objects.get(name='jackGroup')
+ self.user = User.objects.get_or_create(username='jack')[0]
+ self.group = Group.objects.get_or_create(name='jackGroup')[0]
def _get_request(self, user=None):
if user is None:
@@ -169,6 +169,92 @@ def show_user(request, username):
else:
self.fail("Wrong arguments given but GuardianError not raised")
+ def test_user_has_no_access(self):
+
+ request = self._get_request()
+
+ @permission_required_or_403('auth.change_user')
+ def dummy_view(request):
+ return HttpResponse('dummy_view')
+ self.assertEqual(dummy_view(request).status_code, 403)
+
+ def test_user_has_access(self):
+
+ perm = 'auth.change_user'
+ joe, created = User.objects.get_or_create(username='joe')
+ assign(perm, self.user, obj=joe)
+
+ request = self._get_request(self.user)
+
+ @permission_required_or_403(perm, (
+ 'auth.User', 'username', 'username'))
+ def dummy_view(request, username):
+ return HttpResponse('dummy_view')
+ response = dummy_view(request, username='joe')
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'dummy_view')
+
+ def test_user_has_obj_access_even_if_we_also_check_for_global(self):
+
+ perm = 'auth.change_user'
+ joe, created = User.objects.get_or_create(username='joe')
+ assign(perm, self.user, obj=joe)
+
+ request = self._get_request(self.user)
+
+ @permission_required_or_403(perm, (
+ 'auth.User', 'username', 'username'), accept_global_perms=True)
+ def dummy_view(request, username):
+ return HttpResponse('dummy_view')
+ response = dummy_view(request, username='joe')
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'dummy_view')
+
+ def test_user_has_no_obj_perm_access(self):
+
+ perm = 'auth.change_user'
+ joe, created = User.objects.get_or_create(username='joe')
+
+ request = self._get_request(self.user)
+
+ @permission_required_or_403(perm, (
+ 'auth.User', 'username', 'username'))
+ def dummy_view(request, username):
+ return HttpResponse('dummy_view')
+ response = dummy_view(request, username='joe')
+ self.assertEqual(response.status_code, 403)
+
+ def test_user_has_global_perm_access_but_flag_not_set(self):
+
+ perm = 'auth.change_user'
+ joe, created = User.objects.get_or_create(username='joe')
+ assign(perm, self.user)
+
+ request = self._get_request(self.user)
+
+ @permission_required_or_403(perm, (
+ 'auth.User', 'username', 'username'))
+ def dummy_view(request, username):
+ return HttpResponse('dummy_view')
+ response = dummy_view(request, username='joe')
+ self.assertEqual(response.status_code, 403)
+
+ def test_user_has_global_perm_access(self):
+
+ perm = 'auth.change_user'
+ joe, created = User.objects.get_or_create(username='joe')
+ assign(perm, self.user)
+
+ request = self._get_request(self.user)
+
+ @permission_required_or_403(perm, (
+ 'auth.User', 'username', 'username'), accept_global_perms=True)
+ def dummy_view(request, username):
+ return HttpResponse('dummy_view')
+ response = dummy_view(request, username='joe')
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.content, 'dummy_view')
+
def test_model_lookup(self):
request = self._get_request(self.user)
View
@@ -35,5 +35,18 @@
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'tests', 'templates'),
)
-print TEMPLATE_DIRS
+
+# Database specific
+
+if os.environ.get('GUARDIAN_TEST_DB_BACKEND') == 'mysql':
+ DATABASES['default']['ENGINE'] = 'django.db.backends.mysql'
+ DATABASES['default']['NAME'] = 'guardian_test'
+ DATABASES['default']['TEST_NAME'] = 'guardian_test'
+ DATABASES['default']['USER'] = os.environ.get('USER', 'root')
+
+if os.environ.get('GUARDIAN_TEST_DB_BACKEND') == 'postgresql':
+ DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'
+ DATABASES['default']['NAME'] = 'guardian'
+ DATABASES['default']['TEST_NAME'] = 'guardian_test'
+ DATABASES['default']['USER'] = os.environ.get('USER', 'postgres')
View
27 tox.ini
@@ -8,13 +8,33 @@ envlist =
py27-grappelli,
py27-django12,
py27-django12-grappelli,
+ docs,
[testenv]
commands = python setup.py test
deps =
django==1.3.1
mock==0.7.2
+[testenv:mysql]
+setenv =
+ GUARDIAN_TEST_DB_BACKEND=mysql
+commands = python setup.py test
+deps =
+ django==1.3.1
+ mock==0.7.2
+ MySQL-python==1.2.3
+
+[testenv:postgresql]
+setenv =
+ GUARDIAN_TEST_DB_BACKEND=postgresql
+commands = python setup.py test
+deps =
+ django==1.3.1
+ mock==0.7.2
+ psycopg2==2.4.1
+# psycopg2==2.4.2 has troubles with test runner, see: https://code.djangoproject.com/ticket/16250
+
[testenv:py26-grappelli]
basepython = python2.6
deps =
@@ -55,3 +75,10 @@ deps =
mock==0.7.2
django-grappelli==2.3.5
+[testenv:docs]
+changedir = docs
+deps =
+ sphinx
+commands =
+ sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
+

0 comments on commit 1d02e16

Please sign in to comment.