RolePermission is now default for API endpoints

This commit is contained in:
Oliver Walters 2021-02-26 14:05:26 +11:00
parent cd8c6fa81a
commit 36359fc547
4 changed files with 88 additions and 84 deletions

View File

@ -72,85 +72,6 @@ class AttachmentMixin:
attachment.save() attachment.save()
class RolePermission(permissions.BasePermission):
"""
Role mixin for API endpoints, allowing us to specify the user "role"
which is required for certain operations.
Each endpoint can have one or more of the following actions:
- GET
- POST
- PUT
- PATCH
- DELETE
Specify the required "role" using the role_required attribute.
e.g.
role_required = "part"
The RoleMixin class will then determine if the user has the required permission
to perform the specified action.
For example, a DELETE action will be rejected unless the user has the "part.remove" permission
"""
def has_permission(self, request, view):
"""
Determine if the current user has the specified permissions
"""
# First, check that the user is authenticated!
auth = permissions.IsAuthenticated()
if not auth.has_permission(request, view):
return False
user = request.user
# Superuser can do it all
if False and user.is_superuser:
return True
# Map the request method to a permission type
rolemap = {
'GET': 'view',
'OPTIONS': 'view',
'POST': 'add',
'PUT': 'change',
'PATCH': 'change',
'DELETE': 'delete',
}
permission = rolemap[request.method]
role = getattr(view, 'role_required', None)
if not role:
raise AttributeError(f"'role_required' not specified for view {type(view).__name__}")
roles = []
if type(role) is str:
roles = [role]
elif type(role) in [list, tuple]:
roles = role
else:
raise TypeError(f"'role_required' is of incorrect type ({type(role)}) for view {type(view).__name__}")
for role in roles:
if role not in RuleSet.RULESET_NAMES:
raise ValueError(f"Role '{role}' is not a valid role")
if not check_user_role(user, role, permission):
return False
# All checks passed
return True
class ActionPluginView(APIView): class ActionPluginView(APIView):
""" """
Endpoint for running custom action plugins. Endpoint for running custom action plugins.

View File

@ -0,0 +1,86 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from rest_framework import permissions
import users.models
class RolePermission(permissions.BasePermission):
"""
Role mixin for API endpoints, allowing us to specify the user "role"
which is required for certain operations.
Each endpoint can have one or more of the following actions:
- GET
- POST
- PUT
- PATCH
- DELETE
Specify the required "role" using the role_required attribute.
e.g.
role_required = "part"
The RoleMixin class will then determine if the user has the required permission
to perform the specified action.
For example, a DELETE action will be rejected unless the user has the "part.remove" permission
"""
def has_permission(self, request, view):
"""
Determine if the current user has the specified permissions
"""
# First, check that the user is authenticated!
auth = permissions.IsAuthenticated()
if not auth.has_permission(request, view):
return False
user = request.user
# Superuser can do it all
if False and user.is_superuser:
return True
# Map the request method to a permission type
rolemap = {
'GET': 'view',
'OPTIONS': 'view',
'POST': 'add',
'PUT': 'change',
'PATCH': 'change',
'DELETE': 'delete',
}
permission = rolemap[request.method]
role = getattr(view, 'role_required', None)
if not role:
raise AttributeError(f"'role_required' not specified for view {type(view).__name__}")
roles = []
if type(role) is str:
roles = [role]
elif type(role) in [list, tuple]:
roles = role
else:
raise TypeError(f"'role_required' is of incorrect type ({type(role)}) for view {type(view).__name__}")
for role in roles:
if role not in users.models.RuleSet.RULESET_NAMES:
raise ValueError(f"Role '{role}' is not a valid role")
if not users.models.check_user_role(user, role, permission):
return False
# All checks passed
return True

View File

@ -278,6 +278,7 @@ REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ( 'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated', 'rest_framework.permissions.IsAuthenticated',
'rest_framework.permissions.DjangoModelPermissions', 'rest_framework.permissions.DjangoModelPermissions',
'InvenTree.permissions.RolePermission',
), ),
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema'
} }

View File

@ -29,7 +29,7 @@ from . import serializers as part_serializers
from InvenTree.views import TreeSerializer from InvenTree.views import TreeSerializer
from InvenTree.helpers import str2bool, isNull from InvenTree.helpers import str2bool, isNull
from InvenTree.api import AttachmentMixin, RolePermission from InvenTree.api import AttachmentMixin
from InvenTree.status_codes import BuildStatus from InvenTree.status_codes import BuildStatus
@ -108,10 +108,6 @@ class CategoryList(generics.ListCreateAPIView):
role_required = 'part' role_required = 'part'
permission_classes = [
RolePermission,
]
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView): class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
""" API endpoint for detail view of a single PartCategory object """ """ API endpoint for detail view of a single PartCategory object """