Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 188 lines (143 sloc) 5.763 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
# coding:utf-8

"""
Limit to usergroups
~~~~~~~~~~~~~~~~~~~
Helper to limit something to:
* for everyone (anonymous users)
* for staff users
* for superusers
* for a user group
In forms you will get a select field with:
* anonymous users
* staff users
* superusers
* ..all existing user groups..
usage example
~~~~~~~~~~~~~
model.py
---------------------------------------------------------------------------
class FooBar(models.Model):
permit_edit = limit_to_usergroups.UsergroupsModelField()
permit_view = limit_to_usergroups.UsergroupsModelField()
---------------------------------------------------------------------------
views.py
---------------------------------------------------------------------------
def view(request):
queryset = FooBar.objects.all()
queryset = limit_to_usergroups.filter_permission(queryset, permit_view=request.user)
...
def edit(request, id):
foo = FooBar.objects.get(id=id)
if not limit_to_usergroups.has_permission(poll, permit_edit=request.user):
msg = _("You have no permission to edit this.")
if settings.DEBUG:
verbose_limit_name = limit_to_usergroups.get_verbose_limit_name(foo.permit_edit)
msg += " (Limited to: %s)" % verbose_limit_name
messages.error(request, msg)
return HttpResponseRedirect("foobar)
...
---------------------------------------------------------------------------

:copyleft: 2011-2012 by the django-tools team, see AUTHORS for more details.
:license: GNU GPL v3 or above, see LICENSE for more details.
"""

from django.db import models
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import Group


def has_permission(item, **kwargs):
    """
return True/False if use has permission stored in UsergroupsModelField.
return True, if permission are ok
return False, if permission are not sufficient.
e.g.:
has_permission(poll, permit_vote=request.user)
has_permission(item, model_field1=user, model_field2=user)
"""
    for attr_name, user in kwargs.items():
        limit_permission_value = getattr(item, attr_name)
        limit_permission_value = int(limit_permission_value)

        if limit_permission_value == UsergroupsModelField.ANONYMOUS_USERS:
            continue

        if user.is_anonymous():
            return False

        if limit_permission_value == UsergroupsModelField.NORMAL_USERS:
            if user.is_authenticated():
                continue
            else:
                return False

        if limit_permission_value == UsergroupsModelField.STAFF_USERS:
            if user.is_staff:
                continue
            else:
                return False

        if limit_permission_value == UsergroupsModelField.SUPERUSERS:
            if user.is_superuser:
                continue
            else:
                return False

        usergroup = Group.objects.get(id=limit_permission_value)
        usergroups = user.groups.all()
        if usergroup not in usergroups:
            return False

    return True



def filter_permission(queryset, **kwargs):
    """
Filter a given queryset with UsergroupsModelField.
e.g.:
queryset = filter_permission(queryset, permit_view=request.user)
queryset = filter_permission(queryset, model_field1=user, model_field2=user)
FIXME: Would be nice, if this is a normal QuerySet method
"""
    result = [item for item in queryset if has_permission(item, **kwargs)]
    return result


def get_verbose_limit_name(value):
    """
Simply convert the integer value of a UsergroupsModelField to his select choice text
>>> get_verbose_limit_name(-1)
u"staff users"
"""
    limit_dict = get_limit_dict()
    return limit_dict[value]


def get_user_groups():
    groups = Group.objects.values_list("id", "name")
    return list(groups)


def get_limit_dict():
    # use unicode() to evaluate ugettext_lazy:
    limit_dict = dict([(k, unicode(v)) for k, v in UsergroupsModelField.USER_TYPES_DICT.items()])

    groups = get_user_groups()
    limit_dict.update(dict(groups))
    return limit_dict


class UsergroupsModelField(models.IntegerField):
    """
TODO: Use html select optgroup [1] to group anonymous, staff and superusers
from user groups
[1] http://www.w3.org/wiki/HTML/Elements/optgroup
"""
    ANONYMOUS_USERS = 0
    STAFF_USERS = -1
    SUPERUSERS = -2
    NORMAL_USERS = -3

    USER_TYPES_CHOICES = [
        (ANONYMOUS_USERS, _("anonymous users")),
        (NORMAL_USERS, _("normal users")),
        (STAFF_USERS, _("staff users")),
        (SUPERUSERS, _("superusers")),
    ]
    USER_TYPES_DICT = dict(USER_TYPES_CHOICES)

    def __init__(self, *args, **kwargs):
        """
We added only the static choices here, because we should not access
the database here (can break unittests)
In this cases the choices feature of this field is activated, but
in any case self.get_choices() would be called: There we append
the user groups
"""
        kwargs["choices"] = self.USER_TYPES_CHOICES
        
        super(UsergroupsModelField, self).__init__(*args, **kwargs)

    def get_choices(self, *args, **kwargs):
        """
Built the choices list with the static part and all existing
user groups from database.
"""
        groups = get_user_groups()
        choices = self.USER_TYPES_CHOICES + list(groups)
        return choices


Something went wrong with that request. Please try again.