mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-03 22:55:43 +00:00 
			
		
		
		
	Check user permissions before linking or un-linking barcodes (#3772)
* Check user permissions before linking or un-linking barcodse * Bump API version * Permission fixes for unit tests * Fix permission issues * Unit test fixes
This commit is contained in:
		@@ -2,11 +2,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# InvenTree API version
 | 
					# 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
 | 
					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
 | 
					v76 -> 2022-09-10 : https://github.com/inventree/InvenTree/pull/3640
 | 
				
			||||||
    - Refactor of barcode data on the API
 | 
					    - Refactor of barcode data on the API
 | 
				
			||||||
    - StockItem.uid renamed to StockItem.barcode_hash
 | 
					    - StockItem.uid renamed to StockItem.barcode_hash
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,7 +5,7 @@ from django.urls import path, re_path
 | 
				
			|||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from rest_framework import permissions
 | 
					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.response import Response
 | 
				
			||||||
from rest_framework.views import APIView
 | 
					from rest_framework.views import APIView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -13,6 +13,7 @@ from InvenTree.helpers import hash_barcode
 | 
				
			|||||||
from plugin import registry
 | 
					from plugin import registry
 | 
				
			||||||
from plugin.builtin.barcodes.inventree_barcode import (
 | 
					from plugin.builtin.barcodes.inventree_barcode import (
 | 
				
			||||||
    InvenTreeExternalBarcodePlugin, InvenTreeInternalBarcodePlugin)
 | 
					    InvenTreeExternalBarcodePlugin, InvenTreeInternalBarcodePlugin)
 | 
				
			||||||
 | 
					from users.models import RuleSet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BarcodeScan(APIView):
 | 
					class BarcodeScan(APIView):
 | 
				
			||||||
@@ -139,6 +140,17 @@ class BarcodeAssign(APIView):
 | 
				
			|||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    instance = model.objects.get(pk=data[label])
 | 
					                    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(
 | 
					                    instance.assign_barcode(
 | 
				
			||||||
                        barcode_data=barcode_data,
 | 
					                        barcode_data=barcode_data,
 | 
				
			||||||
                        barcode_hash=barcode_hash,
 | 
					                        barcode_hash=barcode_hash,
 | 
				
			||||||
@@ -210,6 +222,17 @@ class BarcodeUnassign(APIView):
 | 
				
			|||||||
                        label: _('No match found for provided value')
 | 
					                        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
 | 
					                # Unassign the barcode data from the model instance
 | 
				
			||||||
                instance.unassign_barcode()
 | 
					                instance.unassign_barcode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -190,6 +190,8 @@ class BarcodeAPITest(InvenTreeAPITestCase):
 | 
				
			|||||||
        """Test that a barcode can be associated with a StockItem."""
 | 
					        """Test that a barcode can be associated with a StockItem."""
 | 
				
			||||||
        item = StockItem.objects.get(pk=522)
 | 
					        item = StockItem.objects.get(pk=522)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assignRole('stock.change')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.assertEqual(len(item.barcode_hash), 0)
 | 
					        self.assertEqual(len(item.barcode_hash), 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        barcode_data = 'A-TEST-BARCODE-STRING'
 | 
					        barcode_data = 'A-TEST-BARCODE-STRING'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -125,6 +125,19 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.assertIn('Missing data:', str(response.data))
 | 
					        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
 | 
					        # Provide too many fields
 | 
				
			||||||
        response = self.assign(
 | 
					        response = self.assign(
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -188,6 +201,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        barcode = 'xyz-123'
 | 
					        barcode = 'xyz-123'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assignRole('part.change')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Test that an initial scan yields no results
 | 
					        # Test that an initial scan yields no results
 | 
				
			||||||
        response = self.scan(
 | 
					        response = self.scan(
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -196,6 +211,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
 | 
				
			|||||||
            expected_code=400
 | 
					            expected_code=400
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assignRole('part.change')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Attempt to assign to an invalid part ID
 | 
					        # Attempt to assign to an invalid part ID
 | 
				
			||||||
        response = self.assign(
 | 
					        response = self.assign(
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -247,6 +264,8 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        self.assertIn('Barcode matches existing item', str(response.data['error']))
 | 
					        self.assertIn('Barcode matches existing item', str(response.data['error']))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.assignRole('part.change')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Now test that we can unassign the barcode data also
 | 
					        # Now test that we can unassign the barcode data also
 | 
				
			||||||
        response = self.unassign(
 | 
					        response = self.unassign(
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
@@ -265,6 +284,17 @@ class TestInvenTreeBarcode(InvenTreeAPITestCase):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        barcode = '555555555555555555555555'
 | 
					        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
 | 
					        # Assign random barcode data to a StockLocation instance
 | 
				
			||||||
        response = self.assign(
 | 
					        response = self.assign(
 | 
				
			||||||
            data={
 | 
					            data={
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user