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:
Oliver 2022-10-13 12:14:36 +11:00 committed by GitHub
parent fccbcad63f
commit 99d822ecdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 2 deletions

View File

@ -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

View File

@ -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()

View File

@ -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'

View File

@ -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={