mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds unit testing for fancy new metadata class
This commit is contained in:
parent
eaa5913c8c
commit
82a6ff7772
@ -73,6 +73,22 @@ class InvenTreeAPITestCase(APITestCase):
|
||||
ruleset.save()
|
||||
break
|
||||
|
||||
def getActions(self, url):
|
||||
"""
|
||||
Return a dict of the 'actions' available at a given endpoint.
|
||||
Makes use of the HTTP 'OPTIONS' method to request this.
|
||||
"""
|
||||
|
||||
response = self.client.options(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
actions = response.data.get('actions', None)
|
||||
|
||||
if not actions:
|
||||
actions = {}
|
||||
|
||||
return actions
|
||||
|
||||
def get(self, url, data={}, expected_code=200):
|
||||
"""
|
||||
Issue a GET request
|
||||
|
@ -40,14 +40,14 @@ class InvenTreeMetadata(SimpleMetadata):
|
||||
|
||||
table = f"{app_label}_{tbl_label}"
|
||||
|
||||
actions = metadata['actions']
|
||||
actions = metadata.get('actions', None)
|
||||
|
||||
if actions is not None:
|
||||
|
||||
check = users.models.RuleSet.check_table_permission
|
||||
|
||||
# Map the request method to a permission type
|
||||
rolemap = {
|
||||
'GET': 'view',
|
||||
'OPTIONS': 'view',
|
||||
'POST': 'add',
|
||||
'PUT': 'change',
|
||||
'PATCH': 'change',
|
||||
@ -59,6 +59,14 @@ class InvenTreeMetadata(SimpleMetadata):
|
||||
if method in actions and not check(user, table, permission):
|
||||
del actions[method]
|
||||
|
||||
# Add a 'DELETE' action if we are allowed to delete
|
||||
if check(user, table, 'delete'):
|
||||
actions['DELETE'] = True
|
||||
|
||||
# Add a 'VIEW' action if we are allowed to view
|
||||
if check(user, table, 'view'):
|
||||
actions['GET'] = True
|
||||
|
||||
except AttributeError:
|
||||
# We will assume that if the serializer class does *not* have a Meta
|
||||
# then we don't need a permission
|
||||
|
@ -157,3 +157,68 @@ class APITests(InvenTreeAPITestCase):
|
||||
# New role permissions should have been added now
|
||||
self.assertIn('delete', roles['part'])
|
||||
self.assertIn('change', roles['build'])
|
||||
|
||||
def test_list_endpoint_actions(self):
|
||||
"""
|
||||
Tests for the OPTIONS method for API endpoints.
|
||||
"""
|
||||
|
||||
self.basicAuth()
|
||||
|
||||
# Without any 'part' permissions, we should not see any available actions
|
||||
url = reverse('api-part-list')
|
||||
|
||||
actions = self.getActions(url)
|
||||
|
||||
# No actions, as there are no permissions!
|
||||
self.assertEqual(len(actions), 0)
|
||||
|
||||
# Assign a new role
|
||||
self.assignRole('part.view')
|
||||
actions = self.getActions(url)
|
||||
|
||||
# As we don't have "add" permission, there should be no available API actions
|
||||
self.assertEqual(len(actions), 0)
|
||||
|
||||
# But let's make things interesting...
|
||||
# Why don't we treat ourselves to some "add" permissions
|
||||
self.assignRole('part.add')
|
||||
|
||||
actions = self.getActions(url)
|
||||
|
||||
self.assertIn('POST', actions)
|
||||
self.assertEqual(len(actions), 1)
|
||||
|
||||
def test_detail_endpoint_actions(self):
|
||||
"""
|
||||
Tests for detail API endpoint actions
|
||||
"""
|
||||
|
||||
self.basicAuth()
|
||||
|
||||
url = reverse('api-part-detail', kwargs={'pk': 1})
|
||||
|
||||
actions = self.getActions(url)
|
||||
|
||||
# No actions, as we do not have any permissions!
|
||||
self.assertEqual(len(actions), 0)
|
||||
|
||||
# Add a 'add' permission
|
||||
# Note: 'add' permission automatically implies 'change' also
|
||||
self.assignRole('part.add')
|
||||
|
||||
actions = self.getActions(url)
|
||||
|
||||
# 'add' permission does not apply here!
|
||||
self.assertEqual(len(actions), 1)
|
||||
self.assertIn('PUT', actions.keys())
|
||||
|
||||
# Add some other permissions
|
||||
self.assignRole('part.change')
|
||||
self.assignRole('part.delete')
|
||||
|
||||
actions = self.getActions(url)
|
||||
|
||||
self.assertEqual(len(actions), 2)
|
||||
self.assertIn('PUT', actions.keys())
|
||||
self.assertIn('DELETE', actions.keys())
|
||||
|
@ -1,8 +1,13 @@
|
||||
# Generated by Django 3.2 on 2021-06-01 05:25
|
||||
|
||||
import logging
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
def assign_bom_items(apps, schema_editor):
|
||||
"""
|
||||
Run through existing BuildItem objects,
|
||||
@ -13,7 +18,7 @@ def assign_bom_items(apps, schema_editor):
|
||||
BomItem = apps.get_model('part', 'bomitem')
|
||||
Part = apps.get_model('part', 'part')
|
||||
|
||||
print("Assigning BomItems to existing BuildItem objects")
|
||||
logger.info("Assigning BomItems to existing BuildItem objects")
|
||||
|
||||
count_valid = 0
|
||||
count_total = 0
|
||||
@ -41,7 +46,7 @@ def assign_bom_items(apps, schema_editor):
|
||||
pass
|
||||
|
||||
if count_total > 0:
|
||||
print(f"Assigned BomItem for {count_valid}/{count_total} entries")
|
||||
logger.info(f"Assigned BomItem for {count_valid}/{count_total} entries")
|
||||
|
||||
|
||||
def unassign_bom_items(apps, schema_editor):
|
||||
|
@ -1,5 +1,6 @@
|
||||
# Generated by Django 3.0.7 on 2020-11-10 10:11
|
||||
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from moneyed import CURRENCIES
|
||||
@ -7,6 +8,9 @@ from django.db import migrations, connection
|
||||
from company.models import SupplierPriceBreak
|
||||
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
|
||||
def migrate_currencies(apps, schema_editor):
|
||||
"""
|
||||
Migrate from the 'old' method of handling currencies,
|
||||
@ -19,7 +23,7 @@ def migrate_currencies(apps, schema_editor):
|
||||
for the SupplierPriceBreak model, to a new django-money compatible currency.
|
||||
"""
|
||||
|
||||
print("Updating currency references for SupplierPriceBreak model...")
|
||||
logger.info("Updating currency references for SupplierPriceBreak model...")
|
||||
|
||||
# A list of available currency codes
|
||||
currency_codes = CURRENCIES.keys()
|
||||
@ -39,7 +43,7 @@ def migrate_currencies(apps, schema_editor):
|
||||
suffix = suffix.strip().upper()
|
||||
|
||||
if suffix not in currency_codes:
|
||||
print("Missing suffix:", suffix)
|
||||
logger.warning(f"Missing suffix: '{suffix}'")
|
||||
|
||||
while suffix not in currency_codes:
|
||||
# Ask the user to input a valid currency
|
||||
@ -72,7 +76,7 @@ def migrate_currencies(apps, schema_editor):
|
||||
count += 1
|
||||
|
||||
if count > 0:
|
||||
print(f"Updated {count} SupplierPriceBreak rows")
|
||||
logger.info(f"Updated {count} SupplierPriceBreak rows")
|
||||
|
||||
def reverse_currencies(apps, schema_editor):
|
||||
"""
|
||||
|
@ -208,7 +208,7 @@ class RuleSet(models.Model):
|
||||
return True
|
||||
|
||||
# Print message instead of throwing an error
|
||||
print("Failed permission check for", table, permission)
|
||||
logger.info(f"User '{user.name}' failed permission check for {table}.{permission}")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
|
Loading…
Reference in New Issue
Block a user