extend barcode scans with user perm check

This commit is contained in:
Matthias Mair 2026-06-23 23:25:30 +02:00
parent 6057aafe65
commit 87e118df42
No known key found for this signature in database
GPG Key ID: A593429DDA23B66A
5 changed files with 28 additions and 16 deletions

View File

@ -54,14 +54,14 @@ class InvenTreeBarcodePlugin(BarcodeMixin, InvenTreePlugin):
VERSION = "0.0.1"
AUTHOR = "Michael"
def scan(self, barcode_data):
def scan(self, barcode_data, user, **kwargs):
if barcode_data.startswith("PART-"):
try:
pk = int(barcode_data.split("PART-")[1])
instance = Part.objects.get(pk=pk)
label = Part.barcode_model_type()
return {label: instance.format_matched_response()}
return {label: instance.format_matched_response(user=user)}
except Part.DoesNotExist:
pass
```

View File

@ -8,7 +8,7 @@ from typing import Any, Optional
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.core.exceptions import PermissionDenied, ValidationError
from django.db import models, transaction
from django.db.models import QuerySet
from django.db.models.signals import post_save
@ -33,6 +33,7 @@ import InvenTree.format
import InvenTree.helpers
import InvenTree.helpers_model
import InvenTree.sentry
from InvenTree.users.permissions import check_user_permission
logger = structlog.get_logger('inventree')
@ -1334,8 +1335,14 @@ class InvenTreeBarcodeMixin(models.Model):
return generate_barcode(self)
def format_matched_response(self):
def format_matched_response(self, user, **kwargs):
"""Format a standard response for a matched barcode."""
# Check permission for this object
if not check_user_permission(user, self, 'view'):
raise PermissionDenied(
_('User does not have permission to view this object')
)
data = {'pk': self.pk}
if hasattr(self, 'get_api_url'):

View File

@ -153,7 +153,7 @@ class BarcodeView(CreateAPIView):
for current_plugin in plugins:
try:
result = current_plugin.scan(barcode)
result = current_plugin.scan(barcode, user=request.user, **kwargs)
except Exception:
log_error('BarcodeView.scan_barcode', plugin=current_plugin.slug)
continue
@ -282,7 +282,7 @@ class BarcodeAssign(BarcodeView):
# First check if the provided barcode matches an existing database entry
if inventree_barcode_plugin:
result = inventree_barcode_plugin.scan(barcode)
result = inventree_barcode_plugin.scan(barcode, user=request.user, **kwargs)
if result is not None:
result['error'] = _('Barcode matches existing item')
@ -459,7 +459,9 @@ class BarcodePOAllocate(BarcodeView):
manufacturer_part=response.get('manufacturerpart', None),
)
response['success'] = _('Matched supplier part')
response['supplierpart'] = supplier_part.format_matched_response()
response['supplierpart'] = supplier_part.format_matched_response(
user=request.user
)
except ValidationError as e:
response['error'] = str(e)

View File

@ -42,7 +42,7 @@ class BarcodeMixin:
"""Does this plugin have everything needed to process a barcode."""
return True
def scan(self, barcode_data):
def scan(self, barcode_data: str, user, **kwargs) -> dict | None:
"""Scan a barcode against this plugin.
This method is explicitly called from the /scan/ API endpoint,
@ -261,7 +261,7 @@ class SupplierBarcodeMixin(BarcodeMixin):
'extract_barcode_fields must be implemented by each plugin'
)
def scan(self, barcode_data: str) -> dict | None:
def scan(self, barcode_data: str, user, **kwargs) -> dict | None:
"""Perform a generic 'scan' operation on a supplier barcode.
The supplier barcode may provide sufficient information to match against
@ -297,7 +297,7 @@ class SupplierBarcodeMixin(BarcodeMixin):
for k, v in matches.items():
if v and hasattr(v, 'pk'):
has_match = True
data[k] = v.format_matched_response()
data[k] = v.format_matched_response(user=user)
if not has_match:
return None

View File

@ -48,11 +48,11 @@ class InvenTreeInternalBarcodePlugin(SettingsMixin, BarcodeMixin, InvenTreePlugi
},
}
def format_matched_response(self, label, model, instance):
def format_matched_response(self, label, model, instance, user, **kwargs):
"""Format a response for the scanned data."""
return {label: instance.format_matched_response()}
return {label: instance.format_matched_response(user=user, **kwargs)}
def scan(self, barcode_data):
def scan(self, barcode_data, user, **kwargs):
"""Scan a barcode against this plugin.
Here we are looking for a dict object which contains a reference to a particular InvenTree database object
@ -79,7 +79,8 @@ class InvenTreeInternalBarcodePlugin(SettingsMixin, BarcodeMixin, InvenTreePlugi
try:
instance = model.objects.get(pk=int(pk))
return self.format_matched_response(label, model, instance)
user = getattr(self, 'user', None)
return self.format_matched_response(label, model, instance, user=user)
except (ValueError, model.DoesNotExist):
pass
@ -111,7 +112,9 @@ class InvenTreeInternalBarcodePlugin(SettingsMixin, BarcodeMixin, InvenTreePlugi
instance = model.objects.get(pk=pk)
return {
**self.format_matched_response(label, model, instance),
**self.format_matched_response(
label, model, instance, user=user
),
'success': succcess_message,
}
except (ValueError, model.DoesNotExist):
@ -129,7 +132,7 @@ class InvenTreeInternalBarcodePlugin(SettingsMixin, BarcodeMixin, InvenTreePlugi
if instance is not None:
return {
**self.format_matched_response(label, model, instance),
**self.format_matched_response(label, model, instance, user=user),
'success': succcess_message,
}