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
@ -70,86 +70,7 @@ class AttachmentMixin:
|
||||
attachment = serializer.save()
|
||||
attachment.user = self.request.user
|
||||
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):
|
||||
"""
|
||||
|
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': (
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
'rest_framework.permissions.DjangoModelPermissions',
|
||||
'InvenTree.permissions.RolePermission',
|
||||
),
|
||||
'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.helpers import str2bool, isNull
|
||||
from InvenTree.api import AttachmentMixin, RolePermission
|
||||
from InvenTree.api import AttachmentMixin
|
||||
|
||||
from InvenTree.status_codes import BuildStatus
|
||||
|
||||
@ -108,10 +108,6 @@ class CategoryList(generics.ListCreateAPIView):
|
||||
|
||||
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