mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
RolePermission is now default for API endpoints
This commit is contained in:
parent
cd8c6fa81a
commit
36359fc547
@ -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.
|
||||||
|
86
InvenTree/InvenTree/permissions.py
Normal file
86
InvenTree/InvenTree/permissions.py
Normal 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
|
@ -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'
|
||||||
}
|
}
|
||||||
|
@ -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 """
|
||||||
|
Loading…
Reference in New Issue
Block a user