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" VERSION = "0.0.1"
AUTHOR = "Michael" AUTHOR = "Michael"
def scan(self, barcode_data): def scan(self, barcode_data, user, **kwargs):
if barcode_data.startswith("PART-"): if barcode_data.startswith("PART-"):
try: try:
pk = int(barcode_data.split("PART-")[1]) pk = int(barcode_data.split("PART-")[1])
instance = Part.objects.get(pk=pk) instance = Part.objects.get(pk=pk)
label = Part.barcode_model_type() label = Part.barcode_model_type()
return {label: instance.format_matched_response()} return {label: instance.format_matched_response(user=user)}
except Part.DoesNotExist: except Part.DoesNotExist:
pass pass
``` ```

View File

@ -8,7 +8,7 @@ from typing import Any, Optional
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType 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 import models, transaction
from django.db.models import QuerySet from django.db.models import QuerySet
from django.db.models.signals import post_save from django.db.models.signals import post_save
@ -33,6 +33,7 @@ import InvenTree.format
import InvenTree.helpers import InvenTree.helpers
import InvenTree.helpers_model import InvenTree.helpers_model
import InvenTree.sentry import InvenTree.sentry
from InvenTree.users.permissions import check_user_permission
logger = structlog.get_logger('inventree') logger = structlog.get_logger('inventree')
@ -1334,8 +1335,14 @@ class InvenTreeBarcodeMixin(models.Model):
return generate_barcode(self) return generate_barcode(self)
def format_matched_response(self): def format_matched_response(self, user, **kwargs):
"""Format a standard response for a matched barcode.""" """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} data = {'pk': self.pk}
if hasattr(self, 'get_api_url'): if hasattr(self, 'get_api_url'):

View File

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

View File

@ -42,7 +42,7 @@ class BarcodeMixin:
"""Does this plugin have everything needed to process a barcode.""" """Does this plugin have everything needed to process a barcode."""
return True return True
def scan(self, barcode_data): def scan(self, barcode_data: str, user, **kwargs) -> dict | None:
"""Scan a barcode against this plugin. """Scan a barcode against this plugin.
This method is explicitly called from the /scan/ API endpoint, 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' '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. """Perform a generic 'scan' operation on a supplier barcode.
The supplier barcode may provide sufficient information to match against The supplier barcode may provide sufficient information to match against
@ -297,7 +297,7 @@ class SupplierBarcodeMixin(BarcodeMixin):
for k, v in matches.items(): for k, v in matches.items():
if v and hasattr(v, 'pk'): if v and hasattr(v, 'pk'):
has_match = True has_match = True
data[k] = v.format_matched_response() data[k] = v.format_matched_response(user=user)
if not has_match: if not has_match:
return None 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.""" """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. """Scan a barcode against this plugin.
Here we are looking for a dict object which contains a reference to a particular InvenTree database object 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: try:
instance = model.objects.get(pk=int(pk)) 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): except (ValueError, model.DoesNotExist):
pass pass
@ -111,7 +112,9 @@ class InvenTreeInternalBarcodePlugin(SettingsMixin, BarcodeMixin, InvenTreePlugi
instance = model.objects.get(pk=pk) instance = model.objects.get(pk=pk)
return { return {
**self.format_matched_response(label, model, instance), **self.format_matched_response(
label, model, instance, user=user
),
'success': succcess_message, 'success': succcess_message,
} }
except (ValueError, model.DoesNotExist): except (ValueError, model.DoesNotExist):
@ -129,7 +132,7 @@ class InvenTreeInternalBarcodePlugin(SettingsMixin, BarcodeMixin, InvenTreePlugi
if instance is not None: if instance is not None:
return { return {
**self.format_matched_response(label, model, instance), **self.format_matched_response(label, model, instance, user=user),
'success': succcess_message, 'success': succcess_message,
} }