mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-16 17:28:11 +00:00
API endpoints for Parameter instances
This commit is contained in:
@@ -44,6 +44,7 @@ from InvenTree.mixins import (
|
|||||||
CreateAPI,
|
CreateAPI,
|
||||||
ListAPI,
|
ListAPI,
|
||||||
ListCreateAPI,
|
ListCreateAPI,
|
||||||
|
OutputOptionsMixin,
|
||||||
RetrieveAPI,
|
RetrieveAPI,
|
||||||
RetrieveDestroyAPI,
|
RetrieveDestroyAPI,
|
||||||
RetrieveUpdateAPI,
|
RetrieveUpdateAPI,
|
||||||
@@ -708,13 +709,17 @@ class AttachmentFilter(FilterSet):
|
|||||||
return queryset.filter(Q(attachment=None) | Q(attachment='')).distinct()
|
return queryset.filter(Q(attachment=None) | Q(attachment='')).distinct()
|
||||||
|
|
||||||
|
|
||||||
class AttachmentList(BulkDeleteMixin, ListCreateAPI):
|
class AttachmentMixin:
|
||||||
"""List API endpoint for Attachment objects."""
|
"""Mixin class for Attachment views."""
|
||||||
|
|
||||||
queryset = common.models.Attachment.objects.all()
|
queryset = common.models.Attachment.objects.all()
|
||||||
serializer_class = common.serializers.AttachmentSerializer
|
serializer_class = common.serializers.AttachmentSerializer
|
||||||
permission_classes = [IsAuthenticatedOrReadScope]
|
permission_classes = [IsAuthenticatedOrReadScope]
|
||||||
|
|
||||||
|
|
||||||
|
class AttachmentList(AttachmentMixin, BulkDeleteMixin, ListCreateAPI):
|
||||||
|
"""List API endpoint for Attachment objects."""
|
||||||
|
|
||||||
filter_backends = SEARCH_ORDER_FILTER
|
filter_backends = SEARCH_ORDER_FILTER
|
||||||
filterset_class = AttachmentFilter
|
filterset_class = AttachmentFilter
|
||||||
|
|
||||||
@@ -746,13 +751,9 @@ class AttachmentList(BulkDeleteMixin, ListCreateAPI):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class AttachmentDetail(RetrieveUpdateDestroyAPI):
|
class AttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||||
"""Detail API endpoint for Attachment objects."""
|
"""Detail API endpoint for Attachment objects."""
|
||||||
|
|
||||||
queryset = common.models.Attachment.objects.all()
|
|
||||||
serializer_class = common.serializers.AttachmentSerializer
|
|
||||||
permission_classes = [IsAuthenticatedOrReadScope]
|
|
||||||
|
|
||||||
def destroy(self, request, *args, **kwargs):
|
def destroy(self, request, *args, **kwargs):
|
||||||
"""Check user permissions before deleting an attachment."""
|
"""Check user permissions before deleting an attachment."""
|
||||||
attachment = self.get_object()
|
attachment = self.get_object()
|
||||||
@@ -827,6 +828,58 @@ class ParameterTemplateDetail(ParameterTemplateMixin, RetrieveUpdateDestroyAPI):
|
|||||||
"""Detail view for a ParameterTemplate object."""
|
"""Detail view for a ParameterTemplate object."""
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterFilter(FilterSet):
|
||||||
|
"""Custom filters for the ParameterList API endpoint."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Metaclass options for the filterset."""
|
||||||
|
|
||||||
|
model = common.models.Parameter
|
||||||
|
fields = ['model_type', 'model_id', 'template', 'updated_by']
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterMixin:
|
||||||
|
"""Mixin class for Parameter views."""
|
||||||
|
|
||||||
|
queryset = common.models.Parameter.objects.all()
|
||||||
|
serializer_class = common.serializers.ParameterSerializer
|
||||||
|
permission_classes = [IsAuthenticatedOrReadScope]
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterList(
|
||||||
|
OutputOptionsMixin,
|
||||||
|
ParameterMixin,
|
||||||
|
BulkDeleteMixin,
|
||||||
|
DataExportViewMixin,
|
||||||
|
ListCreateAPI,
|
||||||
|
):
|
||||||
|
"""List API endpoint for Parameter objects."""
|
||||||
|
|
||||||
|
filterset_class = ParameterFilter
|
||||||
|
filter_backends = SEARCH_ORDER_FILTER
|
||||||
|
|
||||||
|
ordering_fields = ['name', 'data', 'units', 'template', 'updated', 'updated_by']
|
||||||
|
|
||||||
|
ordering_field_aliases = {
|
||||||
|
'name': 'template__name',
|
||||||
|
'units': 'template__units',
|
||||||
|
'data': ['data_numeric', 'data'],
|
||||||
|
}
|
||||||
|
|
||||||
|
search_fields = [
|
||||||
|
'data',
|
||||||
|
'template__name',
|
||||||
|
'template__description',
|
||||||
|
'template__units',
|
||||||
|
]
|
||||||
|
|
||||||
|
unique_create_fields = ['model_type', 'model_id', 'template']
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterDetail(ParameterMixin, RetrieveUpdateDestroyAPI):
|
||||||
|
"""Detail API endpoint for Parameter objects."""
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(cache_control(public=True, max_age=86400), name='dispatch')
|
@method_decorator(cache_control(public=True, max_age=86400), name='dispatch')
|
||||||
class IconList(ListAPI):
|
class IconList(ListAPI):
|
||||||
"""List view for available icon packages."""
|
"""List view for available icon packages."""
|
||||||
@@ -1082,7 +1135,14 @@ common_api_urls = [
|
|||||||
name='api-parameter-template-list',
|
name='api-parameter-template-list',
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
)
|
),
|
||||||
|
path(
|
||||||
|
'<int:pk>/',
|
||||||
|
include([
|
||||||
|
path('', ParameterDetail.as_view(), name='api-parameter-detail')
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
path('', ParameterList.as_view(), name='api-parameter-list'),
|
||||||
]),
|
]),
|
||||||
),
|
),
|
||||||
path(
|
path(
|
||||||
|
|||||||
@@ -2621,6 +2621,19 @@ class Parameter(
|
|||||||
if math.isnan(self.data_numeric) or math.isinf(self.data_numeric):
|
if math.isnan(self.data_numeric) or math.isinf(self.data_numeric):
|
||||||
self.data_numeric = None
|
self.data_numeric = None
|
||||||
|
|
||||||
|
def check_permission(self, permission, user):
|
||||||
|
"""Check if the user has the required permission for this parameter."""
|
||||||
|
from InvenTree.models import InvenTreeParameterMixin
|
||||||
|
|
||||||
|
model_class = common.validators.parameter_model_class_from_label(
|
||||||
|
self.model_type
|
||||||
|
)
|
||||||
|
|
||||||
|
if not issubclass(model_class, InvenTreeParameterMixin):
|
||||||
|
raise ValidationError(_('Invalid model type specified for parameter'))
|
||||||
|
|
||||||
|
return model_class.check_related_permission(permission, user)
|
||||||
|
|
||||||
model_type = models.CharField(
|
model_type = models.CharField(
|
||||||
max_length=100,
|
max_length=100,
|
||||||
default='',
|
default='',
|
||||||
|
|||||||
@@ -22,9 +22,11 @@ from InvenTree.helpers import get_objectreference
|
|||||||
from InvenTree.helpers_model import construct_absolute_url
|
from InvenTree.helpers_model import construct_absolute_url
|
||||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
|
FilterableSerializerMixin,
|
||||||
InvenTreeAttachmentSerializerField,
|
InvenTreeAttachmentSerializerField,
|
||||||
InvenTreeImageSerializerField,
|
InvenTreeImageSerializerField,
|
||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
|
enable_filter,
|
||||||
)
|
)
|
||||||
from plugin import registry as plugin_registry
|
from plugin import registry as plugin_registry
|
||||||
from users.serializers import OwnerSerializer, UserSerializer
|
from users.serializers import OwnerSerializer, UserSerializer
|
||||||
@@ -692,7 +694,7 @@ class AttachmentSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
# Check that the user has the required permissions to attach files to the target model
|
# Check that the user has the required permissions to attach files to the target model
|
||||||
if not target_model_class.check_related_permission('change', user):
|
if not target_model_class.check_related_permission('change', user):
|
||||||
raise PermissionDenied(_(permission_error_msg))
|
raise PermissionDenied(permission_error_msg)
|
||||||
|
|
||||||
return super().save(**kwargs)
|
return super().save(**kwargs)
|
||||||
|
|
||||||
@@ -737,6 +739,95 @@ class ParameterTemplateSerializer(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ParameterSerializer(
|
||||||
|
FilterableSerializerMixin, DataImportExportSerializerMixin, InvenTreeModelSerializer
|
||||||
|
):
|
||||||
|
"""Serializer for the Parameter model."""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta options for ParameterSerializer."""
|
||||||
|
|
||||||
|
model = common_models.Parameter
|
||||||
|
fields = [
|
||||||
|
'pk',
|
||||||
|
'template',
|
||||||
|
'model_type',
|
||||||
|
'model_id',
|
||||||
|
'data',
|
||||||
|
'data_numeric',
|
||||||
|
'note',
|
||||||
|
'updated',
|
||||||
|
'updated_by',
|
||||||
|
'template_detail',
|
||||||
|
'updated_by_detail',
|
||||||
|
]
|
||||||
|
|
||||||
|
read_only_fields = ['updated', 'updated_by']
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""Override the model_type field to provide dynamic choices."""
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
if len(self.fields['model_type'].choices) == 0:
|
||||||
|
self.fields[
|
||||||
|
'model_type'
|
||||||
|
].choices = common.validators.parameter_model_options()
|
||||||
|
|
||||||
|
def save(self, **kwargs):
|
||||||
|
"""Save the Parameter instance."""
|
||||||
|
from InvenTree.models import InvenTreeParameterMixin
|
||||||
|
from users.permissions import check_user_permission
|
||||||
|
|
||||||
|
model_type = self.validated_data.get('model_type', None)
|
||||||
|
|
||||||
|
if model_type is None and self.instance:
|
||||||
|
model_type = self.instance.model_type
|
||||||
|
|
||||||
|
# Ensure that the user has permission to modify parameters for the specified model
|
||||||
|
user = self.context.get('request').user
|
||||||
|
|
||||||
|
target_model_class = common.validators.parameter_model_class_from_label(
|
||||||
|
model_type
|
||||||
|
)
|
||||||
|
|
||||||
|
if not issubclass(target_model_class, InvenTreeParameterMixin):
|
||||||
|
raise PermissionDenied(_('Invalid model type specified for parameter'))
|
||||||
|
|
||||||
|
permission_error_msg = _(
|
||||||
|
'User does not have permission to create or edit parameters for this model'
|
||||||
|
)
|
||||||
|
|
||||||
|
if not check_user_permission(user, target_model_class, 'change'):
|
||||||
|
raise PermissionDenied(permission_error_msg)
|
||||||
|
|
||||||
|
if not target_model_class.check_related_permission('change', user):
|
||||||
|
raise PermissionDenied(permission_error_msg)
|
||||||
|
|
||||||
|
instance = super().save(**kwargs)
|
||||||
|
instance.updated_by = user
|
||||||
|
instance.save()
|
||||||
|
|
||||||
|
return instance
|
||||||
|
|
||||||
|
# Note: The choices are overridden at run-time on class initialization
|
||||||
|
model_type = serializers.ChoiceField(
|
||||||
|
label=_('Model Type'),
|
||||||
|
default='',
|
||||||
|
choices=common.validators.parameter_model_options(),
|
||||||
|
required=False,
|
||||||
|
allow_blank=True,
|
||||||
|
allow_null=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
updated_by_detail = enable_filter(
|
||||||
|
UserSerializer(source='updated_by', read_only=True, many=False), True
|
||||||
|
)
|
||||||
|
|
||||||
|
template_detail = enable_filter(
|
||||||
|
ParameterTemplateSerializer(source='template', read_only=True, many=False), True
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class IconSerializer(serializers.Serializer):
|
class IconSerializer(serializers.Serializer):
|
||||||
"""Serializer for an icon."""
|
"""Serializer for an icon."""
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,18 @@ def parameter_template_model_options():
|
|||||||
return [('', _('Any model type')), *parameter_model_options()]
|
return [('', _('Any model type')), *parameter_model_options()]
|
||||||
|
|
||||||
|
|
||||||
|
def parameter_model_class_from_label(label: str):
|
||||||
|
"""Return the model class for the given label."""
|
||||||
|
if not label:
|
||||||
|
raise ValidationError(_('No parameter model type provided'))
|
||||||
|
|
||||||
|
for model in parameter_model_types():
|
||||||
|
if model.__name__.lower() == label.lower():
|
||||||
|
return model
|
||||||
|
|
||||||
|
raise ValidationError(_('Invalid parameter model type') + f": '{label}'")
|
||||||
|
|
||||||
|
|
||||||
def validate_parameter_model_type(value: str):
|
def validate_parameter_model_type(value: str):
|
||||||
"""Ensure that the provided parameter model is valid."""
|
"""Ensure that the provided parameter model is valid."""
|
||||||
model_names = [el[0] for el in parameter_model_options()]
|
model_names = [el[0] for el in parameter_model_options()]
|
||||||
|
|||||||
Reference in New Issue
Block a user