diff --git a/InvenTree/InvenTree/api.py b/InvenTree/InvenTree/api.py index 0180ad22b5..afd4d91de1 100644 --- a/InvenTree/InvenTree/api.py +++ b/InvenTree/InvenTree/api.py @@ -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): """ diff --git a/InvenTree/InvenTree/permissions.py b/InvenTree/InvenTree/permissions.py new file mode 100644 index 0000000000..daa57136b3 --- /dev/null +++ b/InvenTree/InvenTree/permissions.py @@ -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 \ No newline at end of file diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 70760624c6..5dbfb845bc 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -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' } diff --git a/InvenTree/part/api.py b/InvenTree/part/api.py index ded9a64cbb..71e1d63314 100644 --- a/InvenTree/part/api.py +++ b/InvenTree/part/api.py @@ -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 """