Skip to content

Commit

Permalink
first working version
Browse files Browse the repository at this point in the history
  • Loading branch information
tomi77 committed May 6, 2017
1 parent d367a89 commit 29be6a3
Show file tree
Hide file tree
Showing 19 changed files with 407 additions and 2 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ ENV/

# Rope project settings
.ropeproject

test.sqlite
2 changes: 0 additions & 2 deletions README.md

This file was deleted.

60 changes: 60 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
================
django-auth-role
================

Add roles to django-auth

Installation
============

.. sourcecode:: sh

pip install django-auth-role

Quick start
===========

Add ``authrole`` to `INSTALLED_APPS`. ``django.contrib.auth`` and ``django.contrib.contenttypes`` are also required.

.. sourcecode:: python

INSTALLED_APPS = [
...
'django.contrib.contenttypes',
'django.contrib.auth',
'authrole',
]

Extend ``auth.User``.

.. sourcecode:: python

from django.db import models

class MyUser(models.Model):
role = models.ForeignKey('authrole.Role', related_name='myusers')
user = models.OneToOneField('auth.User', related_name='user')

Create tables.

.. sourcecode:: sh

./manage.py migrate

Extend Your own authentication backend.

.. sourcecode:: python

from authrole.auth.backends import BaseAuthRoleBackend

class MyBackend(BaseAuthRoleBackend):
def fetch_permission(self, user_obj):
return Permission.objects.filter(group__roles__myusers__user=user_obj)

And add it to `AUTHENTICATION_BACKENDS`.

.. sourcecode:: python

AUTHENTICATION_BACKENDS = (
'app.MyBackend',
)
Empty file added authrole/__init__.py
Empty file.
14 changes: 14 additions & 0 deletions authrole/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from django.contrib import admin

from .models import Role


# @admin.register(Role)
class RoleAdmin(admin.ModelAdmin):
search_fields = ['name']
list_display = ('name',)
list_display_links = ('name',)
list_filter = ('name',)
filter_horizontal = ('groups',)

admin.site.register(Role, RoleAdmin)
Empty file added authrole/auth/__init__.py
Empty file.
43 changes: 43 additions & 0 deletions authrole/auth/backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from __future__ import unicode_literals

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Permission


class BaseAuthRoleBackend(ModelBackend):
"""
Authenticates against authrole.models.Role.
"""
def fetch_permission(self, user_obj):
raise NotImplemented()

def get_role_permissions(self, user_obj, obj=None):
"""
Returns a set of permission strings that this user has through his/her
role.
"""
if user_obj.is_anonymous() or obj is not None:
return set()
if not hasattr(user_obj, '_role_perm_cache'):
if user_obj.is_superuser:
perms = Permission.objects.all()
else:
perms = self.fetch_permission(user_obj)
perms = perms.values_list('content_type__app_label', 'codename') \
.order_by()
user_obj._role_perm_cache = set(['%s.%s' % (ct, name)
for ct, name in perms])
return user_obj._role_perm_cache

def get_all_permissions(self, user_obj, obj=None):
if user_obj.is_anonymous() or obj is not None:
return set()
user_obj._perm_cache = super(BaseAuthRoleBackend, self) \
.get_all_permissions(user_obj, obj)
user_obj._perm_cache.update(self.get_role_permissions(user_obj))
return user_obj._perm_cache


class ElcarAuthRoleBackend(BaseAuthRoleBackend):
def fetch_permission(self, user_obj):
return Permission.objects.filter(group__roles__elcaruser__auth_user=user_obj)
35 changes: 35 additions & 0 deletions authrole/locale/pl/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# django-auth-role polish translation.
# Copyright (C) 2017 Tomasz Jakub Rup
# This file is distributed under the same license as the django-auth-role package.
# Tomasz Jakub Rup <[email protected]>, 2017.
msgid ""
msgstr ""
"Project-Id-Version: django-auth-role\n"
"Report-Msgid-Bugs-To: https://github.com/tomi77/django-auth-role/issues\n"
"POT-Creation-Date: 2017-05-03 15:06+0200\n"
"PO-Revision-Date: 2017-05-03 15:07+0200\n"
"Last-Translator: Tomasz Jakub Rup <[email protected]>\n"
"Language-Team: \n"
"Language: pl\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n"
"%100<12 || n%100>=14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n"
"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"

#: models.py:11
msgid "Role name"
msgstr "Nazwa roli"

#: models.py:13
msgid "Groups of permissions"
msgstr "Grupy uprawnień"

#: models.py:16
msgid "Role"
msgstr "Rola"

#: models.py:17
msgid "Roles"
msgstr "Role"
29 changes: 29 additions & 0 deletions authrole/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-05-03 08:19
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('auth', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='Role',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=128, unique=True, verbose_name='Role name')),
('groups', models.ManyToManyField(related_name='roles', to='auth.Group', verbose_name='Groups of permissions')),
],
options={
'verbose_name': 'Role',
'verbose_name_plural': 'Roles',
},
),
]
Empty file added authrole/migrations/__init__.py
Empty file.
23 changes: 23 additions & 0 deletions authrole/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from __future__ import unicode_literals

from django.db import models
from django.utils.encoding import python_2_unicode_compatible
from django.utils.translation import ugettext_lazy as _


@python_2_unicode_compatible
class Role(models.Model):
name = models.CharField(max_length=128, unique=True,
verbose_name=_('Role name'))
groups = models.ManyToManyField('auth.Group', related_name='roles',
verbose_name=_('Groups of permissions'))

class Meta(object):
verbose_name = _('Role')
verbose_name_plural = _('Roles')

def __repr__(self):
return 'authrole.models.Role[pk=%d]' % self.pk

def __str__(self):
return self.name
8 changes: 8 additions & 0 deletions manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env python
import os

os.environ['DJANGO_SETTINGS_MODULE'] = 'tests.settings'
from django.core import management

if __name__ == "__main__":
management.execute_from_command_line()
Empty file added tests/__init__.py
Empty file.
97 changes: 97 additions & 0 deletions tests/fixtures/role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
- pk: 1
model: 'contenttypes.ContentType'
fields:
app_label: 'app'
model: 'model1'
- pk: 2
model: 'contenttypes.ContentType'
fields:
app_label: 'app'
model: 'model2'

- pk: 1
model: 'auth.Permission'
fields:
name: 'can add app.model1'
content_type: 1
codename: 'can_add_model1'
- pk: 2
model: 'auth.Permission'
fields:
name: 'can update app.model1'
content_type: 1
codename: 'can_update_model1'
- pk: 3
model: 'auth.Permission'
fields:
name: 'can delete app.model1'
content_type: 1
codename: 'can_delete_model1'
- pk: 4
model: 'auth.Permission'
fields:
name: 'can add app.model2'
content_type: 2
codename: 'can_add_model2'
- pk: 5
model: 'auth.Permission'
fields:
name: 'can update app.model2'
content_type: 2
codename: 'can_update_model2'
- pk: 6
model: 'auth.Permission'
fields:
name: 'can delete app.model2'
content_type: 2
codename: 'can_delete_model2'

- pk: 1
model: 'auth.Group'
fields:
name: 'all model1 permissions'
permissions: [1, 2, 3]
- pk: 2
model: 'auth.Group'
fields:
name: 'all model2 permissions'
permissions: [4, 5, 6]

- pk: 1
model: 'authrole.Role'
fields:
name: 'empty group'
groups: []
- pk: 2
model: 'authrole.Role'
fields:
name: 'all groups'
groups: [1, 2]

- pk: 1
model: 'auth.User'
fields:
username: 'user1'
password: 'pbkdf2_sha256$10000$vkRy7QauoLLj$ry+3xm3YX+YrSXbri8s3EcXDIrx5ceM+xQjtpLdw2oE='
is_active: true
is_superuser: false
is_staff: false
- pk: 2
model: 'auth.User'
fields:
username: 'user2'
password: 'pbkdf2_sha256$10000$vkRy7QauoLLj$ry+3xm3YX+YrSXbri8s3EcXDIrx5ceM+xQjtpLdw2oE='
is_active: true
is_superuser: false
is_staff: false

- pk: 1
model: 'tests.MyUser'
fields:
user: 1
role: 1
- pk: 2
model: 'tests.MyUser'
fields:
user: 2
role: 2
28 changes: 28 additions & 0 deletions tests/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-05-03 08:19
from __future__ import unicode_literals

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
('authrole', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='MyUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('role', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='myusers', to='authrole.Role')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='user', to=settings.AUTH_USER_MODEL)),
],
),
]
Empty file added tests/migrations/__init__.py
Empty file.
6 changes: 6 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.db import models


class MyUser(models.Model):
role = models.ForeignKey('authrole.Role', related_name='myusers')
user = models.OneToOneField('auth.User', related_name='user')
30 changes: 30 additions & 0 deletions tests/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import django


SECRET_KEY = 'qaz123'

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test.sqlite'
}
}

INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'authrole',
'tests',
]

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
},
]

MIDDLEWARE_CLASSES = []

if django.VERSION[:2] <= (1, 6):
INSTALLED_APPS += ['south']
Loading

0 comments on commit 29be6a3

Please sign in to comment.