Hello community, here is the log from the commit of package python-django-guardian for openSUSE:Factory checked in at 2012-03-16 13:22:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-django-guardian (Old) and /work/SRC/openSUSE:Factory/.python-django-guardian.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-django-guardian", Maintainer is "" Changes: -------- --- /work/SRC/openSUSE:Factory/python-django-guardian/python-django-guardian.changes 2012-02-16 10:09:10.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.python-django-guardian.new/python-django-guardian.changes 2012-03-16 13:22:45.000000000 +0100 @@ -1,0 +2,13 @@ +Mon Mar 12 14:55:35 UTC 2012 - alexan...@exatati.com.br + +- Update to 1.0.4: + * Added accept_global_perms flag for decorators + * Added missing *fieldset* closing tag at template + * Fixed misleading comments at docstrings + * Fixed broken grappelli tests + * Fixed issue disallowing creation of RPM package + * Started using tox for tests + * Expanded orphaned object permissions documentation + * Expanded configuration settings documentation + +------------------------------------------------------------------- Old: ---- django-guardian-1.0.3.tar.bz2 New: ---- django-guardian-1.0.4.tar.bz2 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-django-guardian.spec ++++++ --- /var/tmp/diff_new_pack.HnD8Pk/_old 2012-03-16 13:22:46.000000000 +0100 +++ /var/tmp/diff_new_pack.HnD8Pk/_new 2012-03-16 13:22:46.000000000 +0100 @@ -1,7 +1,7 @@ # # spec file for package python-django-guardian # -# Copyright (c) 2011 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,7 +19,7 @@ %{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")} Name: python-django-guardian -Version: 1.0.3 +Version: 1.0.4 Release: 0 Url: http://github.com/lukaszb/django-guardian Summary: Implementation of per object permissions for Django 1.2 ++++++ django-guardian-1.0.3.tar.bz2 -> django-guardian-1.0.4.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/CHANGES new/django-guardian-1.0.4/CHANGES --- old/django-guardian-1.0.3/CHANGES 2011-07-25 11:53:27.000000000 +0200 +++ new/django-guardian-1.0.4/CHANGES 2012-03-12 13:45:12.000000000 +0100 @@ -1,5 +1,17 @@ +Release 1.0.4 (Mar 12, 2012) +============================ + +* Added ``accept_global_perms`` flag for decorators +* Added missing *fieldset* closing tag at template +* Fixed misleading comments at docstrings +* Fixed broken grappelli tests +* Fixed issue disallowing creation of RPM package +* Started using tox for tests +* Expanded orphaned object permissions documentation +* Expanded configuration settings documentation + Release 1.0.3 (Jul 25, 2011) -================================== +============================ * added ``get_objects_for_group`` shortcut (thanks to Rafael Ponieman) * added ``user_can_access_owned_objects_only`` flag to ``GuardedModelAdmin`` @@ -8,7 +20,7 @@ * included ADC theme for documentation Release 1.0.2 (Apr 12, 2011) -================================== +============================ * ``get_users_with_perms`` now accepts ``with_group_users`` flag * Fixed ``group_id`` issue at admin templates @@ -17,14 +29,14 @@ Release 1.0.1 (Mar 25, 2011) -================================== +============================ * ``get_users_with_perms`` now accepts ``with_superusers`` flag * Small fix for documentation building process Release 1.0.0 (Jan 27, 2011) -================================== +============================ * A final v1.0 release! diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/PKG-INFO new/django-guardian-1.0.4/PKG-INFO --- old/django-guardian-1.0.3/PKG-INFO 2011-07-25 11:57:51.000000000 +0200 +++ new/django-guardian-1.0.4/PKG-INFO 2012-03-12 13:45:45.000000000 +0100 @@ -1,9 +1,7 @@ Metadata-Version: 1.0 Name: django-guardian -Version: 1.0.3 -Summary: -Implementation of per object permissions for Django 1.2. - +Version: 1.0.4 +Summary: Implementation of per object permissions for Django 1.2 or later. Home-page: http://github.com/lukaszb/django-guardian Author: Lukasz Balcerzak Author-email: lukaszbalcer...@gmail.com diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/django_guardian.egg-info/PKG-INFO new/django-guardian-1.0.4/django_guardian.egg-info/PKG-INFO --- old/django-guardian-1.0.3/django_guardian.egg-info/PKG-INFO 2011-07-25 11:57:50.000000000 +0200 +++ new/django-guardian-1.0.4/django_guardian.egg-info/PKG-INFO 2012-03-12 13:45:43.000000000 +0100 @@ -1,9 +1,7 @@ Metadata-Version: 1.0 Name: django-guardian -Version: 1.0.3 -Summary: -Implementation of per object permissions for Django 1.2. - +Version: 1.0.4 +Summary: Implementation of per object permissions for Django 1.2 or later. Home-page: http://github.com/lukaszb/django-guardian Author: Lukasz Balcerzak Author-email: lukaszbalcer...@gmail.com diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/django_guardian.egg-info/SOURCES.txt new/django-guardian-1.0.4/django_guardian.egg-info/SOURCES.txt --- old/django-guardian-1.0.3/django_guardian.egg-info/SOURCES.txt 2011-07-25 11:57:50.000000000 +0200 +++ new/django-guardian-1.0.4/django_guardian.egg-info/SOURCES.txt 2012-03-12 13:45:45.000000000 +0100 @@ -37,6 +37,7 @@ docs/develop/changes.rst docs/develop/example_project.rst docs/develop/index.rst +docs/develop/supported-versions.rst docs/develop/testing.rst docs/theme/ADCtheme/LICENSE docs/theme/ADCtheme/layout.html @@ -90,6 +91,7 @@ guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage.html guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_group.html guardian/templates/admin/guardian/contrib/grappelli/obj_perms_manage_user.html +guardian/templates/admin/guardian/model/action_add_obj_perms.html guardian/templates/admin/guardian/model/change_form.html guardian/templates/admin/guardian/model/field.html guardian/templates/admin/guardian/model/obj_perms_manage.html @@ -99,6 +101,7 @@ guardian/templatetags/guardian_tags.py guardian/tests/__init__.py guardian/tests/admin_test.py +guardian/tests/conf_test.py guardian/tests/core_test.py guardian/tests/custompkmodel_test.py guardian/tests/decorators_test.py @@ -110,4 +113,5 @@ guardian/tests/urls.py guardian/tests/utils_test.py guardian/tests/templates/404.html -guardian/tests/templates/500.html \ No newline at end of file +guardian/tests/templates/500.html +guardian/tests/templates/dummy403.html \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/docs/api/guardian.decorators.rst new/django-guardian-1.0.4/docs/api/guardian.decorators.rst --- old/django-guardian-1.0.3/docs/api/guardian.decorators.rst 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/docs/api/guardian.decorators.rst 2011-11-16 15:10:19.000000000 +0100 @@ -6,12 +6,16 @@ .. automodule:: guardian.decorators +.. _api-decorators-permission_required: + permission_required ------------------- .. autofunction:: guardian.decorators.permission_required +.. _api-decorators-permission_required_or_403: + permission_required_or_403 -------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/docs/configuration.rst new/django-guardian-1.0.4/docs/configuration.rst --- old/django-guardian-1.0.3/docs/configuration.rst 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/docs/configuration.rst 2011-11-19 23:18:18.000000000 +0100 @@ -32,3 +32,59 @@ We can change id to whatever we like. Project should be now ready to use object permissions. + +Optional settings +================= + +In addition to requried ``ANONYMOUS_USER_ID`` setting, guardian has following, +optional configuration variables: + + +.. setting:: GUARDIAN_RAISE_403 + +GUARDIAN_RAISE_403 +------------------ + +.. versionadded:: 1.0.4 + +If set to ``True``, guardian would raise +``django.core.exceptions.PermissionDenied`` error instead of returning empty +``django.http.HttpResponseForbidden``. + +.. warning:: + + Remember that you cannot use both :setting:`GUARDIAN_RENDER_403` **AND** + :setting:`GUARDIAN_RAISE_403` - if both are set to ``True``, + ``django.core.exceptions.ImproperlyConfigured`` would be raised. + + + +.. setting:: GUARDIAN_RENDER_403 + +GUARDIAN_RENDER_403 +------------------- + +.. versionadded:: 1.0.4 + +If set to ``True``, guardian would try to render 403 response rather than +return contentless ``django.http.HttpResponseForbidden``. Would use template +pointed by :setting:`GUARDIAN_TEMPLATE_403` to do that. Default is ``False``. + +.. warning:: + + Remember that you cannot use both :setting:`GUARDIAN_RENDER_403` **AND** + :setting:`GUARDIAN_RAISE_403` - if both are set to ``True``, + ``django.core.exceptions.ImproperlyConfigured`` would be raised. + + +.. setting:: GUARDIAN_TEMPLATE_403 + +GUARDIAN_TEMPLATE_403 +--------------------- + +.. versionadded:: 1.0.4 + +Tells parts of guardian what template to use for responses with status code +``403`` (i.e. :ref:`api-decorators-permission_required`). Defaults to +``403.html``. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/docs/develop/index.rst new/django-guardian-1.0.4/docs/develop/index.rst --- old/django-guardian-1.0.3/docs/develop/index.rst 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/docs/develop/index.rst 2011-11-19 22:28:06.000000000 +0100 @@ -7,5 +7,6 @@ example_project testing + supported-versions changes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/docs/develop/supported-versions.rst new/django-guardian-1.0.4/docs/develop/supported-versions.rst --- old/django-guardian-1.0.3/docs/develop/supported-versions.rst 1970-01-01 01:00:00.000000000 +0100 +++ new/django-guardian-1.0.4/docs/develop/supported-versions.rst 2011-11-19 23:27:12.000000000 +0100 @@ -0,0 +1,19 @@ +.. _supported-versions: + +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**. + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/docs/develop/testing.rst new/django-guardian-1.0.4/docs/develop/testing.rst --- old/django-guardian-1.0.3/docs/develop/testing.rst 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/docs/develop/testing.rst 2011-11-19 22:29:42.000000000 +0100 @@ -17,6 +17,10 @@ Having this on mind we tried to build small set of necessary functions and created a lot of testing scenarios. Neverteless, if anyone would found a bug in this application, please take a minute and file it at `issue-tracker`_. +Moreover, if someone would spot a *security hole* (a bug that might affect +security of systems that use ``django-guardian`` as permission management +library), please **DO NOT** create a public issue but contact me directly +(lukaszbalcer...@gmail.com). Running tests ------------- @@ -71,7 +75,26 @@ ------------------------------------------------------------------- TOTAL 231 231 100% +Tox +--- + +.. versionadded:: 1.0.4 + +We also started using tox_ to ensure ``django-guardian``'s tests would pass on +all supported Python and Django versions (see :ref:`supported-versions`). To +use it, simply install ``tox``:: + + pip install tox + +and run it within ``django-guardian`` checkout directory:: + + tox + +First time should take some time (it needs to create separate virtual +environments and pull dependencies) but would ensure everything is fine. + + .. _owasp: http://www.owasp.org/ .. _issue-tracker: http://github.com/lukaszb/django-guardian .. _coverage: http://nedbatchelder.com/code/coverage/ - +.. _tox: http://pypi.python.org/pypi/tox Files old/django-guardian-1.0.3/docs/exts.pyc and new/django-guardian-1.0.4/docs/exts.pyc differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/docs/theme/ADCtheme/static/adctheme.css new/django-guardian-1.0.4/docs/theme/ADCtheme/static/adctheme.css --- old/django-guardian-1.0.3/docs/theme/ADCtheme/static/adctheme.css 2011-07-25 11:00:47.000000000 +0200 +++ new/django-guardian-1.0.4/docs/theme/ADCtheme/static/adctheme.css 2011-11-16 15:09:08.000000000 +0100 @@ -391,9 +391,7 @@ table.docutils { border-collapse: collapse; - border-top: 1px solid #919699; - border-left: 1px solid #919699; - border-right: 1px solid #919699; + border: 1px solid #919699; font-size:12px; padding:8px; text-align:left; @@ -754,4 +752,4 @@ } li p { margin-top:8px; -} \ No newline at end of file +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/docs/userguide/caveats.rst new/django-guardian-1.0.4/docs/userguide/caveats.rst --- old/django-guardian-1.0.3/docs/userguide/caveats.rst 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/docs/userguide/caveats.rst 2011-10-10 10:34:42.000000000 +0200 @@ -20,11 +20,11 @@ another user creates account with *joe* as username. The problem is that if we haven't removed object permissions explicitly in the process of first *joe* account removal, *jane* still has read permissions for *joe's* configuration -file - but this is another user. +file - but this is another user. There is no easy way to deal with orphaned permissions as they are not foreign keyed with objects directly. Even if they would, there are some database engines -- or *ON DELETE* rules - which restricts removal of related objects. +- or *ON DELETE* rules - which restricts removal of related objects. .. important:: @@ -34,10 +34,46 @@ Guardian comes with utility function which tries to help to remove orphaned object permissions. Remember - those are only helpers. Applications should -remove those object permissions explicitly. +remove those object permissions explicitly by itself. + +Taking our previous example, our application should remove user object for +*joe*, however, permisions for *joe* user assigned to *jane* would **NOT** +be removed. In this case, it would be very easy to remove user/group object +permissions if we connect proper action with proper signal. This could be +achieved by following snippet:: + + from django.contrib.auth.models import User + from django.contrib.contenttypes.models import ContentType + from django.db.models import Q + from django.db.models.signals import pre_delete + from guardian.models import UserObjectPermission + from guardian.models import GroupObjectPermission + + + def remove_obj_perms_connected_with_user(sender, instance, **kwargs): + filters = Q(content_type=ContentType.objects.get_for_model(instance), + object_pk=instance.pk) + UserObjectPermission.objects.filter(filters).delete() + GroupObjectPermission.objects.filter(filters).delete() + + pre_delete.connect(remove_obj_perms_connected_with_user, sender=User) + + +This signal handler would remove all object permissions connected with user +just before user is actually removed. + +If we forgot to add such handlers, we may still remove orphaned object +permissions by using :command:`clean_orphan_obj_perms` command. If our +application uses celery_, it is also very easy to remove orphaned permissions +periodically with :func:`guardian.utils.clean_orphan_obj_perms` function. +We would still **strongly** advise to remove orphaned object permissions +explicitly (i.e. at view that confirms object removal or using signals as +described above). .. seealso:: - :func:`guardian.utils.clean_orphan_obj_perms` - :command:`clean_orphan_obj_perms` +.. _celery: http://www.celeryproject.org/ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/__init__.py new/django-guardian-1.0.4/guardian/__init__.py --- old/django-guardian-1.0.3/guardian/__init__.py 2011-07-25 11:52:07.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/__init__.py 2012-03-12 13:38:54.000000000 +0100 @@ -1,7 +1,7 @@ """ -Implementation of per object permissions for Django 1.2. +Implementation of per object permissions for Django 1.2 or later. """ -VERSION = (1, 0, 3) +VERSION = (1, 0, 4) __version__ = '.'.join((str(each) for each in VERSION[:4])) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/admin.py new/django-guardian-1.0.4/guardian/admin.py --- old/django-guardian-1.0.3/guardian/admin.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/admin.py 2011-12-02 16:52:39.000000000 +0100 @@ -151,6 +151,7 @@ related content. """ context = { + 'adminform': {'model_admin': self}, 'object': obj, 'app_label': self.model._meta.app_label, 'opts': self.model._meta, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/backends.py new/django-guardian-1.0.4/guardian/backends.py --- old/django-guardian-1.0.3/guardian/backends.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/backends.py 2012-01-27 17:16:14.000000000 +0100 @@ -46,7 +46,7 @@ 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: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/conf/settings.py new/django-guardian-1.0.4/guardian/conf/settings.py --- old/django-guardian-1.0.3/guardian/conf/settings.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/conf/settings.py 2011-10-02 00:14:36.000000000 +0200 @@ -7,3 +7,14 @@ "ObjectPermissionBackend authorization backend you have to configure " "ANONYMOUS_USER_ID at your settings module") +RENDER_403 = getattr(settings, 'GUARDIAN_RENDER_403', False) +TEMPLATE_403 = getattr(settings, 'GUARDIAN_TEMPLATE_403', '403.html') +RAISE_403 = getattr(settings, 'GUARDIAN_RAISE_403', False) + +def check_configuration(): + if RENDER_403 and RAISE_403: + raise ImproperlyConfigured("Cannot use both GUARDIAN_RENDER_403 AND " + "GUARDIAN_RAISE_403 - only one of this config may be True") + +check_configuration() + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/decorators.py new/django-guardian-1.0.4/guardian/decorators.py --- old/django-guardian-1.0.3/guardian/decorators.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/decorators.py 2012-01-27 17:16:14.000000000 +0100 @@ -1,16 +1,18 @@ - from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME +from django.core.exceptions import PermissionDenied from django.http import HttpResponseForbidden, HttpResponseRedirect from django.utils.functional import wraps from django.utils.http import urlquote from django.db.models import Model, get_model from django.db.models.base import ModelBase from django.db.models.query import QuerySet -from django.shortcuts import get_object_or_404 - +from django.shortcuts import get_object_or_404, render_to_response +from django.template import RequestContext, TemplateDoesNotExist +from guardian.conf import settings as guardian_settings from guardian.exceptions import GuardianError + def permission_required(perm, lookup_variables=None, **kwargs): """ Decorator for views that checks whether a user has a particular permission @@ -26,7 +28,14 @@ Defaults to ``django.contrib.auth.REDIRECT_FIELD_NAME``. :param return_403: if set to ``True`` then instead of redirecting to the login page, response with status code 403 is returned ( - ``django.http.HttpResponseForbidden`` instance). Defaults to ``False``. + ``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:: @@ -50,6 +59,7 @@ 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 @@ -92,8 +102,21 @@ # 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: + response = render_to_response( + guardian_settings.TEMPLATE_403, {}, + RequestContext(request)) + response.status_code = 403 + return response + except TemplateDoesNotExist, e: + if settings.DEBUG: + raise e + elif guardian_settings.RAISE_403: + raise PermissionDenied return HttpResponseForbidden() else: path = urlquote(request.get_full_path()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/fixtures/tests.json new/django-guardian-1.0.4/guardian/fixtures/tests.json --- old/django-guardian-1.0.3/guardian/fixtures/tests.json 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/fixtures/tests.json 2012-03-12 13:15:11.000000000 +0100 @@ -1,5 +1,21 @@ [ { + "pk": 1, + "model": "auth.group", + "fields": { + "name": "admins", + "permissions": [] + } + }, + { + "pk": 2, + "model": "auth.group", + "fields": { + "name": "jackGroup", + "permissions": [] + } + }, + { "pk": -1, "model": "auth.user", "fields": { @@ -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": [] - } } ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/shortcuts.py new/django-guardian-1.0.4/guardian/shortcuts.py --- old/django-guardian-1.0.3/guardian/shortcuts.py 2011-07-25 11:41:17.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/shortcuts.py 2012-03-12 13:15:11.000000000 +0100 @@ -246,7 +246,7 @@ groups[group] = get_perms(group, obj) return groups -def get_objects_for_user(user, perms, klass=None, use_groups=True): +def get_objects_for_user(user, perms, klass=None, use_groups=True, any_perm=False): """ Returns queryset of objects for which a given ``user`` has *all* permissions present at ``perms``. @@ -262,6 +262,7 @@ 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 :raises MixedContentTypeError: when computed content type for ``perms`` and/or ``klass`` clashes. @@ -282,8 +283,10 @@ The permission string can also be an iterable. Continuing with the previous example: - >>> get_objects_for_user(joe, ['auth.change_group', 'auth.delete_group'], 'auth.delete_group']) + >>> get_objects_for_user(joe, ['auth.change_group', 'auth.delete_group']) [] + >>> get_objects_for_user(joe, ['auth.change_group', 'auth.delete_group'], any_perm=True) + [<Group some group>] >>> assign('auth.delete_group', joe, group) >>> get_objects_for_user(joe, ['auth.change_group', 'auth.delete_group']) [<Group some group>] @@ -357,7 +360,7 @@ pk_list = [] for pk, group in groupby(data, keyfunc): obj_codenames = set((e[1] for e in group)) - if codenames.issubset(obj_codenames): + if any_perm or codenames.issubset(obj_codenames): pk_list.append(pk) objects = queryset.filter(pk__in=pk_list) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/templates/admin/guardian/model/action_add_obj_perms.html new/django-guardian-1.0.4/guardian/templates/admin/guardian/model/action_add_obj_perms.html --- old/django-guardian-1.0.3/guardian/templates/admin/guardian/model/action_add_obj_perms.html 1970-01-01 01:00:00.000000000 +0100 +++ new/django-guardian-1.0.4/guardian/templates/admin/guardian/model/action_add_obj_perms.html 2011-11-20 00:49:10.000000000 +0100 @@ -0,0 +1,17 @@ +{% extends "admin/change_form.html" %} + +{% block extrahead %}{{ block.super }} +{{ form.media }} +{% endblock %} + +{% block content %} + +<div id="content-main"> + +<form action="." method="post"> + {% csrf_token %} + {{ form }} +</form> +</div> + +{% endblock %} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/templates/admin/guardian/model/obj_perms_manage.html new/django-guardian-1.0.4/guardian/templates/admin/guardian/model/obj_perms_manage.html --- old/django-guardian-1.0.3/guardian/templates/admin/guardian/model/obj_perms_manage.html 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/templates/admin/guardian/model/obj_perms_manage.html 2012-03-12 13:17:08.000000000 +0100 @@ -125,6 +125,7 @@ <div> <input name="submit_manage_group" type="submit" value="{% trans "Manage group" %}"/> </div> + </fieldset> </form> </div> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/templatetags/guardian_tags.py new/django-guardian-1.0.4/guardian/templatetags/guardian_tags.py --- old/django-guardian-1.0.3/guardian/templatetags/guardian_tags.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/templatetags/guardian_tags.py 2011-10-02 00:14:36.000000000 +0200 @@ -60,6 +60,10 @@ <a href="/pages/delete?target={{ flatpage.url }}">Remove page</a> {% endif %} + .. note:: + Please remember that superusers would always get full list of permissions + for a given object. + """ bits = token.split_contents() format = '{% get_obj_perms user/group for obj as "context_var" %}' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/tests/__init__.py new/django-guardian-1.0.4/guardian/tests/__init__.py --- old/django-guardian-1.0.3/guardian/tests/__init__.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/tests/__init__.py 2011-10-10 10:39:53.000000000 +0200 @@ -1,4 +1,5 @@ from admin_test import * +from conf_test import * from core_test import * from custompkmodel_test import * from decorators_test import * @@ -8,4 +9,3 @@ from utils_test import * from shortcuts_test import * from tags_test import * - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/tests/admin_test.py new/django-guardian-1.0.4/guardian/tests/admin_test.py --- old/django-guardian-1.0.3/guardian/tests/admin_test.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/tests/admin_test.py 2012-01-27 17:16:14.000000000 +0100 @@ -347,12 +347,13 @@ request = HttpRequest() request.user = joe qs = gma.queryset(request) - self.assertItemsEqual([e.pk for e in qs], [joe_entry.pk, jane_entry.pk]) + self.assertEqual(sorted([e.pk for e in qs]), + sorted([joe_entry.pk, jane_entry.pk])) 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): """ @@ -369,7 +370,7 @@ 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() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/tests/conf_test.py new/django-guardian-1.0.4/guardian/tests/conf_test.py --- old/django-guardian-1.0.3/guardian/tests/conf_test.py 1970-01-01 01:00:00.000000000 +0100 +++ new/django-guardian-1.0.4/guardian/tests/conf_test.py 2011-10-02 00:14:36.000000000 +0200 @@ -0,0 +1,15 @@ +import mock +from django.core.exceptions import ImproperlyConfigured +from django.test import TestCase +from guardian.conf import settings as guardian_settings + + +class TestConfiguration(TestCase): + + def test_check_configuration(self): + + with mock.patch('guardian.conf.settings.RENDER_403', True): + with mock.patch('guardian.conf.settings.RAISE_403', True): + self.assertRaises(ImproperlyConfigured, + guardian_settings.check_configuration) + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/tests/decorators_test.py new/django-guardian-1.0.4/guardian/tests/decorators_test.py --- old/django-guardian-1.0.3/guardian/tests/decorators_test.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/tests/decorators_test.py 2012-01-27 17:16:14.000000000 +0100 @@ -1,11 +1,14 @@ +import mock from django.test import TestCase +from django.conf import settings from django.contrib.auth.models import User, Group, AnonymousUser +from django.core.exceptions import PermissionDenied from django.http import HttpRequest from django.http import HttpResponse from django.http import HttpResponseForbidden from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 - +from django.template import TemplateDoesNotExist from guardian.decorators import permission_required, permission_required_or_403 from guardian.exceptions import GuardianError from guardian.shortcuts import assign @@ -17,8 +20,8 @@ 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: @@ -39,6 +42,68 @@ self.fail("Trying to decorate using permission_required without " "permission as first argument should raise exception") + def test_RENDER_403_is_false(self): + request = self._get_request(self.anon) + + @permission_required_or_403('not_installed_app.change_user') + def dummy_view(request): + return HttpResponse('dummy_view') + + with mock.patch('guardian.conf.settings.RENDER_403', False): + response = dummy_view(request) + self.assertEqual(response.content, '') + self.assertTrue(isinstance(response, HttpResponseForbidden)) + + @mock.patch('guardian.conf.settings.RENDER_403', True) + def test_TEMPLATE_403_setting(self): + request = self._get_request(self.anon) + + @permission_required_or_403('not_installed_app.change_user') + def dummy_view(request): + return HttpResponse('dummy_view') + + with mock.patch('guardian.conf.settings.TEMPLATE_403', 'dummy403.html'): + response = dummy_view(request) + self.assertEqual(response.content, 'foobar403\n') + + @mock.patch('guardian.conf.settings.RENDER_403', True) + def test_403_response_is_empty_if_template_cannot_be_found(self): + request = self._get_request(self.anon) + + @permission_required_or_403('not_installed_app.change_user') + def dummy_view(request): + return HttpResponse('dummy_view') + with mock.patch('guardian.conf.settings.TEMPLATE_403', + '_non-exisitng-403.html'): + response = dummy_view(request) + self.assertEqual(response.status_code, 403) + self.assertEqual(response.content, '') + + @mock.patch('guardian.conf.settings.RENDER_403', True) + def test_403_response_raises_error_if_debug_is_turned_on(self): + org_DEBUG = settings.DEBUG + settings.DEBUG = True + request = self._get_request(self.anon) + + @permission_required_or_403('not_installed_app.change_user') + def dummy_view(request): + return HttpResponse('dummy_view') + with mock.patch('guardian.conf.settings.TEMPLATE_403', + '_non-exisitng-403.html'): + self.assertRaises(TemplateDoesNotExist, dummy_view, request) + settings.DEBUG = org_DEBUG + + @mock.patch('guardian.conf.settings.RENDER_403', False) + @mock.patch('guardian.conf.settings.RAISE_403', True) + def test_RAISE_403_setting_is_true(self): + request = self._get_request(self.anon) + + @permission_required_or_403('not_installed_app.change_user') + def dummy_view(request): + return HttpResponse('dummy_view') + + self.assertRaises(PermissionDenied, dummy_view, request) + def test_anonymous_user_wrong_app(self): request = self._get_request(self.anon) @@ -46,7 +111,7 @@ @permission_required_or_403('not_installed_app.change_user') def dummy_view(request): return HttpResponse('dummy_view') - self.assertTrue(isinstance(dummy_view(request), HttpResponseForbidden)) + self.assertEqual(dummy_view(request).status_code, 403) def test_anonymous_user_wrong_codename(self): @@ -55,7 +120,7 @@ @permission_required_or_403('auth.wrong_codename') def dummy_view(request): return HttpResponse('dummy_view') - self.assertTrue(isinstance(dummy_view(request), HttpResponseForbidden)) + self.assertEqual(dummy_view(request).status_code, 403) def test_anonymous_user(self): @@ -64,7 +129,7 @@ @permission_required_or_403('auth.change_user') def dummy_view(request): return HttpResponse('dummy_view') - self.assertTrue(isinstance(dummy_view(request), HttpResponseForbidden)) + self.assertEqual(dummy_view(request).status_code, 403) def test_wrong_lookup_variables_number(self): @@ -104,6 +169,92 @@ 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) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/tests/shortcuts_test.py new/django-guardian-1.0.4/guardian/tests/shortcuts_test.py --- old/django-guardian-1.0.3/guardian/tests/shortcuts_test.py 2011-07-25 11:41:17.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/tests/shortcuts_test.py 2012-03-12 13:15:11.000000000 +0100 @@ -481,6 +481,20 @@ set(objects.values_list('name', flat=True)), set([groups[1].name])) + def test_any_of_multiple_perms_to_check(self): + group_names = ['group1', 'group2', 'group3'] + groups = [Group.objects.create(name=name) for name in group_names] + assign('auth.change_group', self.user, groups[0]) + assign('auth.delete_group', self.user, groups[2]) + + objects = get_objects_for_user(self.user, ['auth.change_group', + 'auth.delete_group'], any_perm=True) + self.assertEqual(len(objects), 2) + self.assertTrue(isinstance(objects, QuerySet)) + self.assertEqual( + set(objects.values_list('name', flat=True)), + set([groups[0].name, groups[2].name])) + def test_groups_perms(self): group1 = Group.objects.create(name='group1') group2 = Group.objects.create(name='group2') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/tests/templates/dummy403.html new/django-guardian-1.0.4/guardian/tests/templates/dummy403.html --- old/django-guardian-1.0.3/guardian/tests/templates/dummy403.html 1970-01-01 01:00:00.000000000 +0100 +++ new/django-guardian-1.0.4/guardian/tests/templates/dummy403.html 2011-10-02 00:14:36.000000000 +0200 @@ -0,0 +1 @@ +foobar403 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/guardian/testsettings.py new/django-guardian-1.0.4/guardian/testsettings.py --- old/django-guardian-1.0.3/guardian/testsettings.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/guardian/testsettings.py 2012-01-27 17:16:14.000000000 +0100 @@ -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') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/django-guardian-1.0.3/setup.py new/django-guardian-1.0.4/setup.py --- old/django-guardian-1.0.3/setup.py 2011-07-25 10:11:25.000000000 +0200 +++ new/django-guardian-1.0.4/setup.py 2011-10-02 00:14:36.000000000 +0200 @@ -18,7 +18,7 @@ author = 'Lukasz Balcerzak', author_email = 'lukaszbalcer...@gmail.com', download_url='http://github.com/lukaszb/django-guardian/downloads', - description = guardian.__doc__, + description = guardian.__doc__.strip(), long_description = long_description, zip_safe = False, packages = find_packages(), -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org