Added owner permission to check user has the right to read/update object
This commit is contained in:
parent
3e277aad4f
commit
367014f70e
|
@ -1,4 +1,7 @@
|
||||||
|
import operator
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.http import Http404
|
||||||
|
|
||||||
from rest_framework.permissions import BasePermission, DjangoModelPermissions
|
from rest_framework.permissions import BasePermission, DjangoModelPermissions
|
||||||
|
|
||||||
|
@ -20,3 +23,39 @@ class HasModelPermission(DjangoModelPermissions):
|
||||||
"""
|
"""
|
||||||
def get_required_permissions(self, method, model_cls):
|
def get_required_permissions(self, method, model_cls):
|
||||||
return super().get_required_permissions(method, self.model)
|
return super().get_required_permissions(method, self.model)
|
||||||
|
|
||||||
|
|
||||||
|
class OwnerPermission(BasePermission):
|
||||||
|
"""
|
||||||
|
Ensure the request user is the owner of the object.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
class MyView(APIView):
|
||||||
|
model = MyModel
|
||||||
|
permission_classes = [OwnerPermission]
|
||||||
|
owner_field = 'owner'
|
||||||
|
owner_checks = ['read', 'write']
|
||||||
|
"""
|
||||||
|
perms_map = {
|
||||||
|
'GET': 'read',
|
||||||
|
'OPTIONS': 'read',
|
||||||
|
'HEAD': 'read',
|
||||||
|
'POST': 'write',
|
||||||
|
'PUT': 'write',
|
||||||
|
'PATCH': 'write',
|
||||||
|
'DELETE': 'write',
|
||||||
|
}
|
||||||
|
|
||||||
|
def has_object_permission(self, request, view, obj):
|
||||||
|
method_check = self.perms_map[request.method]
|
||||||
|
owner_checks = getattr(view, 'owner_checks', ['read', 'write'])
|
||||||
|
if method_check not in owner_checks:
|
||||||
|
# check not enabled
|
||||||
|
return True
|
||||||
|
|
||||||
|
owner_field = getattr(view, 'owner_field', 'user')
|
||||||
|
owner = operator.attrgetter(owner_field)(obj)
|
||||||
|
if owner != request.user:
|
||||||
|
raise Http404
|
||||||
|
return True
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from rest_framework.views import APIView
|
||||||
|
|
||||||
|
from django.contrib.auth.models import AnonymousUser
|
||||||
|
from django.http import Http404
|
||||||
|
|
||||||
|
from funkwhale_api.common import permissions
|
||||||
|
|
||||||
|
|
||||||
|
def test_owner_permission_owner_field_ok(nodb_factories, api_request):
|
||||||
|
playlist = nodb_factories['playlists.Playlist']()
|
||||||
|
view = APIView.as_view()
|
||||||
|
permission = permissions.OwnerPermission()
|
||||||
|
request = api_request.get('/')
|
||||||
|
setattr(request, 'user', playlist.user)
|
||||||
|
check = permission.has_object_permission(request, view, playlist)
|
||||||
|
|
||||||
|
assert check is True
|
||||||
|
|
||||||
|
|
||||||
|
def test_owner_permission_owner_field_not_ok(nodb_factories, api_request):
|
||||||
|
playlist = nodb_factories['playlists.Playlist']()
|
||||||
|
view = APIView.as_view()
|
||||||
|
permission = permissions.OwnerPermission()
|
||||||
|
request = api_request.get('/')
|
||||||
|
setattr(request, 'user', AnonymousUser())
|
||||||
|
|
||||||
|
with pytest.raises(Http404):
|
||||||
|
permission.has_object_permission(request, view, playlist)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def test_owner_permission_read_only(nodb_factories, api_request):
|
||||||
|
playlist = nodb_factories['playlists.Playlist']()
|
||||||
|
view = APIView.as_view()
|
||||||
|
setattr(view, 'owner_checks', ['write'])
|
||||||
|
permission = permissions.OwnerPermission()
|
||||||
|
request = api_request.get('/')
|
||||||
|
setattr(request, 'user', AnonymousUser())
|
||||||
|
check = permission.has_object_permission(request, view, playlist)
|
||||||
|
|
||||||
|
assert check is True
|
Loading…
Reference in New Issue