diff --git a/src/backend/InvenTree/plugin/base/barcodes/api.py b/src/backend/InvenTree/plugin/base/barcodes/api.py index 9e32fd3113..781ec19548 100644 --- a/src/backend/InvenTree/plugin/base/barcodes/api.py +++ b/src/backend/InvenTree/plugin/base/barcodes/api.py @@ -848,6 +848,16 @@ class BarcodeScanResultMixin: """Return the queryset for the BarcodeScan API.""" queryset = super().get_queryset() + try: + user = self.request.user + except AttributeError: + raise PermissionDenied('User information is not available') + + # Allow staff users access to all BarcodeScanResult objects + if not user.is_staff: + # All other users are limited to viewing their own barcode scan history + queryset = queryset.filter(user=user) + # Pre-fetch user data queryset = queryset.prefetch_related('user') diff --git a/src/backend/InvenTree/plugin/base/barcodes/test_barcode.py b/src/backend/InvenTree/plugin/base/barcodes/test_barcode.py index 71ab47135a..ef2e69d97d 100644 --- a/src/backend/InvenTree/plugin/base/barcodes/test_barcode.py +++ b/src/backend/InvenTree/plugin/base/barcodes/test_barcode.py @@ -256,6 +256,89 @@ class BarcodeAPITest(InvenTreeAPITestCase): self.assertIn('object does not exist', str(response.data[k])) +class BarcodeScanResultAPITest(InvenTreeAPITestCase): + """Tests for the BarcodeScanResult list / detail API endpoints.""" + + def setUp(self): + """Create barcode scan results for two different users.""" + super().setUp() + + from django.contrib.auth import get_user_model + + self.other_user = get_user_model().objects.create_user( + username='otheruser', password='otherpassword', email='other@testing.com' + ) + + self.own_result = BarcodeScanResult.objects.create( + data='own-barcode', user=self.user + ) + self.other_result = BarcodeScanResult.objects.create( + data='other-barcode', user=self.other_user + ) + + def test_list_non_staff(self): + """A non-staff user can only see their own barcode scan history.""" + self.user.is_staff = False + self.user.save() + + response = self.get(reverse('api-barcode-scan-result-list'), expected_code=200) + + pks = [item['pk'] for item in response.data] + + self.assertIn(self.own_result.pk, pks) + self.assertNotIn(self.other_result.pk, pks) + + def test_list_staff(self): + """A staff user can see barcode scan history for all users.""" + self.user.is_staff = True + self.user.save() + + response = self.get(reverse('api-barcode-scan-result-list'), expected_code=200) + + pks = [item['pk'] for item in response.data] + + self.assertIn(self.own_result.pk, pks) + self.assertIn(self.other_result.pk, pks) + + def test_detail_non_staff(self): + """A non-staff user cannot retrieve another user's barcode scan result.""" + self.user.is_staff = False + self.user.save() + + self.get( + reverse( + 'api-barcode-scan-result-detail', kwargs={'pk': self.own_result.pk} + ), + expected_code=200, + ) + + self.get( + reverse( + 'api-barcode-scan-result-detail', kwargs={'pk': self.other_result.pk} + ), + expected_code=404, + ) + + def test_detail_staff(self): + """A staff user can retrieve any user's barcode scan result.""" + self.user.is_staff = True + self.user.save() + + self.get( + reverse( + 'api-barcode-scan-result-detail', kwargs={'pk': self.own_result.pk} + ), + expected_code=200, + ) + + self.get( + reverse( + 'api-barcode-scan-result-detail', kwargs={'pk': self.other_result.pk} + ), + expected_code=200, + ) + + class POAllocateTest(InvenTreeAPITestCase): """Unit tests for the barcode endpoint for allocating items to a purchase order."""