Skip to content

Commit 21cd937

Browse files
authored
Merge branch 'master' into fix_api_nullables
2 parents cdb14d0 + f01d56e commit 21cd937

File tree

23 files changed

+171
-59
lines changed

23 files changed

+171
-59
lines changed

.github/workflows/qc_checks.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ jobs:
392392

393393
performance:
394394
name: Tests - Performance
395-
runs-on: codspeed-macro
395+
runs-on: ubuntu-24.04 # codspeed-macro
396396

397397
needs: ["pre-commit", "paths-filter"]
398398
if: needs.paths-filter.outputs.server == 'true' || needs.paths-filter.outputs.force == 'true'

.pre-commit-config.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ repos:
1818
exclude: mkdocs.yml
1919
- id: mixed-line-ending
2020
- repo: https://github.com/astral-sh/ruff-pre-commit
21-
rev: v0.14.8
21+
rev: v0.14.10
2222
hooks:
2323
- id: ruff-format
2424
args: [--preview]
@@ -29,7 +29,7 @@ repos:
2929
--preview
3030
]
3131
- repo: https://github.com/astral-sh/uv-pre-commit
32-
rev: 0.9.16
32+
rev: 0.9.22
3333
hooks:
3434
- id: pip-compile
3535
name: pip-compile requirements-dev.in
@@ -71,7 +71,7 @@ repos:
7171
src/frontend/vite.config.ts |
7272
)$
7373
- repo: https://github.com/biomejs/pre-commit
74-
rev: v2.3.8
74+
rev: v2.3.10
7575
hooks:
7676
- id: biome-check
7777
additional_dependencies: ["@biomejs/biome@1.9.4"]

src/backend/InvenTree/InvenTree/api.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
1818
from rest_framework import serializers
1919
from rest_framework.generics import GenericAPIView
20+
from rest_framework.request import clone_request
2021
from rest_framework.response import Response
2122
from rest_framework.serializers import ValidationError
2223
from rest_framework.views import APIView
@@ -31,7 +32,7 @@
3132
from InvenTree.sso import sso_registration_enabled
3233
from plugin.serializers import MetadataSerializer
3334
from users.models import ApiToken
34-
from users.permissions import check_user_permission
35+
from users.permissions import check_user_permission, prefetch_rule_sets
3536

3637
from .helpers import plugins_info
3738
from .helpers_email import is_email_configured
@@ -767,6 +768,13 @@ def post(self, request, *args, **kwargs):
767768

768769
search_filters = self.get_result_filters()
769770

771+
# Create a clone of the request object to modify
772+
# Use GET method for the individual list views
773+
cloned_request = clone_request(request, 'GET')
774+
775+
# Fetch and cache all groups associated with the current user
776+
groups = prefetch_rule_sets(request.user)
777+
770778
for key, cls in self.get_result_types().items():
771779
# Only return results which are specifically requested
772780
if key in data:
@@ -790,22 +798,23 @@ def post(self, request, *args, **kwargs):
790798
view = cls()
791799

792800
# Override regular query params with specific ones for this search request
793-
request._request.GET = params
794-
view.request = request
801+
cloned_request._request.GET = params
802+
view.request = cloned_request
795803
view.format_kwarg = 'format'
796804

797805
# Check permissions and update results dict with particular query
798806
model = view.serializer_class.Meta.model
799807

808+
if not check_user_permission(
809+
request.user, model, 'view', groups=groups
810+
):
811+
results[key] = {
812+
'error': _('User does not have permission to view this model')
813+
}
814+
continue
815+
800816
try:
801-
if check_user_permission(request.user, model, 'view'):
802-
results[key] = view.list(request, *args, **kwargs).data
803-
else:
804-
results[key] = {
805-
'error': _(
806-
'User does not have permission to view this model'
807-
)
808-
}
817+
results[key] = view.list(request, *args, **kwargs).data
809818
except Exception as exc:
810819
results[key] = {'error': str(exc)}
811820

src/backend/InvenTree/InvenTree/helpers_email.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,8 @@ def get_email_for_user(user) -> Optional[str]:
122122
# Otherwise, find first matching email
123123
# Priority is given to primary or verified email addresses
124124
if (
125-
email := EmailAddress.objects.filter(user=user)
125+
email := EmailAddress.objects
126+
.filter(user=user)
126127
.order_by('-primary', '-verified')
127128
.first()
128129
):

src/backend/InvenTree/InvenTree/management/commands/schema.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ def handle(self, *args, **kwargs):
7171
for p_name, p_spec in spec['paths'].items():
7272
# strip path name
7373
p_name = (
74-
p_name.removeprefix(dja_path_prefix)
74+
p_name
75+
.removeprefix(dja_path_prefix)
7576
.removeprefix('/_allauth/browser/v1/')
7677
.removeprefix('/_allauth/app/v1/')
7778
)

src/backend/InvenTree/InvenTree/models.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,8 @@ def get_parameter(self, name: str):
610610
def get_parameters(self) -> QuerySet:
611611
"""Return all Parameter instances for this model."""
612612
return (
613-
self.parameters_list.all()
613+
self.parameters_list
614+
.all()
614615
.prefetch_related('template', 'model_type')
615616
.order_by('template__name')
616617
)
@@ -752,7 +753,8 @@ def delete(self, *args, **kwargs):
752753
for child in self.get_children():
753754
# Store a flattened list of node IDs for each of the lower trees
754755
nodes = list(
755-
child.get_descendants(include_self=True)
756+
child
757+
.get_descendants(include_self=True)
756758
.values_list('pk', flat=True)
757759
.distinct()
758760
)

src/backend/InvenTree/InvenTree/serializers.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from rest_framework.exceptions import ValidationError
2222
from rest_framework.fields import empty
2323
from rest_framework.mixins import ListModelMixin
24+
from rest_framework.permissions import SAFE_METHODS
2425
from rest_framework.serializers import DecimalField
2526
from rest_framework.utils import model_meta
2627
from taggit.serializers import TaggitSerializer, TagListSerializerField
@@ -229,7 +230,7 @@ def do_filtering(self) -> None:
229230
# Skip filtering for a write requests - all fields should be present for data creation
230231
if request := self.context.get('request', None):
231232
if method := getattr(request, 'method', None):
232-
if str(method).lower() in ['post', 'put', 'patch'] and not is_exporting:
233+
if method not in SAFE_METHODS and not is_exporting:
233234
return
234235

235236
# Throw out fields which are not requested (either by default or explicitly)

src/backend/InvenTree/common/notifications.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,9 @@ def trigger_notification(obj: Model, category: str = '', obj_ref: str = 'pk', **
177177
# Filter out any users who are inactive, or do not have the required model permissions
178178
valid_users = list(
179179
filter(
180-
lambda u: u
181-
and u.is_active
182-
and (not obj or check_user_permission(u, obj, 'view')),
180+
lambda u: (
181+
u and u.is_active and (not obj or check_user_permission(u, obj, 'view'))
182+
),
183183
list(target_users),
184184
)
185185
)

src/backend/InvenTree/company/serializers.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,7 @@ class Meta:
268268
source='part', many=False, read_only=True, allow_null=True
269269
),
270270
True,
271-
prefetch_fields=[
272-
Prefetch(
273-
'part', queryset=part.models.Part.objects.select_related('pricing_data')
274-
)
275-
],
271+
prefetch_fields=['part', 'part__pricing_data', 'part__category'],
276272
)
277273

278274
pretty_name = enable_filter(
@@ -438,7 +434,7 @@ def __init__(self, *args, **kwargs):
438434
label=_('Part'), source='part', many=False, read_only=True, allow_null=True
439435
),
440436
False,
441-
prefetch_fields=['part'],
437+
prefetch_fields=['part', 'part__pricing_data'],
442438
)
443439

444440
supplier_detail = enable_filter(

src/backend/InvenTree/company/test_api.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,14 @@
22

33
from django.urls import reverse
44

5-
from company.models import Address, Company, Contact, SupplierPart, SupplierPriceBreak
5+
from company.models import (
6+
Address,
7+
Company,
8+
Contact,
9+
ManufacturerPart,
10+
SupplierPart,
11+
SupplierPriceBreak,
12+
)
613
from InvenTree.unit_test import InvenTreeAPITestCase
714
from part.models import Part
815
from users.permissions import check_user_permission
@@ -498,7 +505,9 @@ def test_manufacturer_part_list(self):
498505

499506
def test_manufacturer_part_detail(self):
500507
"""Tests for the ManufacturerPart detail endpoint."""
501-
url = reverse('api-manufacturer-part-detail', kwargs={'pk': 1})
508+
mp = ManufacturerPart.objects.first()
509+
510+
url = reverse('api-manufacturer-part-detail', kwargs={'pk': mp.pk})
502511

503512
response = self.get(url)
504513
self.assertEqual(response.data['MPN'], 'MPN123')

0 commit comments

Comments
 (0)