Hello community, here is the log from the commit of package python-django-guardian for openSUSE:Factory checked in at 2020-06-10 00:51:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-django-guardian (Old) and /work/SRC/openSUSE:Factory/.python-django-guardian.new.3606 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-django-guardian" Wed Jun 10 00:51:32 2020 rev:17 rq:812905 version:2.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-django-guardian/python-django-guardian.changes 2020-02-20 14:59:09.414732673 +0100 +++ /work/SRC/openSUSE:Factory/.python-django-guardian.new.3606/python-django-guardian.changes 2020-06-10 00:51:40.463456414 +0200 @@ -1,0 +2,13 @@ +Tue Jun 9 11:44:07 UTC 2020 - Ondřej Súkup <mimi...@gmail.com> + +- Update to 2.3.0 + * Drop support for Django 2.1 + * Fix compatibility with UUIDField primary keys + * Fix formatting for pyupgrade + * Fix error with get_objects_for_user on PostgreSQL + * Modify 'assign_perm' shortcut to treat lists as a queryset + * Updated links to Django documentation and django-authority repository + * Removed reference to "easy_install" in the documentation + * Run migrations check only if required version of django is installed + +------------------------------------------------------------------- Old: ---- django-guardian-2.2.0.tar.gz New: ---- django-guardian-2.3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-django-guardian.spec ++++++ --- /var/tmp/diff_new_pack.9FG6MP/_old 2020-06-10 00:51:41.771459836 +0200 +++ /var/tmp/diff_new_pack.9FG6MP/_new 2020-06-10 00:51:41.771459836 +0200 @@ -19,7 +19,7 @@ %define pypi_package_name django-guardian %define skip_python2 1 Name: python-%{pypi_package_name} -Version: 2.2.0 +Version: 2.3.0 Release: 0 Summary: Implementation of per object permissions for Django License: BSD-3-Clause ++++++ django-guardian-2.2.0.tar.gz -> django-guardian-2.3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/.travis.yml new/django-guardian-2.3.0/.travis.yml --- old/django-guardian-2.2.0/.travis.yml 2020-02-03 19:18:19.000000000 +0100 +++ new/django-guardian-2.3.0/.travis.yml 2020-06-08 01:49:56.000000000 +0200 @@ -13,7 +13,6 @@ irc: "irc.freenode.net#django-guardian" templates: - django21: &django21 DJANGO_VERSION=2.1.* django22: &django22 DJANGO_VERSION=2.2.* django30: &django30 DJANGO_VERSION=3.0.* djangomaster: &djangomaster DJANGO_VERSION=master @@ -31,16 +30,10 @@ matrix: fast_finish: true include: - - { python: 3.5, env: [*django21, *postgres], <<: *pgdb} - - { python: 3.5, env: [*django21, *mysql], <<: *mariadb} - - { python: 3.5, env: [*django21, *sqlite]} - { python: 3.5, env: [*django22, *postgres], <<: *pgdb} - { python: 3.5, env: [*django22, *mysql], <<: *mariadb} - { python: 3.5, env: [*django22, *sqlite]} - - { python: 3.6, env: [*django21, *postgres], <<: *pgdb} - - { python: 3.6, env: [*django21, *mysql], <<: *mariadb} - - { python: 3.6, env: [*django21, *sqlite]} - { python: 3.6, env: [*django22, *postgres], <<: *pgdb} - { python: 3.6, env: [*django22, *mysql], <<: *mariadb} - { python: 3.6, env: [*django22, *sqlite]} @@ -51,9 +44,6 @@ - { python: 3.6, env: [*djangomaster, *mysql], <<: *mariadb} - { python: 3.6, env: [*djangomaster, *sqlite]} - - { python: 3.7, env: [*django21, *postgres], <<: *pgdb} - - { python: 3.7, env: [*django21, *mysql], <<: *mariadb} - - { python: 3.7, env: [*django21, *sqlite]} - { python: 3.7, env: [*django22, *postgres], <<: *pgdb} - { python: 3.7, env: [*django22, *mysql], <<: *mariadb} - { python: 3.7, env: [*django22, *sqlite]} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/AUTHORS new/django-guardian-2.3.0/AUTHORS --- old/django-guardian-2.2.0/AUTHORS 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/AUTHORS 2020-06-08 01:49:56.000000000 +0200 @@ -59,3 +59,5 @@ - Jeff Hackshaw <intrepide...@gmail.com> - Chase Bennett <c...@se.gd> - Jonny Arnold <jonny.arnol...@gmail.com> +- Davis Raymond Muro <davisraymondm...@gmail.com> +- Richard de Wit <henk....@gmail.com> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/CHANGES new/django-guardian-2.3.0/CHANGES --- old/django-guardian-2.2.0/CHANGES 2020-02-03 19:20:40.000000000 +0100 +++ new/django-guardian-2.3.0/CHANGES 2020-06-08 01:50:13.000000000 +0200 @@ -1,3 +1,15 @@ +Release 2.3.0 (June 6, 2020) +=============================== + +* Drop support for Django 2.1 +* Fix compatibility with UUIDField primary keys +* Fix formatting for pyupgrade +* Fix error with get_objects_for_user on PostgreSQL +* Modify 'assign_perm' shortcut to treat lists as a queryset +* Updated links to Django documentation and django-authority repository +* Removed reference to "easy_install" in the documentation +* Run migrations check only if required version of django is installed + Release 2.2.0 (January 3, 2020) =============================== diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/PKG-INFO new/django-guardian-2.3.0/PKG-INFO --- old/django-guardian-2.2.0/PKG-INFO 2020-02-03 19:22:39.000000000 +0100 +++ new/django-guardian-2.3.0/PKG-INFO 2020-06-08 01:52:28.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: django-guardian -Version: 2.2.0 +Version: 2.3.0 Summary: Implementation of per object permissions for Django. Home-page: http://github.com/django-guardian/django-guardian Author: Lukasz Balcerzak @@ -32,9 +32,9 @@ ------------ * Python 3.5+ - * A supported version of Django (currently 2.1+) + * A supported version of Django (currently 2.2+) - Travis CI tests on Django version 2.1, 2.2, 3.0, and master. + Travis CI tests on Django version 2.2, 3.0, and master. Installation ------------ @@ -131,7 +131,6 @@ Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django -Classifier: Framework :: Django :: 2.1 Classifier: Framework :: Django :: 2.2 Classifier: Framework :: Django :: 3.0 Classifier: Intended Audience :: Developers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/README.rst new/django-guardian-2.3.0/README.rst --- old/django-guardian-2.2.0/README.rst 2020-02-03 19:18:19.000000000 +0100 +++ new/django-guardian-2.3.0/README.rst 2020-06-08 01:49:56.000000000 +0200 @@ -23,9 +23,9 @@ ------------ * Python 3.5+ -* A supported version of Django (currently 2.1+) +* A supported version of Django (currently 2.2+) -Travis CI tests on Django version 2.1, 2.2, 3.0, and master. +Travis CI tests on Django version 2.2, 3.0, and master. Installation ------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/django_guardian.egg-info/PKG-INFO new/django-guardian-2.3.0/django_guardian.egg-info/PKG-INFO --- old/django-guardian-2.2.0/django_guardian.egg-info/PKG-INFO 2020-02-03 19:22:39.000000000 +0100 +++ new/django-guardian-2.3.0/django_guardian.egg-info/PKG-INFO 2020-06-08 01:52:27.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.2 Name: django-guardian -Version: 2.2.0 +Version: 2.3.0 Summary: Implementation of per object permissions for Django. Home-page: http://github.com/django-guardian/django-guardian Author: Lukasz Balcerzak @@ -32,9 +32,9 @@ ------------ * Python 3.5+ - * A supported version of Django (currently 2.1+) + * A supported version of Django (currently 2.2+) - Travis CI tests on Django version 2.1, 2.2, 3.0, and master. + Travis CI tests on Django version 2.2, 3.0, and master. Installation ------------ @@ -131,7 +131,6 @@ Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django -Classifier: Framework :: Django :: 2.1 Classifier: Framework :: Django :: 2.2 Classifier: Framework :: Django :: 3.0 Classifier: Intended Audience :: Developers diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/django_guardian.egg-info/SOURCES.txt new/django-guardian-2.3.0/django_guardian.egg-info/SOURCES.txt --- old/django-guardian-2.2.0/django_guardian.egg-info/SOURCES.txt 2020-02-03 19:22:39.000000000 +0100 +++ new/django-guardian-2.3.0/django_guardian.egg-info/SOURCES.txt 2020-06-08 01:52:28.000000000 +0200 @@ -167,6 +167,8 @@ guardian/testapp/migrations/0001_initial.py guardian/testapp/migrations/0002_logentrywithgroup.py guardian/testapp/migrations/0003_auto_20190611_0440.py +guardian/testapp/migrations/0004_childtestmodel_parenttestmodel.py +guardian/testapp/migrations/0005_uuidpkmodel.py guardian/testapp/migrations/__init__.py guardian/testapp/tests/__init__.py guardian/testapp/tests/conf.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/django_guardian.egg-info/requires.txt new/django-guardian-2.3.0/django_guardian.egg-info/requires.txt --- old/django-guardian-2.2.0/django_guardian.egg-info/requires.txt 2020-02-03 19:22:39.000000000 +0100 +++ new/django-guardian-2.3.0/django_guardian.egg-info/requires.txt 2020-06-08 01:52:27.000000000 +0200 @@ -1 +1 @@ -Django>=2.1 +Django>=2.2 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/docs/configuration.rst new/django-guardian-2.3.0/docs/configuration.rst --- old/django-guardian-2.2.0/docs/configuration.rst 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/docs/configuration.rst 2020-06-08 01:49:56.000000000 +0200 @@ -114,7 +114,7 @@ Defaults to ``"AnonymousUser"``. -.. seealso:: https://docs.djangoproject.com/en/2.1/topics/auth/customizing/#substituting-a-custom-user-model +.. seealso:: https://docs.djangoproject.com/en/stable/topics/auth/customizing/#substituting-a-custom-user-model .. setting:: GUARDIAN_GET_INIT_ANONYMOUS_USER diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/docs/develop/supported-versions.rst new/django-guardian-2.3.0/docs/develop/supported-versions.rst --- old/django-guardian-2.2.0/docs/develop/supported-versions.rst 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/docs/develop/supported-versions.rst 2020-06-08 01:49:56.000000000 +0200 @@ -3,11 +3,11 @@ Supported versions ================== -``django-guardian`` supports Python 3.5+ and Django 2.1+. +``django-guardian`` supports Python 3.5+ and Django 2.2+. Rules ----- * We support Python 3.5+. -* We support Django 2.1+. This is due to many simplifications in code we could +* We support Django 2.2+. This is due to many simplifications in code we could do. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/docs/installation.rst new/django-guardian-2.3.0/docs/installation.rst --- old/django-guardian-2.2.0/docs/installation.rst 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/docs/installation.rst 2020-06-08 01:49:56.000000000 +0200 @@ -3,17 +3,13 @@ Installation ============ -This application requires Django_ 2.1 or higher and it is the only prerequisite +This application requires Django_ 2.2 or higher and it is the only prerequisite before ``django-guardian`` may be used. In order to install ``django-guardian`` simply use ``pip``:: pip install django-guardian -or ``easy_install``:: - - easy_install django-guardian - This would be enough to run ``django-guardian``. However, in order to run tests or example application, there are some other requirements. See more details about the topics: @@ -22,4 +18,3 @@ - :ref:`Example project <example-project>` .. _django: http://www.djangoproject.com/ - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/docs/overview.rst new/django-guardian-2.3.0/docs/overview.rst --- old/django-guardian-2.2.0/docs/overview.rst 2019-06-11 11:38:51.000000000 +0200 +++ new/django-guardian-2.3.0/docs/overview.rst 2020-06-08 01:49:56.000000000 +0200 @@ -41,6 +41,6 @@ .. _issue-tracker: http://github.com/lukaszb/django-guardian .. _grappelli: https://github.com/sehmaschine/django-grappelli -.. [1] See http://docs.djangoproject.com/en/1.2/topics/auth/#handling-object-permissions +.. [1] See https://docs.djangoproject.com/en/stable/topics/auth/customizing/#handling-object-permissions for more detail. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/docs/userguide/assign.rst new/django-guardian-2.3.0/docs/userguide/assign.rst --- old/django-guardian-2.2.0/docs/userguide/assign.rst 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/docs/userguide/assign.rst 2020-06-08 01:49:56.000000000 +0200 @@ -45,19 +45,14 @@ - *add_modelname* - *change_modelname* - *delete_modelname* - - *view_modelname* (since Django 2.1) + - *view_modelname* (where *modelname* is a simplified name of our model's class). See https://docs.djangoproject.com/en/stable/topics/auth/default/#default-permissions for more detail. -.. note:: - When upgrading to Django 2.1 custom created *view_modelname* permissions - clash with the newly built-in ones. The simplest way to fix this is to - add ``default_permissions = ('add', 'change', 'delete')`` to ``Meta``. - -There is nothing new here since creation of permissions is -`handled by django <http://docs.djangoproject.com/en/2.2/topics/auth/#id1>`_. +There is nothing new here since creation of permissions is +`handled by django <https://docs.djangoproject.com/en/stable/topics/auth/>`_. Now we can move to :ref:`assigning object permissions <assign-obj-perms>`. .. _assign-obj-perms: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/docs/userguide/check.rst new/django-guardian-2.3.0/docs/userguide/check.rst --- old/django-guardian-2.2.0/docs/userguide/check.rst 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/docs/userguide/check.rst 2020-06-08 01:49:56.000000000 +0200 @@ -185,5 +185,5 @@ .. autofunction:: guardian.templatetags.guardian_tags.get_obj_perms :noindex: -.. _django-authority: http://bitbucket.org/jezdez/django-authority/ +.. _django-authority: https://github.com/jazzband/django-authority diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/__init__.py new/django-guardian-2.3.0/guardian/__init__.py --- old/django-guardian-2.2.0/guardian/__init__.py 2020-02-03 19:21:46.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/__init__.py 2020-06-08 01:50:55.000000000 +0200 @@ -6,7 +6,7 @@ default_app_config = 'guardian.apps.GuardianConfig' # PEP 396: The __version__ attribute's value SHOULD be a string. -__version__ = '2.2.0' +__version__ = '2.3.0' # Compatibility to eg. django-rest-framework VERSION = tuple(int(x) for x in __version__.split('.')[:3]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/managers.py new/django-guardian-2.3.0/guardian/managers.py --- old/django-guardian-2.2.0/guardian/managers.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/managers.py 2020-06-08 01:49:56.000000000 +0200 @@ -54,8 +54,11 @@ Bulk assigns permissions with given ``perm`` for an objects in ``queryset`` and ``user_or_group``. """ + if isinstance(queryset, list): + ctype = get_content_type(queryset[0]) + else: + ctype = get_content_type(queryset.model) - ctype = get_content_type(queryset.model) if not isinstance(perm, Permission): permission = Permission.objects.get(content_type=ctype, codename=perm) else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/shortcuts.py new/django-guardian-2.3.0/guardian/shortcuts.py --- old/django-guardian-2.2.0/guardian/shortcuts.py 2020-02-03 19:18:19.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/shortcuts.py 2020-06-08 01:49:56.000000000 +0200 @@ -3,22 +3,28 @@ """ import warnings from collections import defaultdict +from functools import partial from itertools import groupby from django.apps import apps from django.contrib.auth import get_user_model from django.contrib.auth.models import Group, Permission from django.contrib.contenttypes.models import ContentType +from django.db import connection from django.db.models import Count, Q, QuerySet from django.shortcuts import _get_queryset -from django.db.models.functions import Cast +from django.db.models.expressions import Value +from django.db.models.functions import Cast, Replace from django.db.models import ( - IntegerField, AutoField, BigIntegerField, + CharField, + ForeignKey, + IntegerField, PositiveIntegerField, PositiveSmallIntegerField, SmallIntegerField, + UUIDField, ) from guardian.core import ObjectPermissionChecker from guardian.ctypes import get_content_type @@ -43,8 +49,8 @@ ``guardian.exceptions.NotUserNorGroup`` exception :param obj: persisted Django's ``Model`` instance or QuerySet of Django - ``Model`` instances or ``None`` if assigning global permission. - Default is ``None``. + ``Model`` instances or list of Django ``Model`` instances or ``None`` + if assigning global permission. Default is ``None``. We can assign permission for ``Model`` instance for specific user: @@ -100,14 +106,16 @@ if '.' in perm: app_label, perm = perm.split(".", 1) - if isinstance(obj, QuerySet): + if isinstance(obj, (QuerySet, list)): if isinstance(user_or_group, (QuerySet, list)): raise MultipleIdentityAndObjectError("Only bulk operations on either users/groups OR objects supported") if user: - model = get_user_obj_perms_model(obj.model) + model = get_user_obj_perms_model( + obj[0] if isinstance(obj, list) else obj.model) return model.objects.bulk_assign_perm(perm, user, obj) if group: - model = get_group_obj_perms_model(obj.model) + model = get_group_obj_perms_model( + obj[0] if isinstance(obj, list) else obj.model) return model.objects.bulk_assign_perm(perm, group, obj) if isinstance(user_or_group, (QuerySet, list)): @@ -617,14 +625,12 @@ user_obj_perms_queryset = counts.filter( object_pk_count__gte=len(codenames)) - is_cast_integer = _is_cast_integer_pk(queryset) - field_pk = user_fields[0] values = user_obj_perms_queryset - if is_cast_integer: - values = values.annotate( - obj_pk=Cast(field_pk, BigIntegerField()) - ) + + handle_pk_field = _handle_pk_field(queryset) + if handle_pk_field is not None: + values = values.annotate(obj_pk=handle_pk_field(expression=field_pk)) field_pk = 'obj_pk' values = values.values_list(field_pk, flat=True) @@ -632,10 +638,8 @@ if use_groups: field_pk = group_fields[0] values = groups_obj_perms_queryset - if is_cast_integer: - values = values.annotate( - obj_pk=Cast(field_pk, BigIntegerField()) - ) + if handle_pk_field is not None: + values = values.annotate(obj_pk=handle_pk_field(expression=field_pk)) field_pk = 'obj_pk' values = values.values_list(field_pk, flat=True) q |= Q(pk__in=values) @@ -783,23 +787,45 @@ objects = queryset.filter(pk__in=pk_list) return objects - is_cast_integer = _is_cast_integer_pk(queryset) - field_pk = fields[0] values = groups_obj_perms_queryset - if is_cast_integer: - values = values.annotate( - obj_pk=Cast(field_pk, BigIntegerField()) - ) + handle_pk_field = _handle_pk_field(queryset) + if handle_pk_field is not None: + values = values.annotate(obj_pk=handle_pk_field(expression=field_pk)) field_pk = 'obj_pk' values = values.values_list(field_pk, flat=True) return queryset.filter(pk__in=values) -def _is_cast_integer_pk(queryset): - return isinstance(queryset.model._meta.pk, ( - IntegerField, AutoField, BigIntegerField, - PositiveIntegerField, PositiveSmallIntegerField, - SmallIntegerField)) +def _handle_pk_field(queryset): + pk = queryset.model._meta.pk + + if isinstance(pk, ForeignKey): + return _handle_pk_field(pk.target_field) + + if isinstance( + pk, + ( + IntegerField, + AutoField, + BigIntegerField, + PositiveIntegerField, + PositiveSmallIntegerField, + SmallIntegerField, + ), + ): + return partial(Cast, output_field=BigIntegerField()) + + if isinstance(pk, UUIDField): + if connection.features.has_native_uuid_field: + return partial(Cast, output_field=UUIDField()) + return partial( + Replace, + text=Value('-'), + replacement=Value(''), + output_field=CharField(), + ) + + return None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/migrations/0001_initial.py new/django-guardian-2.3.0/guardian/testapp/migrations/0001_initial.py --- old/django-guardian-2.2.0/guardian/testapp/migrations/0001_initial.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/migrations/0001_initial.py 2020-06-08 01:49:56.000000000 +0200 @@ -78,7 +78,7 @@ }, ), migrations.CreateModel( - name='NonIntPKModel', + name='CharPKModel', fields=[ ('char_pk', models.CharField(max_length=128, primary_key=True, serialize=False)), ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/migrations/0004_childtestmodel_parenttestmodel.py new/django-guardian-2.3.0/guardian/testapp/migrations/0004_childtestmodel_parenttestmodel.py --- old/django-guardian-2.2.0/guardian/testapp/migrations/0004_childtestmodel_parenttestmodel.py 1970-01-01 01:00:00.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/migrations/0004_childtestmodel_parenttestmodel.py 2020-06-08 01:49:56.000000000 +0200 @@ -0,0 +1,29 @@ +# Generated by Django 2.2.10 on 2020-02-05 07:47 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('testapp', '0003_auto_20190611_0440'), + ] + + operations = [ + migrations.CreateModel( + name='ParentTestModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_on', models.DateTimeField(auto_now_add=True)), + ], + ), + migrations.CreateModel( + name='ChildTestModel', + fields=[ + ('parent_id', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='testapp.ParentTestModel')), + ('name', models.CharField(max_length=31)), + ], + bases=('testapp.parenttestmodel',), + ), + ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/migrations/0005_uuidpkmodel.py new/django-guardian-2.3.0/guardian/testapp/migrations/0005_uuidpkmodel.py --- old/django-guardian-2.2.0/guardian/testapp/migrations/0005_uuidpkmodel.py 1970-01-01 01:00:00.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/migrations/0005_uuidpkmodel.py 2020-06-08 01:49:56.000000000 +0200 @@ -0,0 +1,20 @@ +# Generated by Django 3.0.3 on 2020-02-05 04:41 + +from django.db import migrations, models +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ('testapp', '0004_childtestmodel_parenttestmodel'), + ] + + operations = [ + migrations.CreateModel( + name='UUIDPKModel', + fields=[ + ('uuid_pk', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ], + ), + ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/models.py new/django-guardian-2.3.0/guardian/testapp/models.py --- old/django-guardian-2.2.0/guardian/testapp/models.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/models.py 2020-06-08 01:49:56.000000000 +0200 @@ -1,3 +1,4 @@ +import uuid from datetime import datetime from django.db import models @@ -83,14 +84,26 @@ objects = models.Manager() -class NonIntPKModel(models.Model): +class CharPKModel(models.Model): """ Model for testing whether get_objects_for_user will work when the objects to - be returned have non-integer primary keys. + be returned have varchar primary keys. """ char_pk = models.CharField(primary_key=True, max_length=128) +class UUIDPKModel(models.Model): + """ + Model for testing whether get_objects_for_user will work when the objects to + be returned have UUID primary keys. + """ + uuid_pk = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + editable=False, + ) + + class CustomUser(AbstractUser, GuardianUserMixin): custom_id = models.AutoField(primary_key=True) @@ -104,3 +117,16 @@ def get_short_name(self): return self.email + + +class ParentTestModel(models.Model): + created_on = models.DateTimeField(auto_now_add=True) + + +class ChildTestModel(ParentTestModel): + parent_id = models.OneToOneField( + ParentTestModel, + on_delete=models.CASCADE, + parent_link=True + ) + name = models.CharField(max_length=31) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_conf.py new/django-guardian-2.3.0/guardian/testapp/tests/test_conf.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_conf.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_conf.py 2020-06-08 01:49:56.000000000 +0200 @@ -1,6 +1,6 @@ from django.core.exceptions import ImproperlyConfigured from django.test import TestCase -import mock +from unittest import mock from guardian.conf import settings as guardian_settings from guardian.ctypes import get_content_type diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_core.py new/django-guardian-2.3.0/guardian/testapp/tests/test_core.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_core.py 2020-02-03 19:18:19.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_core.py 2020-06-08 01:49:56.000000000 +0200 @@ -41,6 +41,7 @@ model='bar', app_label='fake-for-guardian-tests') self.ctype_qset = ContentType.objects.filter(model='bar', app_label='fake-for-guardian-tests') + self.ctype_list = [self.ctype_qset.first()] self.anonymous_user = User.objects.get( username=guardian_settings.ANONYMOUS_USER_NAME) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_decorators.py new/django-guardian-2.3.0/guardian/testapp/tests/test_decorators.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_decorators.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_decorators.py 2020-06-08 01:49:56.000000000 +0200 @@ -14,7 +14,7 @@ from guardian.compat import get_user_model_path from guardian.compat import get_user_permission_full_codename -import mock +from unittest import mock from guardian.decorators import permission_required, permission_required_or_403, permission_required_or_404 from guardian.exceptions import GuardianError from guardian.exceptions import WrongAppError diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_management.py new/django-guardian-2.3.0/guardian/testapp/tests/test_management.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_management.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_management.py 2020-06-08 01:49:56.000000000 +0200 @@ -5,7 +5,7 @@ from django.contrib.sessions.models import Session from django.test import TestCase, override_settings -import mock +from unittest import mock from guardian.management import create_anonymous_user from guardian.utils import get_anonymous_user diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_managers.py new/django-guardian-2.3.0/guardian/testapp/tests/test_managers.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_managers.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_managers.py 2020-06-08 01:49:56.000000000 +0200 @@ -1,6 +1,6 @@ import warnings -import mock +from unittest import mock from django.test import TestCase from guardian.managers import UserObjectPermissionManager from guardian.managers import GroupObjectPermissionManager diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_mixins.py new/django-guardian-2.3.0/guardian/testapp/tests/test_mixins.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_mixins.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_mixins.py 2020-06-08 01:49:56.000000000 +0200 @@ -9,7 +9,7 @@ from django.views.generic import ListView from guardian.shortcuts import assign_perm -import mock +from unittest import mock from guardian.mixins import LoginRequiredMixin from guardian.mixins import PermissionRequiredMixin from guardian.mixins import PermissionListMixin diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_other.py new/django-guardian-2.3.0/guardian/testapp/tests/test_other.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_other.py 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_other.py 2020-06-08 01:49:56.000000000 +0200 @@ -1,4 +1,4 @@ -import mock +from unittest import mock import unittest from django.contrib.auth import get_user_model diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/guardian/testapp/tests/test_shortcuts.py new/django-guardian-2.3.0/guardian/testapp/tests/test_shortcuts.py --- old/django-guardian-2.2.0/guardian/testapp/tests/test_shortcuts.py 2020-02-03 19:18:19.000000000 +0100 +++ new/django-guardian-2.3.0/guardian/testapp/tests/test_shortcuts.py 2020-06-08 01:49:56.000000000 +0200 @@ -24,7 +24,7 @@ from guardian.exceptions import NotUserNorGroup from guardian.exceptions import WrongAppError from guardian.exceptions import MultipleIdentityAndObjectError -from guardian.testapp.models import NonIntPKModel +from guardian.testapp.models import CharPKModel, ChildTestModel, UUIDPKModel from guardian.testapp.tests.test_core import ObjectPermissionTestCase from guardian.models import Group, Permission @@ -134,6 +134,34 @@ self.assertEqual(len(warns), 1) self.assertTrue(isinstance(warns[0].message, DeprecationWarning)) + def test_user_assign_perm_list(self): + """ + Test that one is able to assign permissions for a list of objects + to a user + """ + assign_perm("add_contenttype", self.user, self.ctype_list) + assign_perm("change_contenttype", self.group, self.ctype_list) + assign_perm(self.get_permission("delete_contenttype"), self.user, self.ctype_list) + for obj in self.ctype_list: + self.assertTrue(self.user.has_perm("add_contenttype", obj)) + self.assertTrue(self.user.has_perm("change_contenttype", obj)) + self.assertTrue(self.user.has_perm("delete_contenttype", obj)) + + def test_group_assign_perm_list(self): + """ + Test that one is able to assign permissions for a list of + objects to a group + """ + assign_perm("add_contenttype", self.group, self.ctype_list) + assign_perm("change_contenttype", self.group, self.ctype_list) + assign_perm(self.get_permission("delete_contenttype"), self.group, self.ctype_list) + + check = ObjectPermissionChecker(self.group) + for obj in self.ctype_list: + self.assertTrue(check.has_perm("add_contenttype", obj)) + self.assertTrue(check.has_perm("change_contenttype", obj)) + self.assertTrue(check.has_perm("delete_contenttype", obj)) + class MultipleIdentitiesOperationsTest(ObjectPermissionTestCase): """ @@ -972,34 +1000,49 @@ set(objects.values_list('id', flat=True)), {ctypes[0].id, ctypes[1].id}) - def test_non_integer_primary_key(self): + def test_varchar_primary_key(self): """ Verify that the function works when the objects that should be returned - have non-integer primary keys. + have varchar primary keys. """ - obj_with_char_pk = NonIntPKModel.objects.create( + obj_with_char_pk = CharPKModel.objects.create( char_pk='testprimarykey') - assign_perm('add_nonintpkmodel', self.user, obj_with_char_pk) + assign_perm('add_charpkmodel', self.user, obj_with_char_pk) - objects = get_objects_for_user(self.user, 'testapp.add_nonintpkmodel') + objects = get_objects_for_user(self.user, 'testapp.add_charpkmodel') self.assertEqual(len(objects), 1) self.assertTrue(isinstance(objects, QuerySet)) self.assertEqual( set(objects.values_list('pk', flat=True)), {obj_with_char_pk.pk}) - def test_non_integer_primary_key_with_any_perm(self): + def test_uuid_primary_key(self): + """ + Verify that the function works when the objects that should be returned + have uuid primary keys. + """ + obj_with_uuid_pk = UUIDPKModel.objects.create() + assign_perm('add_uuidpkmodel', self.user, obj_with_uuid_pk) + + objects = get_objects_for_user(self.user, 'testapp.add_uuidpkmodel') + self.assertEqual(len(objects), 1) + self.assertTrue(isinstance(objects, QuerySet)) + self.assertEqual( + set(objects.values_list('pk', flat=True)), + {obj_with_uuid_pk.pk}) + + def test_varchar_primary_key_with_any_perm(self): """ Verify that the function works with any_perm set to True when the - objects that should be returned have non-integer primary keys. + objects that should be returned have varchar primary keys. """ - obj_with_char_pk = NonIntPKModel.objects.create( + obj_with_char_pk = CharPKModel.objects.create( char_pk='testprimarykey') - assign_perm('add_nonintpkmodel', self.user, obj_with_char_pk) + assign_perm('add_charpkmodel', self.user, obj_with_char_pk) objects = get_objects_for_user( self.user, - ['testapp.add_nonintpkmodel', 'testapp.change_nonintpkmodel'], + ['testapp.add_charpkmodel', 'testapp.change_charpkmodel'], any_perm=True) self.assertEqual(len(objects), 1) self.assertTrue(isinstance(objects, QuerySet)) @@ -1007,20 +1050,38 @@ set(objects.values_list('pk', flat=True)), {obj_with_char_pk.pk}) - def test_non_integer_primary_key_with_group_values(self): + def test_uuid_primary_key_with_any_perm(self): + """ + Verify that the function works with any_perm set to True when the + objects that should be returned have uuid primary keys. + """ + obj_with_uuid_pk = UUIDPKModel.objects.create() + assign_perm('add_uuidpkmodel', self.user, obj_with_uuid_pk) + + objects = get_objects_for_user( + self.user, + ['testapp.add_uuidpkmodel', 'testapp.change_uuidpkmodel'], + any_perm=True) + self.assertEqual(len(objects), 1) + self.assertTrue(isinstance(objects, QuerySet)) + self.assertEqual( + set(objects.values_list('pk', flat=True)), + {obj_with_uuid_pk.pk}) + + def test_varchar_primary_key_with_group_values(self): """ Verify that the function works when the objects that should be returned - have non-integer primary keys, and those objects are due to the user's + have varchar primary keys, and those objects are due to the user's groups. """ - obj_with_char_pk = NonIntPKModel.objects.create( + obj_with_char_pk = CharPKModel.objects.create( char_pk='testprimarykey') - assign_perm('add_nonintpkmodel', self.group, obj_with_char_pk) + assign_perm('add_charpkmodel', self.group, obj_with_char_pk) self.user.groups.add(self.group) objects = get_objects_for_user( self.user, - ['testapp.add_nonintpkmodel', 'testapp.change_nonintpkmodel'], + ['testapp.add_charpkmodel', 'testapp.change_charpkmodel'], any_perm=True) self.assertEqual(len(objects), 1) self.assertTrue(isinstance(objects, QuerySet)) @@ -1028,6 +1089,37 @@ set(objects.values_list('pk', flat=True)), {obj_with_char_pk.pk}) + def test_model_inheritance(self): + child_with_perm = ChildTestModel.objects.create(name="child1") + assign_perm('testapp.change_childtestmodel', self.user, child_with_perm) + child_without_perm = ChildTestModel.objects.create(name="child2") + + children = get_objects_for_user(self.user, 'testapp.change_childtestmodel', ChildTestModel) + + self.assertEqual(1, len(children)) + self.assertIn(child_with_perm, children) + self.assertNotIn(child_without_perm, children) + + def test_uuid_primary_key_with_group_values(self): + """ + Verify that the function works when the objects that should be returned + have uuid primary keys, and those objects are due to the user's + groups. + """ + obj_with_uuid_pk = UUIDPKModel.objects.create() + assign_perm('add_uuidpkmodel', self.group, obj_with_uuid_pk) + self.user.groups.add(self.group) + + objects = get_objects_for_user( + self.user, + ['testapp.add_uuidpkmodel', 'testapp.change_uuidpkmodel'], + any_perm=True) + self.assertEqual(len(objects), 1) + self.assertTrue(isinstance(objects, QuerySet)) + self.assertEqual( + set(objects.values_list('pk', flat=True)), + {obj_with_uuid_pk.pk}) + def test_exception_different_ctypes(self): self.assertRaises(MixedContentTypeError, get_objects_for_user, self.user, ['auth.change_permission', 'auth.change_group']) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/requirements.txt new/django-guardian-2.3.0/requirements.txt --- old/django-guardian-2.2.0/requirements.txt 2019-12-20 15:00:56.000000000 +0100 +++ new/django-guardian-2.3.0/requirements.txt 2020-06-08 01:49:56.000000000 +0200 @@ -1,4 +1,4 @@ -Django>=2.1 +Django>=2.2 django-environ bumpversion mock diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/setup.cfg new/django-guardian-2.3.0/setup.cfg --- old/django-guardian-2.2.0/setup.cfg 2020-02-03 19:22:39.000000000 +0100 +++ new/django-guardian-2.3.0/setup.cfg 2020-06-08 01:52:28.000000000 +0200 @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2.2.0 +current_version = 2.3.0 [build_sphinx] source-dir = docs/ @@ -10,7 +10,7 @@ upload-dir = docs/build/html [bdist_rpm] -requires = Django >= 2.1 +requires = Django >= 2.2 [aliases] test = pytest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/setup.py new/django-guardian-2.3.0/setup.py --- old/django-guardian-2.2.0/setup.py 2020-02-03 19:21:46.000000000 +0100 +++ new/django-guardian-2.3.0/setup.py 2020-06-08 01:50:55.000000000 +0200 @@ -3,10 +3,10 @@ from extras import RunFlakesCommand -version = '2.2.0' +version = '2.3.0' readme_file = os.path.join(os.path.dirname(__file__), 'README.rst') -with open(readme_file, 'r') as f: +with open(readme_file) as f: long_description = f.read() setup( @@ -28,12 +28,11 @@ ], include_package_data=True, license='BSD', - install_requires=["Django>=2.1"], + install_requires=["Django>=2.2"], tests_require=['mock', 'django-environ', 'pytest', 'pytest-django'], classifiers=['Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Framework :: Django', - 'Framework :: Django :: 2.1', 'Framework :: Django :: 2.2', 'Framework :: Django :: 3.0', 'Intended Audience :: Developers', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-2.2.0/tox.ini new/django-guardian-2.3.0/tox.ini --- old/django-guardian-2.2.0/tox.ini 2020-02-03 19:18:19.000000000 +0100 +++ new/django-guardian-2.3.0/tox.ini 2020-06-08 01:49:56.000000000 +0200 @@ -1,7 +1,6 @@ [tox] downloadcache = {toxworkdir}/cache/ envlist = # sort by django version, next by python version - {core,example,docs}-py{35,36,37}-django21, {core,example,docs}-py{35,36,37,38}-django22, {core,example,docs}-py{36,37,38}-django30, @@ -16,7 +15,6 @@ example: example_project docs: docs commands = - django21: python {toxinidir}/manage.py makemigrations --check --dry-run django22: python {toxinidir}/manage.py makemigrations --check --dry-run django30: python {toxinidir}/manage.py makemigrations --check --dry-run core: py.test --cov=guardian @@ -34,6 +32,5 @@ docs: sphinx docs: sphinx_rtd_theme docs: setuptools_scm - django21: django>=2.1,<2.2 django22: django>=2.2,<2.3 django30: django>=3.0,<3.1