mirror of
https://github.com/inventree/InvenTree.git
synced 2026-09-09 22:30:17 +00:00
Permissions fix for Calendar views (#12764)
This commit is contained in:
@@ -71,6 +71,7 @@ from order.status_codes import (
|
||||
)
|
||||
from part.models import Part
|
||||
from users.models import Owner
|
||||
from users.permissions import check_user_permission
|
||||
|
||||
order_router = InvenTreeApiRouter()
|
||||
|
||||
@@ -2497,6 +2498,32 @@ class OrderCalendarExport(ICalFeed):
|
||||
timezone = settings.TIME_ZONE
|
||||
file_name = 'calendar.ics'
|
||||
|
||||
# Map the URL 'ordertype' kwarg to the corresponding order model,
|
||||
# so that access can be checked against the matching RuleSet
|
||||
ORDER_MODELS = {
|
||||
'purchase-order': models.PurchaseOrder,
|
||||
'sales-order': models.SalesOrder,
|
||||
'return-order': models.ReturnOrder,
|
||||
'transfer-order': models.TransferOrder,
|
||||
}
|
||||
|
||||
def check_permission(self, request, **kwargs):
|
||||
"""Check that the requesting user has 'view' permission for the requested order type.
|
||||
|
||||
Returns a 403 JsonResponse if the user lacks the required RuleSet permission,
|
||||
or None if access is permitted.
|
||||
"""
|
||||
model = self.ORDER_MODELS.get(kwargs.get('ordertype'))
|
||||
|
||||
if model is not None and not check_user_permission(request.user, model, 'view'):
|
||||
response = JsonResponse({
|
||||
'detail': 'You do not have permission to view this resource.'
|
||||
})
|
||||
response.status_code = 403
|
||||
return response
|
||||
|
||||
return None
|
||||
|
||||
def __call__(self, request, *args, **kwargs):
|
||||
"""Overload call in order to check for authentication.
|
||||
|
||||
@@ -2513,6 +2540,8 @@ class OrderCalendarExport(ICalFeed):
|
||||
|
||||
if request.user.is_authenticated:
|
||||
# Authenticated on first try - maybe normal browser call?
|
||||
if forbidden := self.check_permission(request, **kwargs):
|
||||
return forbidden
|
||||
return super().__call__(request, *args, **kwargs)
|
||||
|
||||
# No login yet - check in headers
|
||||
@@ -2531,6 +2560,8 @@ class OrderCalendarExport(ICalFeed):
|
||||
# Check again
|
||||
if request.user.is_authenticated:
|
||||
# Authenticated after second try
|
||||
if forbidden := self.check_permission(request, **kwargs):
|
||||
return forbidden
|
||||
return super().__call__(request, *args, **kwargs)
|
||||
|
||||
# Still nothing - return Unauth. header with info on how to authenticate
|
||||
|
||||
@@ -921,6 +921,21 @@ class PurchaseOrderTest(OrderTest):
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_po_calendar_no_permission(self):
|
||||
"""Test that an authenticated user without purchase_order view permission is denied."""
|
||||
self.clearRoles()
|
||||
|
||||
response = self.get(
|
||||
reverse('api-po-so-calendar', kwargs={'ordertype': 'purchase-order'}),
|
||||
expected_code=403,
|
||||
format=None,
|
||||
)
|
||||
|
||||
resp_dict = response.json()
|
||||
self.assertEqual(
|
||||
resp_dict['detail'], 'You do not have permission to view this resource.'
|
||||
)
|
||||
|
||||
def test_po_custom_status_query_count(self):
|
||||
"""Test that listing PurchaseOrders with custom statuses does not cause N+1 queries.
|
||||
|
||||
@@ -2291,6 +2306,21 @@ class SalesOrderTest(OrderTest):
|
||||
self.assertGreaterEqual(n_events, 1)
|
||||
self.assertEqual(number_orders_incl_complete, n_events)
|
||||
|
||||
def test_so_calendar_no_permission(self):
|
||||
"""Test that an authenticated user without sales_order view permission is denied."""
|
||||
self.clearRoles()
|
||||
|
||||
response = self.get(
|
||||
reverse('api-po-so-calendar', kwargs={'ordertype': 'sales-order'}),
|
||||
expected_code=403,
|
||||
format=None,
|
||||
)
|
||||
|
||||
resp_dict = response.json()
|
||||
self.assertEqual(
|
||||
resp_dict['detail'], 'You do not have permission to view this resource.'
|
||||
)
|
||||
|
||||
def test_export(self):
|
||||
"""Test we can export the SalesOrder list."""
|
||||
set_global_setting(models.SalesOrder.UNLOCK_SETTING, True)
|
||||
@@ -3793,6 +3823,21 @@ class ReturnOrderTests(InvenTreeAPITestCase):
|
||||
calendar = Calendar.from_ical(response.content)
|
||||
self.assertIsInstance(calendar, Calendar)
|
||||
|
||||
def test_ro_calendar_no_permission(self):
|
||||
"""Test that an authenticated user without return_order view permission is denied."""
|
||||
self.clearRoles()
|
||||
|
||||
response = self.get(
|
||||
reverse('api-po-so-calendar', kwargs={'ordertype': 'return-order'}),
|
||||
expected_code=403,
|
||||
format=None,
|
||||
)
|
||||
|
||||
resp_dict = response.json()
|
||||
self.assertEqual(
|
||||
resp_dict['detail'], 'You do not have permission to view this resource.'
|
||||
)
|
||||
|
||||
def test_export(self):
|
||||
"""Test data export for the ReturnOrder API endpoints."""
|
||||
# Export return orders
|
||||
@@ -4380,6 +4425,21 @@ class TransferOrderTest(OrderTest):
|
||||
self.assertGreaterEqual(n_events, 1)
|
||||
self.assertEqual(number_orders_incl_complete, n_events)
|
||||
|
||||
def test_transfer_order_calendar_no_permission(self):
|
||||
"""Test that an authenticated user without transfer_order view permission is denied."""
|
||||
self.clearRoles()
|
||||
|
||||
response = self.get(
|
||||
reverse('api-po-so-calendar', kwargs={'ordertype': 'transfer-order'}),
|
||||
expected_code=403,
|
||||
format=None,
|
||||
)
|
||||
|
||||
resp_dict = response.json()
|
||||
self.assertEqual(
|
||||
resp_dict['detail'], 'You do not have permission to view this resource.'
|
||||
)
|
||||
|
||||
def test_export(self):
|
||||
"""Test we can export the TransferOrder list."""
|
||||
n = models.TransferOrder.objects.count()
|
||||
|
||||
Reference in New Issue
Block a user