diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 22c65f2417..c7a133c517 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 76 +INVENTREE_API_VERSION = 77 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v77 -> 2022-10-12 : https://github.com/inventree/InvenTree/pull/3772 + - Adds model permission checks for barcode assignment actions + v76 -> 2022-09-10 : https://github.com/inventree/InvenTree/pull/3640 - Refactor of barcode data on the API - StockItem.uid renamed to StockItem.barcode_hash diff --git a/InvenTree/plugin/base/barcodes/api.py b/InvenTree/plugin/base/barcodes/api.py index 21a35a754a..15aeaa62fe 100644 --- a/InvenTree/plugin/base/barcodes/api.py +++ b/InvenTree/plugin/base/barcodes/api.py @@ -5,7 +5,7 @@ from django.urls import path, re_path from django.utils.translation import gettext_lazy as _ from rest_framework import permissions -from rest_framework.exceptions import ValidationError +from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework.response import Response from rest_framework.views import APIView @@ -13,6 +13,7 @@ from InvenTree.helpers import hash_barcode from plugin import registry from plugin.builtin.barcodes.inventree_barcode import ( InvenTreeExternalBarcodePlugin, InvenTreeInternalBarcodePlugin) +from users.models import RuleSet class BarcodeScan(APIView): @@ -139,6 +140,17 @@ class BarcodeAssign(APIView): try: instance = model.objects.get(pk=data[label]) + # Check that the user has the required permission + app_label = model._meta.app_label + model_name = model._meta.model_name + + table = f"{app_label}_{model_name}" + + if not RuleSet.check_table_permission(request.user, table, "change"): + raise PermissionDenied({ + "error": f"You do not have the required permissions for {table}" + }) + instance.assign_barcode( barcode_data=barcode_data, barcode_hash=barcode_hash, @@ -210,6 +222,17 @@ class BarcodeUnassign(APIView): label: _('No match found for provided value') }) + # Check that the user has the required permission + app_label = model._meta.app_label + model_name = model._meta.model_name + + table = f"{app_label}_{model_name}" + + if not RuleSet.check_table_permission(request.user, table, "change"): + raise PermissionDenied({ + "error": f"You do not have the required permissions for {table}" + }) + # Unassign the barcode data from the model instance instance.unassign_barcode() diff --git a/InvenTree/plugin/base/barcodes/test_barcode.py b/InvenTree/plugin/base/barcodes/test_barcode.py index c847d0f586..d3ca79bf4a 100644 --- a/InvenTree/plugin/base/barcodes/test_barcode.py +++ b/InvenTree/plugin/base/barcodes/test_barcode.py @@ -190,6 +190,8 @@ class BarcodeAPITest(InvenTreeAPITestCase): """Test that a barcode can be associated with a StockItem.""" item = StockItem.objects.get(pk=522) + self.assignRole('stock.change') + self.assertEqual(len(item.barcode_hash), 0) barcode_data = 'A-TEST-BARCODE-STRING' diff --git a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py index 1230794625..6f2439de23 100644 --- a/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/test_inventree_barcode.py @@ -125,6 +125,19 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): self.assertIn('Missing data:', str(response.data)) + # Permission error check + response = self.assign( + { + 'barcode': 'abcdefg', + 'part': 1, + 'stockitem': 1, + }, + expected_code=403 + ) + + self.assignRole('part.change') + self.assignRole('stock.change') + # Provide too many fields response = self.assign( { @@ -188,6 +201,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): barcode = 'xyz-123' + self.assignRole('part.change') + # Test that an initial scan yields no results response = self.scan( { @@ -196,6 +211,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): expected_code=400 ) + self.assignRole('part.change') + # Attempt to assign to an invalid part ID response = self.assign( { @@ -247,6 +264,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): self.assertIn('Barcode matches existing item', str(response.data['error'])) + self.assignRole('part.change') + # Now test that we can unassign the barcode data also response = self.unassign( { @@ -265,6 +284,17 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase): barcode = '555555555555555555555555' + # Assign random barcode data to a StockLocation instance + response = self.assign( + data={ + 'barcode': barcode, + 'stocklocation': 1, + }, + expected_code=403, + ) + + self.assignRole('stock_location.change') + # Assign random barcode data to a StockLocation instance response = self.assign( data={