From eaa5913c8cf05d05b9fc95ca4215952ddc473a8e Mon Sep 17 00:00:00 2001 From: Oliver Date: Wed, 23 Jun 2021 20:30:26 +1000 Subject: [PATCH] Adds custom DRF metadata handler - Limit available "actions" data to only what the user is allowed to do --- InvenTree/InvenTree/metadata.py | 67 +++++++++++++++++++++++++++++++++ InvenTree/InvenTree/settings.py | 1 + InvenTree/templates/js/forms.js | 8 ++-- 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 InvenTree/InvenTree/metadata.py diff --git a/InvenTree/InvenTree/metadata.py b/InvenTree/InvenTree/metadata.py new file mode 100644 index 0000000000..b9d0732acf --- /dev/null +++ b/InvenTree/InvenTree/metadata.py @@ -0,0 +1,67 @@ + +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from rest_framework.metadata import SimpleMetadata + +import users.models + + +class InvenTreeMetadata(SimpleMetadata): + """ + Custom metadata class for the DRF API. + + This custom metadata class imits the available "actions", + based on the user's role permissions. + + Thus when a client send an OPTIONS request to an API endpoint, + it will only receive a list of actions which it is allowed to perform! + + """ + + def determine_metadata(self, request, view): + + metadata = super().determine_metadata(request, view) + + user = request.user + + if user is None: + # No actions for you! + metadata['actions'] = {} + return metadata + + try: + # Extract the model name associated with the view + model = view.serializer_class.Meta.model + + # Construct the 'table name' from the model + app_label = model._meta.app_label + tbl_label = model._meta.model_name + + table = f"{app_label}_{tbl_label}" + + actions = metadata['actions'] + + check = users.models.RuleSet.check_table_permission + + # Map the request method to a permission type + rolemap = { + 'GET': 'view', + 'OPTIONS': 'view', + 'POST': 'add', + 'PUT': 'change', + 'PATCH': 'change', + 'DELETE': 'delete', + } + + # Remove any HTTP methods that the user does not have permission for + for method, permission in rolemap.items(): + if method in actions and not check(user, table, permission): + del actions[method] + + except AttributeError: + # We will assume that if the serializer class does *not* have a Meta + # then we don't need a permission + pass + + return metadata diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index fceaf9a58f..be13411fd8 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -341,6 +341,7 @@ REST_FRAMEWORK = { 'InvenTree.permissions.RolePermission', ), 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', + 'DEFAULT_METADATA_CLASS': 'InvenTree.metadata.InvenTreeMetadata' } WSGI_APPLICATION = 'InvenTree.wsgi.application' diff --git a/InvenTree/templates/js/forms.js b/InvenTree/templates/js/forms.js index fa2ca9eb2e..822688d9ad 100644 --- a/InvenTree/templates/js/forms.js +++ b/InvenTree/templates/js/forms.js @@ -23,7 +23,8 @@ */ function getApiEndpointOptions(url, options={}) { - $.ajax({ + // Return the ajax request object + return $.ajax({ url: url, type: 'OPTIONS', contentType: 'application/json', @@ -31,8 +32,7 @@ function getApiEndpointOptions(url, options={}) { accepts: { json: 'application/json', }, - success: function(response) { - console.log(response); - } }); } + +