mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
* Added initial draft for machines * refactor: isPluginRegistryLoaded check into own ready function * Added suggestions from codereview * Refactor: base_drivers -> machine_types * Use new BaseInvenTreeSetting unique interface * Fix Django not ready error * Added get_machines function to driver - get_machines function on driver - get_machine function on driver - initialized attribute on machine * Added error handeling for driver and machine type * Extended get_machines functionality * Export everything from plugin module * Fix spelling mistakes * Better states handeling, BaseMachineType is now used instead of Machine Model * Use uuid as pk * WIP: machine termination hook * Remove termination hook as this does not work with gunicorn * Remove machine from registry after delete * Added ClassProviderMixin * Check for slug dupplication * Added config_type to MachineSettings to define machine/driver settings * Refactor helper mixins into own file in InvenTree app * Fixed typing and added required_attributes for BaseDriver * fix: generic status import * Added first draft for machine states * Added convention for status codes * Added update_machine hook * Removed unnecessary _key suffix from machine config model * Initil draft for machine API * Refactored BaseInvenTreeSetting all_items and allValues method * Added required to InvenTreeBaseSetting and check_settings method * check if all required machine settings are defined and refactor: use getattr * Fix: comment * Fix initialize error and python 3.9 compability * Make machine states available through the global states api * Added basic PUI machine admin implementation that is still in dev * Added basic machine setting UI to PUI * Added machine detail view to PUI admin center * Fix merge issues * Fix style issues * Added machine type,machine driver,error stack tables * Fix style in machine/serializers.py * Added pui link from machine to machine type/driver drawer * Removed only partially working django admin in favor of the PUI admin center implementation * Added required field to settings item * Added machine restart function * Added restart requird badge to machine table/drawer * Added driver init function * handle error functions for machines and registry * Added driver errors * Added machine table to driver drawer * Added back button to detail drawer component * Fix auto formatable pre-commit * fix: style * Fix deepsource * Removed slug field from table, added more links between drawers, remove detail drawer blur * Added initial docs * Removed description from driver/machine type select and fixed disabled driver select if no machine type is selected * Added basic label printing implementation * Remove translated column names because they are now retrieved from the api * Added printer location setting * Save last 10 used printer machine per user and sort them in the printing dialog * Added BasePrintingOptionsSerializer for common options * Fix not printing_options are not properly casted to its internal value * Fix type * Improved machine docs * Fix docs * Added UNKNOWN status code to label printer status * Skip machine loading when running migrations * Fix testing? * Fix: tests? * Fix: tests? * Disable docs check precommit * Disable docs check precommit * First draft for tests * fix test * Add type ignore * Added API tests * Test ci? * Add more tests * Added more tests * Bump api version * Changed driver/base driver naming schema * Added more tests * Fix tests * Added setting choice with kwargs and get_machines with initialized=None * Refetch table after deleting machine * Fix test --------- Co-authored-by: Matthias Mair <code@mjmair.com>
252 lines
7.6 KiB
Python
252 lines
7.6 KiB
Python
"""JSON API for the machine app."""
|
|
|
|
from django.urls import include, path, re_path
|
|
|
|
from drf_spectacular.utils import extend_schema
|
|
from rest_framework import permissions
|
|
from rest_framework.exceptions import NotFound
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
|
|
import machine.serializers as MachineSerializers
|
|
from InvenTree.filters import SEARCH_ORDER_FILTER
|
|
from InvenTree.mixins import ListCreateAPI, RetrieveUpdateAPI, RetrieveUpdateDestroyAPI
|
|
from machine import registry
|
|
from machine.models import MachineConfig, MachineSetting
|
|
|
|
|
|
class MachineList(ListCreateAPI):
|
|
"""API endpoint for list of Machine objects.
|
|
|
|
- GET: Return a list of all Machine objects
|
|
- POST: create a MachineConfig
|
|
"""
|
|
|
|
queryset = MachineConfig.objects.all()
|
|
serializer_class = MachineSerializers.MachineConfigSerializer
|
|
|
|
def get_serializer_class(self):
|
|
"""Allow driver, machine_type fields on creation."""
|
|
if self.request.method == 'POST':
|
|
return MachineSerializers.MachineConfigCreateSerializer
|
|
return super().get_serializer_class()
|
|
|
|
filter_backends = SEARCH_ORDER_FILTER
|
|
|
|
filterset_fields = ['machine_type', 'driver', 'active']
|
|
|
|
ordering_fields = ['name', 'machine_type', 'driver', 'active']
|
|
|
|
ordering = ['-active', 'machine_type']
|
|
|
|
search_fields = ['name']
|
|
|
|
|
|
class MachineDetail(RetrieveUpdateDestroyAPI):
|
|
"""API detail endpoint for MachineConfig object.
|
|
|
|
- GET: return a single MachineConfig
|
|
- PUT: update a MachineConfig
|
|
- PATCH: partial update a MachineConfig
|
|
- DELETE: delete a MachineConfig
|
|
"""
|
|
|
|
queryset = MachineConfig.objects.all()
|
|
serializer_class = MachineSerializers.MachineConfigSerializer
|
|
|
|
|
|
def get_machine(machine_pk):
|
|
"""Get machine by pk.
|
|
|
|
Raises:
|
|
NotFound: If machine is not found
|
|
|
|
Returns:
|
|
BaseMachineType: The machine instance in the registry
|
|
"""
|
|
machine = registry.get_machine(machine_pk)
|
|
|
|
if machine is None:
|
|
raise NotFound(detail=f"Machine '{machine_pk}' not found")
|
|
|
|
return machine
|
|
|
|
|
|
class MachineSettingList(APIView):
|
|
"""List endpoint for all machine related settings.
|
|
|
|
- GET: return all settings for a machine config
|
|
"""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
responses={200: MachineSerializers.MachineSettingSerializer(many=True)}
|
|
)
|
|
def get(self, request, pk):
|
|
"""Return all settings for a machine config."""
|
|
machine = get_machine(pk)
|
|
|
|
all_settings = []
|
|
|
|
for settings, config_type in machine.setting_types:
|
|
settings_dict = MachineSetting.all_settings(
|
|
settings_definition=settings,
|
|
machine_config=machine.machine_config,
|
|
config_type=config_type,
|
|
)
|
|
all_settings.extend(list(settings_dict.values()))
|
|
|
|
results = MachineSerializers.MachineSettingSerializer(
|
|
all_settings, many=True
|
|
).data
|
|
return Response(results)
|
|
|
|
|
|
class MachineSettingDetail(RetrieveUpdateAPI):
|
|
"""Detail endpoint for a machine-specific setting.
|
|
|
|
- GET: Get machine setting detail
|
|
- PUT: Update machine setting
|
|
- PATCH: Update machine setting
|
|
|
|
(Note that these cannot be created or deleted via API)
|
|
"""
|
|
|
|
lookup_field = 'key'
|
|
queryset = MachineSetting.objects.all()
|
|
serializer_class = MachineSerializers.MachineSettingSerializer
|
|
|
|
def get_object(self):
|
|
"""Lookup machine setting object, based on the URL."""
|
|
pk = self.kwargs['pk']
|
|
key = self.kwargs['key']
|
|
config_type = MachineSetting.get_config_type(self.kwargs['config_type'])
|
|
|
|
machine = get_machine(pk)
|
|
|
|
setting_map = {d: s for s, d in machine.setting_types}
|
|
if key.upper() not in setting_map[config_type]:
|
|
raise NotFound(
|
|
detail=f"Machine '{machine.name}' has no {config_type.name} setting matching '{key.upper()}'"
|
|
)
|
|
|
|
return MachineSetting.get_setting_object(
|
|
key, machine_config=machine.machine_config, config_type=config_type
|
|
)
|
|
|
|
|
|
class MachineRestart(APIView):
|
|
"""Endpoint for performing a machine restart.
|
|
|
|
- POST: restart machine by pk
|
|
"""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
@extend_schema(responses={200: MachineSerializers.MachineRestartSerializer()})
|
|
def post(self, request, pk):
|
|
"""Restart machine by pk."""
|
|
machine = get_machine(pk)
|
|
registry.restart_machine(machine)
|
|
|
|
result = MachineSerializers.MachineRestartSerializer({'ok': True}).data
|
|
return Response(result)
|
|
|
|
|
|
class MachineTypesList(APIView):
|
|
"""List API Endpoint for all discovered machine types.
|
|
|
|
- GET: List all machine types
|
|
"""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
@extend_schema(responses={200: MachineSerializers.MachineTypeSerializer(many=True)})
|
|
def get(self, request):
|
|
"""List all machine types."""
|
|
machine_types = list(registry.machine_types.values())
|
|
results = MachineSerializers.MachineTypeSerializer(
|
|
machine_types, many=True
|
|
).data
|
|
return Response(results)
|
|
|
|
|
|
class MachineDriverList(APIView):
|
|
"""List API Endpoint for all discovered machine drivers.
|
|
|
|
- GET: List all machine drivers
|
|
"""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
@extend_schema(
|
|
responses={200: MachineSerializers.MachineDriverSerializer(many=True)}
|
|
)
|
|
def get(self, request):
|
|
"""List all machine drivers."""
|
|
drivers = registry.drivers.values()
|
|
if machine_type := request.query_params.get('machine_type', None):
|
|
drivers = filter(lambda d: d.machine_type == machine_type, drivers)
|
|
|
|
results = MachineSerializers.MachineDriverSerializer(
|
|
list(drivers), many=True
|
|
).data
|
|
return Response(results)
|
|
|
|
|
|
class RegistryStatusView(APIView):
|
|
"""Status API endpoint for the machine registry.
|
|
|
|
- GET: Provide status data for the machine registry
|
|
"""
|
|
|
|
permission_classes = [permissions.IsAuthenticated]
|
|
|
|
serializer_class = MachineSerializers.MachineRegistryStatusSerializer
|
|
|
|
@extend_schema(
|
|
responses={200: MachineSerializers.MachineRegistryStatusSerializer()}
|
|
)
|
|
def get(self, request):
|
|
"""Provide status data for the machine registry."""
|
|
result = MachineSerializers.MachineRegistryStatusSerializer({
|
|
'registry_errors': [{'message': str(error)} for error in registry.errors]
|
|
}).data
|
|
|
|
return Response(result)
|
|
|
|
|
|
machine_api_urls = [
|
|
# machine types
|
|
path('types/', MachineTypesList.as_view(), name='api-machine-types'),
|
|
# machine drivers
|
|
path('drivers/', MachineDriverList.as_view(), name='api-machine-drivers'),
|
|
# registry status
|
|
path('status/', RegistryStatusView.as_view(), name='api-machine-registry-status'),
|
|
# detail views for a single Machine
|
|
path(
|
|
'<uuid:pk>/',
|
|
include([
|
|
# settings
|
|
path(
|
|
'settings/',
|
|
include([
|
|
re_path(
|
|
r'^(?P<config_type>M|D)/(?P<key>\w+)/',
|
|
MachineSettingDetail.as_view(),
|
|
name='api-machine-settings-detail',
|
|
),
|
|
path('', MachineSettingList.as_view(), name='api-machine-settings'),
|
|
]),
|
|
),
|
|
# restart
|
|
path('restart/', MachineRestart.as_view(), name='api-machine-restart'),
|
|
# detail
|
|
path('', MachineDetail.as_view(), name='api-machine-detail'),
|
|
]),
|
|
),
|
|
# machine list and create
|
|
path('', MachineList.as_view(), name='api-machine-list'),
|
|
]
|