mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Add RolePermission for API endpoints
This commit is contained in:
parent
1dfda5b0ed
commit
cd8c6fa81a
@ -20,6 +20,8 @@ from rest_framework.views import APIView
|
||||
from .views import AjaxView
|
||||
from .version import inventreeVersion, inventreeInstanceName
|
||||
|
||||
from users.models import check_user_role, RuleSet
|
||||
|
||||
from plugins import plugins as inventree_plugins
|
||||
|
||||
|
||||
@ -70,6 +72,85 @@ class AttachmentMixin:
|
||||
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):
|
||||
"""
|
||||
Endpoint for running custom action plugins.
|
||||
|
@ -29,7 +29,8 @@ from . import serializers as part_serializers
|
||||
|
||||
from InvenTree.views import TreeSerializer
|
||||
from InvenTree.helpers import str2bool, isNull
|
||||
from InvenTree.api import AttachmentMixin
|
||||
from InvenTree.api import AttachmentMixin, RolePermission
|
||||
|
||||
from InvenTree.status_codes import BuildStatus
|
||||
|
||||
|
||||
@ -105,6 +106,12 @@ class CategoryList(generics.ListCreateAPIView):
|
||||
'description',
|
||||
]
|
||||
|
||||
role_required = 'part'
|
||||
|
||||
permission_classes = [
|
||||
RolePermission,
|
||||
]
|
||||
|
||||
|
||||
class CategoryDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
""" API endpoint for detail view of a single PartCategory object """
|
||||
|
Loading…
Reference in New Issue
Block a user