from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from .filters import ( NodeAssignmentFilter, TransitionFilter, WorkflowFilter, WorkflowInstanceFilter, WorkflowNodeFilter, WorkflowObserverFilter, ) from .models import ( NodeAssignment, Transition, Workflow, WorkflowInstance, WorkflowNode, WorkflowObserver, ) from .serializers import ( NodeAssignmentSerializer, TransitionSerializer, WorkflowInstanceSerializer, WorkflowNodeSerializer, WorkflowObserverSerializer, WorkflowSerializer, ) class WorkflowViewSet(viewsets.ModelViewSet): queryset = Workflow.objects.all() serializer_class = WorkflowSerializer permission_classes = [IsAuthenticated] filterset_class = WorkflowFilter def initial(self, request, *args, **kwargs): from infrasynth.features.services import FeatureService if not FeatureService().is_enabled("workflows", user=request.user): from django.http import Http404 raise Http404() super().initial(request, *args, **kwargs) def get_queryset(self): return Workflow.objects.select_related("created_by").all() class WorkflowNodeViewSet(viewsets.ModelViewSet): queryset = WorkflowNode.objects.all() serializer_class = WorkflowNodeSerializer permission_classes = [IsAuthenticated] filterset_class = WorkflowNodeFilter def initial(self, request, *args, **kwargs): from infrasynth.features.services import FeatureService if not FeatureService().is_enabled("workflows", user=request.user): from django.http import Http404 raise Http404() super().initial(request, *args, **kwargs) def get_queryset(self): return WorkflowNode.objects.select_related("workflow").all() class TransitionViewSet(viewsets.ModelViewSet): queryset = Transition.objects.all() serializer_class = TransitionSerializer permission_classes = [IsAuthenticated] filterset_class = TransitionFilter def initial(self, request, *args, **kwargs): from infrasynth.features.services import FeatureService if not FeatureService().is_enabled("workflows", user=request.user): from django.http import Http404 raise Http404() super().initial(request, *args, **kwargs) def get_queryset(self): return Transition.objects.select_related("from_node", "to_node").all() class WorkflowInstanceViewSet(viewsets.ModelViewSet): queryset = WorkflowInstance.objects.all() serializer_class = WorkflowInstanceSerializer permission_classes = [IsAuthenticated] filterset_class = WorkflowInstanceFilter def initial(self, request, *args, **kwargs): from infrasynth.features.services import FeatureService if not FeatureService().is_enabled("workflows", user=request.user): from django.http import Http404 raise Http404() super().initial(request, *args, **kwargs) def get_queryset(self): return WorkflowInstance.objects.select_related("workflow", "current_node", "owner").all() def perform_create(self, serializer): from .engine import WorkflowEngine workflow = serializer.validated_data["workflow"] initial_data = serializer.validated_data.get("metadata") instance = WorkflowEngine().start(workflow.slug, owner=self.request.user, initial_data=initial_data) serializer.instance = instance @action(detail=True, methods=["get"]) def route(self, request, pk=None): instance = self.get_object() from .engine import WorkflowEngine return Response({"route": WorkflowEngine().get_route(instance.pk)}) @action(detail=True, methods=["get"]) def state(self, request, pk=None): instance = self.get_object() from .engine import WorkflowEngine return Response({"state": WorkflowEngine().get_node_states(instance.pk)}) @action(detail=True, methods=["post"]) def submit(self, request, pk=None): instance = self.get_object() from .engine import WorkflowEngine assignment_id = request.data.get("assignment_id") decision = request.data.get("decision") if not assignment_id or not decision: return Response( {"detail": "assignment_id and decision are required."}, status=status.HTTP_400_BAD_REQUEST, ) engine = WorkflowEngine() instance = engine.submit_decision( assignment_id, decision, data=request.data.get("data"), user=request.user, comments=request.data.get("comments", ""), ) return Response( { "instance_id": instance.pk, "status": instance.status, "current_node": ( {"id": instance.current_node_id, "name": instance.current_node.name} if instance.current_node_id else None ), } ) @action(detail=True, methods=["post"]) def assign(self, request, pk=None): instance = self.get_object() from .engine import WorkflowEngine node_id = request.data.get("node_id") user_ids = request.data.get("users", []) if not node_id or not user_ids: return Response( {"detail": "node_id and users are required."}, status=status.HTTP_400_BAD_REQUEST, ) from django.contrib.auth import get_user_model user_model = get_user_model() users = user_model.objects.filter(pk__in=user_ids) try: assignments = WorkflowEngine().assign_users( instance.pk, node_id, list(users), is_required=request.data.get("is_required", True), actor=request.user, ) except ValueError as exc: return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST) from .serializers import NodeAssignmentSerializer return Response( NodeAssignmentSerializer(assignments, many=True).data, status=status.HTTP_201_CREATED, ) @action(detail=True, methods=["post", "delete"]) def observers(self, request, pk=None): instance = self.get_object() from .engine import WorkflowEngine from .models import WorkflowObserver user_id = request.data.get("user_id") if not user_id: return Response( {"detail": "user_id is required."}, status=status.HTTP_400_BAD_REQUEST, ) engine = WorkflowEngine() if request.method == "DELETE": deleted, _ = WorkflowObserver.objects.filter(instance=instance, user_id=user_id).delete() if not deleted: return Response( {"detail": "Observer not found."}, status=status.HTTP_404_NOT_FOUND, ) return Response(status=status.HTTP_204_NO_CONTENT) from django.contrib.auth import get_user_model user_model = get_user_model() user = user_model.objects.filter(pk=user_id).first() if user is None: return Response({"detail": "User not found."}, status=status.HTTP_404_NOT_FOUND) observer = engine.add_observer(instance.pk, user) from .serializers import WorkflowObserverSerializer return Response(WorkflowObserverSerializer(observer).data, status=status.HTTP_201_CREATED) class NodeAssignmentViewSet(viewsets.ModelViewSet): queryset = NodeAssignment.objects.all() serializer_class = NodeAssignmentSerializer permission_classes = [IsAuthenticated] filterset_class = NodeAssignmentFilter def initial(self, request, *args, **kwargs): from infrasynth.features.services import FeatureService if not FeatureService().is_enabled("workflows", user=request.user): from django.http import Http404 raise Http404() super().initial(request, *args, **kwargs) def get_queryset(self): return NodeAssignment.objects.select_related("instance", "node", "user").all() class WorkflowObserverViewSet(viewsets.ModelViewSet): queryset = WorkflowObserver.objects.all() serializer_class = WorkflowObserverSerializer permission_classes = [IsAuthenticated] filterset_class = WorkflowObserverFilter def initial(self, request, *args, **kwargs): from infrasynth.features.services import FeatureService if not FeatureService().is_enabled("workflows", user=request.user): from django.http import Http404 raise Http404() super().initial(request, *args, **kwargs) def get_queryset(self): return WorkflowObserver.objects.select_related("instance", "user").all()