-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #86 from maykinmedia/feature/object-type-permissions
Feature/object type permissions
- Loading branch information
Showing
17 changed files
with
460 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,21 @@ | ||
from django.contrib import admin | ||
from django.contrib.auth.admin import UserAdmin | ||
from django.utils.translation import ugettext_lazy as _ | ||
|
||
from hijack_admin.admin import HijackUserAdminMixin | ||
|
||
from .models import User | ||
from .models import ObjectPermission, User | ||
|
||
|
||
@admin.register(User) | ||
class _UserAdmin(UserAdmin, HijackUserAdminMixin): | ||
list_display = UserAdmin.list_display + ("hijack_field",) | ||
fieldsets = UserAdmin.fieldsets + ( | ||
(_("Object permissions"), {"fields": ("object_permissions",)}), | ||
) | ||
raw_id_fields = ("object_permissions",) | ||
|
||
|
||
@admin.register(ObjectPermission) | ||
class ObjectPermissionAdmin(admin.ModelAdmin): | ||
list_display = ("object_type", "mode") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
from django.utils.translation import ugettext_lazy as _ | ||
|
||
from djchoices import ChoiceItem, DjangoChoices | ||
|
||
|
||
class PermissionModes(DjangoChoices): | ||
read_only = ChoiceItem("read_only", _("Read-only")) | ||
read_and_write = ChoiceItem("read_and_write", _("Read and write")) |
57 changes: 57 additions & 0 deletions
57
src/objects/accounts/migrations/0002_auto_20201012_1522.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Generated by Django 2.2.12 on 2020-10-12 13:22 | ||
|
||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
dependencies = [ | ||
("accounts", "0001_initial"), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name="ObjectPermission", | ||
fields=[ | ||
( | ||
"id", | ||
models.AutoField( | ||
auto_created=True, | ||
primary_key=True, | ||
serialize=False, | ||
verbose_name="ID", | ||
), | ||
), | ||
( | ||
"object_type", | ||
models.URLField( | ||
help_text="Url reference to OBJECTTYPE in Objecttypes API", | ||
verbose_name="object type", | ||
), | ||
), | ||
( | ||
"mode", | ||
models.CharField( | ||
choices=[ | ||
("read_only", "Read-only"), | ||
("read_and_write", "Read and write"), | ||
], | ||
help_text="Permission mode", | ||
max_length=20, | ||
verbose_name="mode", | ||
), | ||
), | ||
], | ||
options={ | ||
"verbose_name": "object permission", | ||
"verbose_name_plural": "object permissions", | ||
}, | ||
), | ||
migrations.AddField( | ||
model_name="user", | ||
name="object_permissions", | ||
field=models.ManyToManyField( | ||
blank=True, related_name="users", to="accounts.ObjectPermission" | ||
), | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
from rest_framework.permissions import SAFE_METHODS, BasePermission | ||
from vng_api_common.permissions import bypass_permissions | ||
|
||
from objects.accounts.constants import PermissionModes | ||
|
||
|
||
class ObjectBasedPermission(BasePermission): | ||
def has_permission(self, request, view): | ||
if bypass_permissions(request): | ||
return True | ||
|
||
# user should be authenticated | ||
if not (request.user and request.user.is_authenticated): | ||
return False | ||
|
||
# detail actions are processed in has_object_permission method | ||
if view.action != "create": | ||
return True | ||
|
||
object_type = request.data["type"] | ||
object_permission = request.user.get_permission_for_object_type(object_type) | ||
return bool( | ||
object_permission | ||
and object_permission.mode == PermissionModes.read_and_write | ||
) | ||
|
||
def has_object_permission(self, request, view, obj): | ||
if bypass_permissions(request): | ||
return True | ||
|
||
object_permission = request.user.get_permission_for_object_type(obj.object_type) | ||
if not object_permission: | ||
return False | ||
|
||
if request.method in SAFE_METHODS: | ||
return True | ||
|
||
return bool(object_permission.mode == PermissionModes.read_and_write) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
import factory | ||
import factory.fuzzy | ||
|
||
from ..constants import PermissionModes | ||
|
||
|
||
class UserFactory(factory.django.DjangoModelFactory): | ||
username = factory.Sequence(lambda n: f"user-{n}") | ||
|
||
class Meta: | ||
model = "accounts.User" | ||
|
||
|
||
class ObjectPermissionFactory(factory.django.DjangoModelFactory): | ||
object_type = factory.Faker("url") | ||
mode = factory.fuzzy.FuzzyChoice(choices=PermissionModes.values) | ||
|
||
class Meta: | ||
model = "accounts.ObjectPermission" | ||
|
||
@factory.post_generation | ||
def users(self, create, extracted, **kwargs): | ||
# optional M2M, do nothing when no arguments are passed | ||
if not create: | ||
return | ||
|
||
if extracted: | ||
for user in extracted: | ||
self.users.add(user) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
from django.db import models | ||
|
||
|
||
class ObjectQuerySet(models.QuerySet): | ||
def filter_for_user(self, user): | ||
allowed_object_types = user.object_permissions.values("object_type") | ||
return self.filter(object_type__in=models.Subquery(allowed_object_types)) |
Oops, something went wrong.