[Python-modules-commits] [django-guardian] 08/13: Import django-guardian_1.3.orig.tar.gz

Brian May bam at moszumanska.debian.org
Tue Nov 3 10:02:00 UTC 2015


This is an automated email from the git hooks/post-receive script.

bam pushed a commit to branch master
in repository django-guardian.

commit 94753ae8e998c63b43db42d8921dd6c8804c59b3
Author: Brian May <brian at linuxpenguins.xyz>
Date:   Tue Nov 3 19:50:17 2015 +1100

    Import django-guardian_1.3.orig.tar.gz
---
 .travis.yml                                        |  27 ++--
 AUTHORS                                            |   4 +
 CHANGES                                            |  11 +-
 benchmarks/run_benchmarks.py                       |  14 +-
 docs/userguide/assign.rst                          |   5 +-
 example_project/settings.py                        |   6 +-
 guardian/__init__.py                               |   2 +-
 guardian/admin.py                                  |  16 +-
 guardian/backends.py                               |  70 ++++++---
 guardian/compat.py                                 |  18 ++-
 guardian/management/__init__.py                    |   5 +-
 guardian/migrations/0001_initial.py                | 163 +++++++--------------
 guardian/models.py                                 |   7 +-
 guardian/shortcuts.py                              |  78 +++++++++-
 .../0001_initial.py                                |   0
 ...tpermission_object_pk__add_field_userobjectp.py |   0
 .../0003_update_objectpermission_object_pk.py      |   0
 ...tpermission_object_id__del_unique_groupobjec.py |   0
 ...tpermission_object_pk__chg_field_userobjectp.py |   0
 guardian/south_migrations/__init__.py              |   0
 guardian/templatetags/guardian_tags.py             |  10 +-
 guardian/testapp/migrations/0001_initial.py        |   2 +-
 guardian/testapp/tests/admin_test.py               |   4 +-
 guardian/testapp/tests/direct_rel_test.py          |  16 ++
 guardian/testapp/tests/orphans_test.py             |   5 +-
 guardian/testapp/tests/shortcuts_test.py           | 157 +++++++++++++++++++-
 guardian/testsettings.py                           |   5 +-
 tests.py                                           |   9 +-
 tox.ini                                            |  18 +++
 29 files changed, 471 insertions(+), 181 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index e74e6b4..b7b81be 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,19 +1,23 @@
 language: python
+sudo: false
 python:
  - 2.6
  - 2.7
  - 3.3
+ - 3.4
 
 env:
  - DJANGO_VERSION=1.2.7
  - DJANGO_VERSION=1.3.7
- - DJANGO_VERSION=1.4.16
- - DJANGO_VERSION=1.5.11
- - DJANGO_VERSION=1.6.8
+ - DJANGO_VERSION=1.4.19
+ - DJANGO_VERSION=1.5.12
+ - DJANGO_VERSION=1.6.10
+ - DJANGO_VERSION=1.7.4
+ - DJANGO_VERSION=1.8
 
 install:
-  - pip install -q mock==0.8 Django==$DJANGO_VERSION coverage coveralls
-  - pip install . --use-mirrors
+  - travis_retry pip install -q mock==1.0.1 Django==$DJANGO_VERSION coverage coveralls
+  - travis_retry pip install --use-mirrors
 
 script:
   - coverage run --source=guardian setup.py test
@@ -33,9 +37,12 @@ matrix:
         - python: 3.3
           env: DJANGO_VERSION=1.3.7
         - python: 3.3
-          env: DJANGO_VERSION=1.4.16
-    include:
-        - python: 3.3
-          env: DJANGO_VERSION=1.7.1
+          env: DJANGO_VERSION=1.4.19
+        - python: 3.4
+          env: DJANGO_VERSION=1.2.7
+        - python: 3.4
+          env: DJANGO_VERSION=1.3.7
         - python: 3.4
-          env: DJANGO_VERSION=1.7.1
+          env: DJANGO_VERSION=1.4.19
+        - python: 2.6
+        - env: DJANGO_VERSION=1.7.4
diff --git a/AUTHORS b/AUTHORS
index 57da6ac..f8c96cc 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -50,3 +50,7 @@ Authors ordered by first contribution
 - Morgan Aubert <morgan.aubert at zoho.com>
 - Brian May <brian at microcomaustralia.com.au>
 - Troy Grosfield <troy.grosfield at gmail.com>
+- Michael Drescher <kaesemeister at gmail.com>
+- Verena Jaspersen <verena.jaspersen at gmail.com>
+- Bertrand Svetchine <bertrand.svetchine at gmail.com>
+- Frank Wickström <frank at bambuser.com>
diff --git a/CHANGES b/CHANGES
index f99e6db..2a6bfb2 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,11 +1,18 @@
-Release DEV
-===========
+Release 1.3 (Jun 3, 2015)
+=========================
+
+* Official Django 1.8 support (thanks to multiple contributors)
+
+
+Release 1.2.5 (Dec 28, 2014)
+============================
 
 * Official Django 1.7 support (thanks Troy Grosfield and Brian May)
 * Allow to override ``PermissionRequiredMixin.get_permission_object``, part
   of ``PermissionRequiredMixin.check_permissions`` method, responsible for
   retrieving single object (Thanks zauddelig)
 * French translations (Thanks Morgan Aubert)
+* Added support for ``User.get_all_permissions`` (thanks Michael Drescher)
 
 Release 1.2.4 (Jul 14, 2014)
 ============================
diff --git a/benchmarks/run_benchmarks.py b/benchmarks/run_benchmarks.py
index 7dc984d..cb67228 100644
--- a/benchmarks/run_benchmarks.py
+++ b/benchmarks/run_benchmarks.py
@@ -34,6 +34,7 @@ settings.INSTALLED_APPS = (
 )
 
 from utils import show_settings
+import django
 from django.contrib.auth.models import User, Group
 from django.utils.termcolors import colorize
 from benchmarks.models import TestModel
@@ -47,6 +48,17 @@ def random_string(length=25, chars=string.ascii_letters+string.digits):
     return ''.join(random.choice(chars) for i in range(length))
 
 
+def get_model_name(model):
+    """
+    Returns the name of the model
+    """
+    # model._meta.module_name is deprecated in django version 1.7 and removed in django version 1.8.
+    # It is replaced by model._meta.model_name
+    if django.VERSION < (1, 7):
+        return model._meta.module_name
+    return model._meta.model_name
+
+
 class Call(object):
     def __init__(self, args, kwargs, start=None, finish=None):
         self.args = args
@@ -94,7 +106,7 @@ class Benchmark(object):
         self.objects_with_perms_count = objects_with_perms_count
 
         self.Model = model
-        self.perm = 'auth.change_%s' % model._meta.module_name
+        self.perm = 'auth.change_%s' % get_model_name(model)
 
     def info(self, msg):
         print(colorize(msg + '\n', fg='green'))
diff --git a/docs/userguide/assign.rst b/docs/userguide/assign.rst
index b76b3e9..551b7d6 100644
--- a/docs/userguide/assign.rst
+++ b/docs/userguide/assign.rst
@@ -36,8 +36,9 @@ model could look like:
                 ('view_task', 'View task'),
             )
 
-After we call ``syncdb`` management command our *view_task* permission would be
-added to default set of permissions.
+After we call ``syncdb`` (with a ``--all`` switch if you are using south)
+management command our *view_task* permission would be added to default set of
+permissions.
 
 .. note::
    By default, Django adds 3 permissions for each registered model:
diff --git a/example_project/settings.py b/example_project/settings.py
index 7f0eb88..02291df 100644
--- a/example_project/settings.py
+++ b/example_project/settings.py
@@ -33,7 +33,6 @@ INSTALLED_APPS = (
     'django.contrib.sites',
     'django.contrib.admin',
     'django.contrib.messages',
-    'django.contrib.staticfiles',
     'guardian',
     'guardian.testapp',
     'posts',
@@ -104,7 +103,10 @@ USE_L10N = True
 
 LOGIN_REDIRECT_URL = '/'
 
-TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner'
+if django.VERSION < (1, 8):
+    TEST_RUNNER = 'django.test.simple.DjangoTestSuiteRunner'
+else:
+    TEST_RUNNER = 'django.test.runner.DiscoverRunner'
 
 AUTHENTICATION_BACKENDS = (
     'django.contrib.auth.backends.ModelBackend',
diff --git a/guardian/__init__.py b/guardian/__init__.py
index 51a1c76..0d8d71e 100644
--- a/guardian/__init__.py
+++ b/guardian/__init__.py
@@ -3,7 +3,7 @@ Implementation of per object permissions for Django 1.2 or later.
 """
 from __future__ import unicode_literals
 
-VERSION = (1, 2, 5, 'dev')
+VERSION = (1, 3)
 
 __version__ = '.'.join((str(each) for each in VERSION[:4]))
 
diff --git a/guardian/admin.py b/guardian/admin.py
index e2a54f2..5c83454 100644
--- a/guardian/admin.py
+++ b/guardian/admin.py
@@ -1,5 +1,6 @@
 from __future__ import unicode_literals
 
+import django
 from django import forms
 from django.conf import settings
 from guardian.compat import url, patterns
@@ -12,7 +13,7 @@ from django.template import RequestContext
 from django.utils.datastructures import SortedDict
 from django.utils.translation import ugettext, ugettext_lazy as _
 
-from guardian.compat import get_user_model
+from guardian.compat import get_user_model, get_model_name
 from guardian.forms import UserObjectPermissionsForm
 from guardian.forms import GroupObjectPermissionsForm
 from guardian.shortcuts import get_perms
@@ -65,7 +66,7 @@ class GuardedModelAdminMixin(object):
         # backward compatibility
         method = getattr(
             super(GuardedModelAdminMixin, self), 'get_queryset',
-            super(GuardedModelAdminMixin, self).queryset)
+            getattr(super(GuardedModelAdminMixin, self), 'queryset', None))
         qs = method(request)
 
         if request.user.is_superuser:
@@ -85,7 +86,6 @@ class GuardedModelAdminMixin(object):
     # Allow queryset method as fallback for Django versions < 1.6
     # for versions >= 1.6 this is taken care of by Django itself
     # and triggers a warning message automatically.
-    import django
     if django.VERSION < (1, 6):
         queryset = get_queryset
 
@@ -104,7 +104,7 @@ class GuardedModelAdminMixin(object):
         """
         urls = super(GuardedModelAdminMixin, self).get_urls()
         if self.include_object_permissions_urls:
-            info = self.model._meta.app_label, self.model._meta.module_name
+            info = self.model._meta.app_label, get_model_name(self.model)
             myurls = patterns('',
                 url(r'^(?P<object_pk>.+)/permissions/$',
                     view=self.admin_site.admin_view(self.obj_perms_manage_view),
@@ -165,7 +165,7 @@ class GuardedModelAdminMixin(object):
             info = (
                 self.admin_site.name,
                 self.model._meta.app_label,
-                self.model._meta.module_name
+                get_model_name(self.model)
             )
             if user_form.is_valid():
                 user_id = user_form.cleaned_data['user'].pk
@@ -180,7 +180,7 @@ class GuardedModelAdminMixin(object):
             info = (
                 self.admin_site.name,
                 self.model._meta.app_label,
-                self.model._meta.module_name
+                get_model_name(self.model)
             )
             if group_form.is_valid():
                 group_id = group_form.cleaned_data['group'].id
@@ -232,7 +232,7 @@ class GuardedModelAdminMixin(object):
             info = (
                 self.admin_site.name,
                 self.model._meta.app_label,
-                self.model._meta.module_name
+                get_model_name(self.model)
             )
             url = reverse(
                 '%s:%s_%s_permissions_manage_user' % info,
@@ -285,7 +285,7 @@ class GuardedModelAdminMixin(object):
             info = (
                 self.admin_site.name,
                 self.model._meta.app_label,
-                self.model._meta.module_name
+                get_model_name(self.model)
             )
             url = reverse(
                 '%s:%s_%s_permissions_manage_group' % info,
diff --git a/guardian/backends.py b/guardian/backends.py
index 2839f05..66f41a8 100644
--- a/guardian/backends.py
+++ b/guardian/backends.py
@@ -7,6 +7,45 @@ from guardian.conf import settings
 from guardian.exceptions import WrongAppError
 from guardian.core import ObjectPermissionChecker
 
+
+def check_object_support(obj):
+    """
+    Returns ``True`` if given ``obj`` is supported
+    """
+    # Backend checks only object permissions (isinstance implies that obj
+    # is not None)
+    # Backend checks only permissions for Django models
+    return isinstance(obj, models.Model)
+
+
+def check_user_support(user_obj):
+    """
+    Returns a tuple of checkresult and ``user_obj`` which should be used for
+    permission checks
+
+    Checks if the given user is supported. Anonymous users need explicit
+    activation via ANONYMOUS_USER_ID
+    """
+    # This is how we support anonymous users - simply try to retrieve User
+    # instance and perform checks for that predefined user
+    if not user_obj.is_authenticated():
+        # If anonymous user permission is disabled then they are always unauthorized
+        if settings.ANONYMOUS_USER_ID is None:
+            return False, user_obj
+        user_obj = get_user_model().objects.get(pk=settings.ANONYMOUS_USER_ID)
+
+    return True, user_obj
+
+
+def check_support(user_obj, obj):
+    """
+    Combination of ``check_object_support`` and ``check_user_support``
+    """
+    obj_support = check_object_support(obj)
+    user_support, user_obj = check_user_support(user_obj)
+    return obj_support and user_support, user_obj
+
+
 class ObjectPermissionBackend(object):
     supports_object_permissions = True
     supports_anonymous_user = True
@@ -34,24 +73,10 @@ class ObjectPermissionBackend(object):
         If user is authenticated but inactive at the same time, all checks
         always returns ``False``.
         """
-        # Backend checks only object permissions
-        if obj is None:
-            return False
-
-        # Backend checks only permissions for Django models
-        if not isinstance(obj, models.Model):
-            return False
-
-        # This is how we support anonymous users - simply try to retrieve User
-        # instance and perform checks for that predefined user
-        if not user_obj.is_authenticated():
-            # If anonymous user permission is disabled then they are always unauthorized
-            if settings.ANONYMOUS_USER_ID is None:
-                return False
-            user_obj = get_user_model().objects.get(pk=settings.ANONYMOUS_USER_ID)
 
-        # Do not check any further if user is not active
-        if not user_obj.is_active:
+        # check if user_obj and object are supported
+        support, user_obj = check_support(user_obj, obj)
+        if not support:
             return False
 
         if '.' in perm:
@@ -63,3 +88,14 @@ class ObjectPermissionBackend(object):
         check = ObjectPermissionChecker(user_obj)
         return check.has_perm(perm, obj)
 
+    def get_all_permissions(self, user_obj, obj=None):
+        """
+        Returns a set of permission strings that the given ``user_obj`` has for ``obj``
+        """
+        # check if user_obj and object are supported
+        support, user_obj = check_support(user_obj, obj)
+        if not support:
+            return set()
+
+        check = ObjectPermissionChecker(user_obj)
+        return check.get_perms(obj)
diff --git a/guardian/compat.py b/guardian/compat.py
index 160125c..387903f 100644
--- a/guardian/compat.py
+++ b/guardian/compat.py
@@ -1,14 +1,19 @@
 from __future__ import unicode_literals
 
+import django
 from django.conf import settings
 from django.contrib.auth.models import Group
 from django.contrib.auth.models import Permission
 from django.contrib.auth.models import AnonymousUser
-from django.utils.importlib import import_module
 import six
 import sys
 
 try:
+    from importlib import import_module
+except ImportError:
+    from django.utils.importlib import import_module
+
+try:
     from django.conf.urls import url, patterns, include, handler404, handler500
 except ImportError:
     from django.conf.urls.defaults import url, patterns, include, handler404, handler500 # pyflakes:ignore
@@ -129,3 +134,14 @@ def create_permissions(*args, **kwargs):
     return original_create_permissions(*args, **kwargs)
 
 __all__ = ['User', 'Group', 'Permission', 'AnonymousUser']
+
+
+def get_model_name(model):
+    """
+    Returns the name of the model
+    """
+    # model._meta.module_name is deprecated in django version 1.7 and removed in django version 1.8.
+    # It is replaced by model._meta.model_name
+    if django.VERSION < (1, 7):
+        return model._meta.module_name
+    return model._meta.model_name
diff --git a/guardian/management/__init__.py b/guardian/management/__init__.py
index f66c9fc..5f38daf 100644
--- a/guardian/management/__init__.py
+++ b/guardian/management/__init__.py
@@ -31,9 +31,9 @@ def create_anonymous_user(sender, **kwargs):
         User.objects.get(pk=guardian_settings.ANONYMOUS_USER_ID)
     except User.DoesNotExist:
         if django.VERSION >= (1, 5):
-            retrieve_anonymous_functon = import_string(
+            retrieve_anonymous_function = import_string(
                 guardian_settings.GET_INIT_ANONYMOUS_USER)
-            user = retrieve_anonymous_functon(User)
+            user = retrieve_anonymous_function(User)
             # Always set pk to the one pointed at settings
             user.pk = guardian_settings.ANONYMOUS_USER_ID
             user.save()
@@ -45,4 +45,3 @@ def create_anonymous_user(sender, **kwargs):
 if guardian_settings.ANONYMOUS_USER_ID is not None:
     signals.post_syncdb.connect(create_anonymous_user, sender=guardian_app,
         dispatch_uid="guardian.management.create_anonymous_user")
-
diff --git a/guardian/migrations/0001_initial.py b/guardian/migrations/0001_initial.py
index bc491b7..94a5da7 100644
--- a/guardian/migrations/0001_initial.py
+++ b/guardian/migrations/0001_initial.py
@@ -1,112 +1,51 @@
-# encoding: utf-8
-from south.db import db
-from south.v2 import SchemaMigration
-
-from guardian.compat import user_model_label
-from guardian.compat import get_user_model
-
-User = get_user_model()
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-
-        # Adding model 'UserObjectPermission'
-        db.create_table('guardian_userobjectpermission', (
-            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('permission', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.Permission'])),
-            ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
-            ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
-            ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm[user_model_label])),
-        ))
-        db.send_create_signal('guardian', ['UserObjectPermission'])
-
-        # Adding unique constraint on 'UserObjectPermission', fields ['user', 'permission', 'content_type', 'object_id']
-        db.create_unique('guardian_userobjectpermission', ['user_id', 'permission_id', 'content_type_id', 'object_id'])
-
-        # Adding model 'GroupObjectPermission'
-        db.create_table('guardian_groupobjectpermission', (
-            ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
-            ('permission', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.Permission'])),
-            ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
-            ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
-            ('group', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.Group'])),
-        ))
-        db.send_create_signal('guardian', ['GroupObjectPermission'])
-
-        # Adding unique constraint on 'GroupObjectPermission', fields ['group', 'permission', 'content_type', 'object_id']
-        db.create_unique('guardian_groupobjectpermission', ['group_id', 'permission_id', 'content_type_id', 'object_id'])
-
-
-    def backwards(self, orm):
-
-        # Removing unique constraint on 'GroupObjectPermission', fields ['group', 'permission', 'content_type', 'object_id']
-        db.delete_unique('guardian_groupobjectpermission', ['group_id', 'permission_id', 'content_type_id', 'object_id'])
-
-        # Removing unique constraint on 'UserObjectPermission', fields ['user', 'permission', 'content_type', 'object_id']
-        db.delete_unique('guardian_userobjectpermission', ['user_id', 'permission_id', 'content_type_id', 'object_id'])
-
-        # Deleting model 'UserObjectPermission'
-        db.delete_table('guardian_userobjectpermission')
-
-        # Deleting model 'GroupObjectPermission'
-        db.delete_table('guardian_groupobjectpermission')
-
-
-    models = {
-        'auth.group': {
-            'Meta': {'object_name': 'Group'},
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
-            'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
-        },
-        'auth.permission': {
-            'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
-            'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
-        },
-        user_model_label: {
-            'Meta': {'object_name': user_model_label.split('.')[-1], 'db_table': "'%s'" % User._meta.db_table},
-            'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
-            'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
-            'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
-            'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
-            'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
-            'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
-            'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
-            'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
-        },
-        'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        'guardian.groupobjectpermission': {
-            'Meta': {'unique_together': "(['group', 'permission', 'content_type', 'object_id'],)", 'object_name': 'GroupObjectPermission'},
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
-            'group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Group']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Permission']"})
-        },
-        'guardian.userobjectpermission': {
-            'Meta': {'unique_together': "(['user', 'permission', 'content_type', 'object_id'],)", 'object_name': 'UserObjectPermission'},
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
-            'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'permission': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.Permission']"}),
-            'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['%s']" % user_model_label})
-        }
-    }
-
-    complete_apps = ['guardian']
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import models, migrations
+from django.conf import settings
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0001_initial'),
+        ('auth', '0001_initial'),
+        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='GroupObjectPermission',
+            fields=[
+                ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')),
+                ('object_pk', models.CharField(max_length=255, verbose_name='object ID')),
+                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
+                ('group', models.ForeignKey(to='auth.Group')),
+                ('permission', models.ForeignKey(to='auth.Permission')),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.CreateModel(
+            name='UserObjectPermission',
+            fields=[
+                ('id', models.AutoField(primary_key=True, serialize=False, auto_created=True, verbose_name='ID')),
+                ('object_pk', models.CharField(max_length=255, verbose_name='object ID')),
+                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
+                ('permission', models.ForeignKey(to='auth.Permission')),
+                ('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
+            ],
+            options={
+            },
+            bases=(models.Model,),
+        ),
+        migrations.AlterUniqueTogether(
+            name='userobjectpermission',
+            unique_together=set([('user', 'permission', 'object_pk')]),
+        ),
+        migrations.AlterUniqueTogether(
+            name='groupobjectpermission',
+            unique_together=set([('group', 'permission', 'object_pk')]),
+        ),
+    ]
diff --git a/guardian/models.py b/guardian/models.py
index bbff1db..c9ab496 100644
--- a/guardian/models.py
+++ b/guardian/models.py
@@ -5,7 +5,12 @@ from django.core.exceptions import ValidationError
 from django.contrib.auth.models import Group
 from django.contrib.auth.models import Permission
 from django.contrib.contenttypes.models import ContentType
-from django.contrib.contenttypes.generic import GenericForeignKey
+
+try:
+    from django.contrib.contenttypes.fields import GenericForeignKey
+except ImportError:
+    from django.contrib.contenttypes.generic import GenericForeignKey
+
 from django.utils.translation import ugettext_lazy as _
 
 from guardian.compat import user_model_label
diff --git a/guardian/shortcuts.py b/guardian/shortcuts.py
index 3334640..5ef280c 100644
--- a/guardian/shortcuts.py
+++ b/guardian/shortcuts.py
@@ -285,7 +285,7 @@ def get_groups_with_perms(obj, attach_perms=False):
 
 
 def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=False,
-        with_superuser=True):
+        with_superuser=True, accept_global_perms=True):
     """
     Returns queryset of objects for which a given ``user`` has *all*
     permissions present at ``perms``.
@@ -302,9 +302,14 @@ def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=Fals
       this parameter would be computed based on given ``params``.
     :param use_groups: if ``False``, wouldn't check user's groups object
       permissions. Default is ``True``.
-    :param any_perm: if True, any of permission in sequence is accepted
+    :param any_perm: if True, any of permission in sequence is accepted. Default is ``False``.
     :param with_superuser: if ``True`` returns the entire queryset if not it will
-    only return objects the user has explicit permissions.
+    only return objects the user has explicit permissions. Default is ``True``.
+    :param accept_global_perms: if ``True`` takes global permissions into account.
+      Object based permissions are taken into account if more than one permission is handed in in perms and at least
+      one of these perms is not globally set. If any_perm is set to false then the intersection of matching object
+      is returned. Note, that if with_superuser is False, accept_global_perms will be ignored, which means that only
+      object permissions will be checked! Default is ``True``.
 
     :raises MixedContentTypeError: when computed content type for ``perms``
       and/or ``klass`` clashes.
@@ -324,6 +329,7 @@ def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=Fals
         >>> get_objects_for_user(joe, 'auth.change_group')
         [<Group some group>]
 
+
     The permission string can also be an iterable. Continuing with the previous example:
 
         >>> get_objects_for_user(joe, ['auth.change_group', 'auth.delete_group'])
@@ -334,6 +340,18 @@ def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=Fals
         >>> get_objects_for_user(joe, ['auth.change_group', 'auth.delete_group'])
         [<Group some group>]
 
+    Take global permissions into account:
+        >>> jack = User.objects.get(username='jack')
+        >>> assign_perm('auth.change_group', jack) # this will set a global permission
+        >>> get_objects_for_user(jack, 'auth.change_group')
+        [<Group some group>]
+        >>> group2 = Group.objects.create('other group')
+        >>> assign_perm('auth.delete_group', jack, group2)
+        >>> get_objects_for_user(jack, ['auth.change_group', 'auth.delete_group']) # this retrieves intersection
+        [<Group other group>]
+        >>> get_objects_for_user(jack, ['auth.change_group', 'auth.delete_group'], any_perm) # this retrieves union
+        [<Group some group>, <Group other group>]
+
     """
     if isinstance(perms, basestring):
         perms = [perms]
@@ -390,6 +408,33 @@ def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=Fals
     if user.is_anonymous():
         user = get_anonymous_user()
 
+    global_perms = set()
+    has_global_perms = False
+    # a superuser has by default assigned global perms for any
+    if accept_global_perms and with_superuser:
+        for code in codenames:
+            if user.has_perm(app_label + '.' + code):
+                global_perms.add(code)
+        for code in global_perms:
+            codenames.remove(code)
+        ## prerequisite: there must be elements in global_perms otherwise just follow the procedure for
+        # object based permissions only AND
+        # 1. codenames is empty, which means that permissions are ONLY set globally, therefore return the full queryset.
+        # OR
+        # 2. any_perm is True, then the global permission beats the object based permission anyway,
+        # therefore return full queryset
+        if len(global_perms) > 0 and (len(codenames) == 0 or any_perm):
+            return queryset
+        # if we have global perms and still some object based perms differing from global perms and any_perm is set
+        # to false, then we have to flag that global perms exist in order to merge object based permissions by user
+        # and by group correctly. Scenario: global perm change_xx and object based perm delete_xx on object A for user,
+        # and object based permission delete_xx  on object B for group, to which user is assigned.
+        # get_objects_for_user(user, [change_xx, delete_xx], use_groups=True, any_perm=False, accept_global_perms=True)
+        # must retrieve object A and B.
+        elif len(global_perms) > 0 and (len(codenames) > 0):
+            has_global_perms = True
+
+
     # Now we should extract list of pk values for which we would filter queryset
     user_model = get_user_obj_perms_model(queryset.model)
     user_obj_perms_queryset = (user_model.objects
@@ -413,7 +458,7 @@ def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=Fals
             fields = ['object_pk', 'permission__codename']
         else:
             fields = ['content_object__pk', 'permission__codename']
-        if not any_perm:
+        if not any_perm and not has_global_perms:
             user_obj_perms = user_obj_perms_queryset.values_list(*fields)
             groups_obj_perms = groups_obj_perms_queryset.values_list(*fields)
             data = list(user_obj_perms) + list(groups_obj_perms)
@@ -444,7 +489,7 @@ def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=Fals
     return objects
 
 
-def get_objects_for_group(group, perms, klass=None, any_perm=False):
+def get_objects_for_group(group, perms, klass=None, any_perm=False, accept_global_perms=True):
     """
     Returns queryset of objects for which a given ``group`` has *all*
     permissions present at ``perms``.
@@ -459,6 +504,9 @@ def get_objects_for_group(group, perms, klass=None, any_perm=False):
     :param klass: may be a Model, Manager or QuerySet object. If not given
       this parameter would be computed based on given ``params``.
     :param any_perm: if True, any of permission in sequence is accepted
+    :param accept_global_perms: if ``True`` takes global permissions into account.
+      If any_perm is set to false then the intersection of matching objects based on global and object based permissions
+      is returned. Default is ``True``.
 
     :raises MixedContentTypeError: when computed content type for ``perms``
       and/or ``klass`` clashes.
@@ -489,6 +537,14 @@ def get_objects_for_group(group, perms, klass=None, any_perm=False):
         >>> get_objects_for_group(group, ['tasker.add_task', 'tasker.delete_task'])
         [<Task some task>]
 
+    Global permissions assigned to the group are also taken into account. Continuing with previous example:
+        >>> task_other = Task.objects.create('other task')
+        >>> assign_perm('tasker.change_task', group)
+        >>> get_objects_for_group(group, ['tasker.change_task'])
+        [<Task some task>, <Task other task>]
+        >>> get_objects_for_group(group, ['tasker.change_task'], accept_global_perms=False)
+        [<Task some task>]
+
     """
     if isinstance(perms, basestring):
         perms = [perms]
@@ -535,6 +591,17 @@ def get_objects_for_group(group, perms, klass=None, any_perm=False):
     # match which means: ctype.model_class() == queryset.model
     # we should also have ``codenames`` list
 
+    global_perms = set()
+    if accept_global_perms:
+        global_perm_set = group.permissions.values_list('codename', flat=True)
+        for code in codenames:
+            if code in global_perm_set:
+                global_perms.add(code)
+        for code in global_perms:
+            codenames.remove(code)
+        if len(global_perms) > 0 and (len(codenames) == 0 or any_perm):
+            return queryset
+
     # Now we should extract list of pk values for which we would filter queryset
     group_model = get_group_obj_perms_model(queryset.model)
     groups_obj_perms_queryset = (group_model.objects
@@ -555,6 +622,5 @@ def get_objects_for_group(group, perms, klass=None, any_perm=False):
         obj_codenames = set((e[1] for e in group))
         if any_perm or codenames.issubset(obj_codenames):
             pk_list.append(pk)
-
     objects = queryset.filter(pk__in=pk_list)
     return objects
diff --git a/guardian/migrations/0001_initial.py b/guardian/south_migrations/0001_initial.py
similarity index 100%
copy from guardian/migrations/0001_initial.py
copy to guardian/south_migrations/0001_initial.py
diff --git a/guardian/migrations/0002_auto__add_field_groupobjectpermission_object_pk__add_field_userobjectp.py b/guardian/south_migrations/0002_auto__add_field_groupobjectpermission_object_pk__add_field_userobjectp.py
similarity index 100%
rename from guardian/migrations/0002_auto__add_field_groupobjectpermission_object_pk__add_field_userobjectp.py
rename to guardian/south_migrations/0002_auto__add_field_groupobjectpermission_object_pk__add_field_userobjectp.py
diff --git a/guardian/migrations/0003_update_objectpermission_object_pk.py b/guardian/south_migrations/0003_update_objectpermission_object_pk.py
similarity index 100%
rename from guardian/migrations/0003_update_objectpermission_object_pk.py
rename to guardian/south_migrations/0003_update_objectpermission_object_pk.py
diff --git a/guardian/migrations/0004_auto__del_field_groupobjectpermission_object_id__del_unique_groupobjec.py b/guardian/south_migrations/0004_auto__del_field_groupobjectpermission_object_id__del_unique_groupobjec.py
similarity index 100%
rename from guardian/migrations/0004_auto__del_field_groupobjectpermission_object_id__del_unique_groupobjec.py
rename to guardian/south_migrations/0004_auto__del_field_groupobjectpermission_object_id__del_unique_groupobjec.py
diff --git a/guardian/migrations/0005_auto__chg_field_groupobjectpermission_object_pk__chg_field_userobjectp.py b/guardian/south_migrations/0005_auto__chg_field_groupobjectpermission_object_pk__chg_field_userobjectp.py
similarity index 100%
rename from guardian/migrations/0005_auto__chg_field_groupobjectpermission_object_pk__chg_field_userobjectp.py
rename to guardian/south_migrations/0005_auto__chg_field_groupobjectpermission_object_pk__chg_field_userobjectp.py
diff --git a/guardian/south_migrations/__init__.py b/guardian/south_migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/guardian/templatetags/guardian_tags.py b/guardian/templatetags/guardian_tags.py
index 3590bbb..04c3595 100644
--- a/guardian/templatetags/guardian_tags.py
+++ b/guardian/templatetags/guardian_tags.py
@@ -8,8 +8,14 @@
 from __future__ import unicode_literals
 from django import template
 from django.contrib.auth.models import Group, AnonymousUser
-from django.template import get_library
-from django.template import InvalidTemplateLibrary
+try:
+    # Django < 1.8
+    from django.template import get_library
+    from django.template import InvalidTemplateLibrary
+except ImportError:
+    # Django >= 1.8
+    from django.template.base import get_library
+    from django.template.base import InvalidTemplateLibrary
 from django.template.defaulttags import LoadNode
 
 from guardian.compat import get_user_model
diff --git a/guardian/testapp/migrations/0001_initial.py b/guardian/testapp/migrations/0001_initial.py
index f329972..5f92d18 100644
--- a/guardian/testapp/migrations/0001_initial.py
+++ b/guardian/testapp/migrations/0001_initial.py
@@ -21,7 +21,7 @@ class Migration(migrations.Migration):
             name='CustomUser',
             fields=[
                 ('password', models.CharField(max_length=128, verbose_name='password')),
-                ('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login')),
+                ('last_login', models.DateTimeField(default=django.utils.timezone.now, verbose_name='last login', null=True)),
                 ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
                 ('username', models.CharField(help_text='Required. 30 characters or fewer. Letters, digits and @/./+/-/_ only.', unique=True, max_length=30, verbose_name='username', validators=[django.core.validators.RegexValidator('^[\\w. at -]+$', 'Enter a valid username.', 'invalid')])),
                 ('first_name', models.CharField(max_length=30, verbose_name='first name', blank=True)),
diff --git a/guardian/testapp/tests/admin_test.py b/guardian/testapp/tests/admin_test.py
index 775421b..33625cf 100644
--- a/guardian/testapp/tests/admin_test.py
+++ b/guardian/testapp/tests/admin_test.py
@@ -11,7 +11,7 @@ from django.test import TestCase
 from django.test.client import Client
 
 from guardian.admin import GuardedModelAdmin
-from guardian.compat import get_user_model
+from guardian.compat import get_user_model, get_model_name
 from guardian.compat import str
 from guardian.shortcuts import get_perms
 from guardian.shortcuts import get_perms_for_model
@@ -43,7 +43,7 @@ class AdminTests(TestCase):
         self.client = Client()
         self.obj = ContentType.objects.create(name='foo', model='bar',
             app_label='fake-for-guardian-tests')
-        self.obj_info = self.obj._meta.app_label, self.obj._meta.module_name
+        self.obj_info = self.obj._meta.app_label, get_model_name(self.obj)
 
     def tearDown(self):
         self.client.logout()
diff --git a/guardian/testapp/tests/direct_rel_test.py b/guardian/testapp/tests/direct_rel_test.py
index f839ec6..393c48b 100644
--- a/guardian/testapp/tests/direct_rel_test.py
+++ b/guardian/testapp/tests/direct_rel_test.py
@@ -101,6 +101,22 @@ class TestDirectUserPermissions(TestCase):
         result = get_objects_for_user(self.joe, 'testapp.add_project')
         self.assertEqual(sorted(p.pk for p in result), sorted([foo.pk, bar.pk]))
 
+    def test_get_all_permissions(self):
+        foo = Project.objects.create(name='foo')
+        assign_perm('add_project', self.joe, foo)
+        assign_perm('change_project', self.joe, foo)
+
+        result = self.joe.get_all_permissions(foo)
+        self.assertEqual(result, set(('add_project', 'change_project')))
+
+    def test_get_all_permissions_no_object(self):
+        foo = Project.objects.create(name='foo')
+        assign_perm('add_project', self.joe, foo)
+        assign_perm('change_project', self.joe, foo)
+
+        result = self.joe.get_all_permissions()
+        self.assertEqual(result, set())
+
 
 @skipUnlessTestApp
 class TestDirectGroupPermissions(TestCase):
diff --git a/guardian/testapp/tests/orphans_test.py b/guardian/testapp/tests/orphans_test.py
index 6cab41f..a49a922 100644
--- a/guardian/testapp/tests/orphans_test.py
+++ b/guardian/testapp/tests/orphans_test.py
@@ -10,7 +10,7 @@ from django.contrib.contenttypes.models import ContentType
 from django.core.management import call_command
 from django.test import TestCase
 
-from guardian.compat import get_user_model, create_permissions
+from guardian.compat import get_user_model, create_permissions, get_model_name
 from guardian.utils import clean_orphan_obj_perms
 from guardian.shortcuts import assign_perm
 from guardian.models import Group
@@ -18,7 +18,7 @@ from guardian.testapp.tests.conf import skipUnlessTestApp
 
 
 User = get_user_model()
-user_module_name = User._meta.module_name
+user_module_name = get_model_name(User)
 
 @skipUnlessTestApp
 class OrphanedObjectPermissionsTest(TestCase):
@@ -99,4 +99,3 @@ class OrphanedObjectPermissionsTest(TestCase):
             target.save()
             for perm in perms:
                 self.assertFalse(self.user.has_perm(perm, target))
-
diff --git a/guardian/testapp/tests/shortcuts_test.py b/guardian/testapp/tests/shortcuts_test.py
index 56512d0..8f5d650 100644
--- a/guardian/testapp/tests/shortcuts_test.py
+++ b/guardian/testapp/tests/shortcuts_test.py
@@ -8,7 +8,7 @@ from django.test import TestCase
 from guardian.shortcuts import get_perms_for_model
 from guardian.core import ObjectPermissionChecker
 from guardian.compat import get_user_model
-from guardian.compat import get_user_permission_full_codename
+from guardian.compat import get_user_permission_full_codename, get_model_name
 from guardian.shortcuts import assign
 from guardian.shortcuts import assign_perm
 from guardian.shortcuts import remove_perm
@@ -29,7 +29,7 @@ import warnings
 
 User = get_user_model()
 user_app_label = User._meta.app_label
-user_module_name = User._meta.module_name
+user_module_name = get_model_name(User)
 
 class ShortcutsTests(ObjectPermissionTestCase):
 
@@ -476,11 +476,13 @@ class GetObjectsForUser(TestCase):
             ['change_group'])
 
     def test_empty_perms_sequence(self):
+        objects = get_objects_for_user(self.user, [], Group.objects.all())
         self.assertEqual(
-            set(get_objects_for_user(self.user, [], Group.objects.all())),
+            set(objects),
             set()
         )
 
+
     def test_perms_single(self):
         perm = 'auth.change_group'
         assign_perm(perm, self.user, self.group)
@@ -578,7 +580,7 @@ class GetObjectsForUser(TestCase):
 
         # Objects to operate on
         ctypes = list(ContentType.objects.all().order_by('id'))
-
+        assign_perm('auth.change_group', self.user)
         assign_perm('change_contenttype', self.user, ctypes[0])
         assign_perm('change_contenttype', self.user, ctypes[1])
         assign_perm('delete_contenttype', self.user, ctypes[1])
@@ -608,6 +610,113 @@ class GetObjectsForUser(TestCase):
             set(objects.values_list('id', flat=True)),
             set(ctypes[i].id for i in [0, 1, 3, 4]))
 
+    def test_has_global_permission_only(self):
+        group_names = ['group1', 'group2', 'group3']
+        groups = [Group.objects.create(name=name) for name in group_names]
+        #global permission to change any group
+        perm = 'auth.change_group'
+
+        assign_perm(perm, self.user)
+        objects = get_objects_for_user(self.user, perm)
+        remove_perm(perm, self.user)
+        self.assertEqual(set(objects),
+                         set(Group.objects.all()))
+
+    def test_has_global_permission_and_object_based_permission(self):
+        group_names = ['group1', 'group2', 'group3']
+        groups = [Group.objects.create(name=name) for name in group_names]
+        #global permission to change any group
+        perm_global = 'auth.change_group'
+        perm_obj = 'delete_group'
+        assign_perm(perm_global, self.user)
... 245 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-guardian.git



More information about the Python-modules-commits mailing list