2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 03:26:45 +00:00
Matthias Mair d5086b2fb1
User defined states (#7862)
* Add custom user defined states

* make tests more reliable

* fix list options

* Adapt version

* do not engage if rebuilding

* remove unneeded attr

* remove unneeded attr

* fix enum imports

* adapt cove target

* Add status_custom_key to all other serializers

* fix serializer method

* simplify branching

* remove unneeded imports

* inherit read_only status from leader field

* Add more tests

* fix tests

* add test for function

* refactor for easier testing

* move test to seperate class

* Add options testing

* extend serializer

* add test for all states and refactor to reuse already build functions

* use custom field in PUI too

* reset diff

* style fix

* fix comparison

* Add test for str

* test color exceptions too

* remove user state from tracking

* Add intro from model fields too

* update docs

* simplify implementation

* update tests

* fix name

* rename test

* simplify tags and test fully

* extend test to machine status

* move logic for response formatting over

* extend api response with machine  status

* ensure only direct subclasses are discovered

* test for length of total respone too

* use new fields on PUI too

* fix test assertion with plugins enabled

* also observe rendering in filters

* Add managment endpoints and APIs

* Add contenttypes to PUI renderes

* use filteres instead

* fix import order

* fix api route definition

* move status choices to serializer

* fix lookup

* fix filtering

* remove admin integration

* cleanup migration

* fix migration change

* cleanup code location

* fix imports

* Add docs for custom states

* add links to custom status
2024-08-22 07:33:15 +10:00

135 lines
4.5 KiB
Python

"""Generic implementation of status api functions for InvenTree models."""
import inspect
from django.urls import include, path
from drf_spectacular.utils import OpenApiResponse, extend_schema
from rest_framework import permissions, serializers
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
import common.models
import common.serializers
from generic.states.custom import get_status_api_response
from importer.mixins import DataExportViewMixin
from InvenTree.filters import SEARCH_ORDER_FILTER
from InvenTree.mixins import ListCreateAPI, RetrieveUpdateDestroyAPI
from InvenTree.permissions import IsStaffOrReadOnly
from InvenTree.serializers import EmptySerializer
from machine.machine_type import MachineStatus
from .states import StatusCode
class StatusViewSerializer(serializers.Serializer):
"""Serializer for the StatusView responses."""
class_name = serializers.CharField()
values = serializers.DictField()
class StatusView(GenericAPIView):
"""Generic API endpoint for discovering information on 'status codes' for a particular model.
This class should be implemented as a subclass for each type of status.
For example, the API endpoint /stock/status/ will have information about
all available 'StockStatus' codes
"""
permission_classes = [permissions.IsAuthenticated]
# Override status_class for implementing subclass
MODEL_REF = 'statusmodel'
def get_status_model(self, *args, **kwargs):
"""Return the StatusCode model based on extra parameters passed to the view."""
status_model = self.kwargs.get(self.MODEL_REF, None)
if status_model is None:
raise serializers.ValidationError(
f"StatusView view called without '{self.MODEL_REF}' parameter"
)
return status_model
@extend_schema(
description='Retrieve information about a specific status code',
responses={
200: OpenApiResponse(description='Status code information'),
400: OpenApiResponse(description='Invalid request'),
},
)
def get(self, request, *args, **kwargs):
"""Perform a GET request to learn information about status codes."""
status_class = self.get_status_model()
if not inspect.isclass(status_class):
raise NotImplementedError('`status_class` not a class')
if not issubclass(status_class, StatusCode):
raise NotImplementedError('`status_class` not a valid StatusCode class')
data = {'class': status_class.__name__, 'values': status_class.dict()}
return Response(data)
class AllStatusViews(StatusView):
"""Endpoint for listing all defined status models."""
permission_classes = [permissions.IsAuthenticated]
serializer_class = EmptySerializer
def get(self, request, *args, **kwargs):
"""Perform a GET request to learn information about status codes."""
data = get_status_api_response()
# Extend with MachineStatus classes
data.update(get_status_api_response(MachineStatus, prefix=['MachineStatus']))
return Response(data)
# Custom states
class CustomStateList(DataExportViewMixin, ListCreateAPI):
"""List view for all custom states."""
queryset = common.models.InvenTreeCustomUserStateModel.objects.all()
serializer_class = common.serializers.CustomStateSerializer
permission_classes = [permissions.IsAuthenticated, IsStaffOrReadOnly]
filter_backends = SEARCH_ORDER_FILTER
ordering_fields = ['key']
search_fields = ['key', 'name', 'label', 'reference_status']
class CustomStateDetail(RetrieveUpdateDestroyAPI):
"""Detail view for a particular custom states."""
queryset = common.models.InvenTreeCustomUserStateModel.objects.all()
serializer_class = common.serializers.CustomStateSerializer
permission_classes = [permissions.IsAuthenticated, IsStaffOrReadOnly]
urlpattern = [
# Custom state
path(
'custom/',
include([
path(
'<int:pk>/', CustomStateDetail.as_view(), name='api-custom-state-detail'
),
path('', CustomStateList.as_view(), name='api-custom-state-list'),
]),
),
# Generic status views
path(
'',
include([
path(
f'<str:{StatusView.MODEL_REF}>/',
include([path('', StatusView.as_view(), name='api-status')]),
),
path('', AllStatusViews.as_view(), name='api-status-all'),
]),
),
]