"""HTTP adapter for shared task automation rules.""" from django.db.models import Count, Q from django.http import Http404 from rest_framework import filters, status, viewsets from rest_framework.decorators import action from rest_framework.response import Response from tasks.automation.application import ( AccessibleTaskNotFound, ManualAutomationUnavailable, eligible_button_automations, get_accessible_automation_task, run_manual_automation, ) from tasks.automation.schema import automation_catalog from tasks.models import TaskAutomation, TaskAutomationRun from ..permissions import CanAccessTaskAutomationAPI from ..serializers import TaskAutomationRunSerializer, TaskAutomationSerializer class TaskAutomationViewSet(viewsets.ModelViewSet): """Manage shared rules and execute task-scoped automation buttons.""" permission_classes = [CanAccessTaskAutomationAPI] serializer_class = TaskAutomationSerializer filter_backends = [filters.SearchFilter, filters.OrderingFilter] search_fields = ["name", "description"] ordering_fields = ["position", "name", "created_at", "last_run_at"] ordering = ["kind", "position", "name", "id"] def get_queryset(self): queryset = ( TaskAutomation.objects.select_related("created_by") .prefetch_related("boards") .annotate(runs_count=Count("runs", distinct=True)) ) kind = self.request.query_params.get("kind") if kind: queryset = queryset.filter(kind=kind) if self.request.query_params.get("active") in {"true", "false"}: queryset = queryset.filter( is_active=self.request.query_params["active"] == "true" ) if board_id := self.request.query_params.get("board"): queryset = queryset.filter( Q(applies_to_all_boards=True) | Q(boards=board_id) ).distinct() return queryset def perform_create(self, serializer): serializer.save(created_by=self.request.user) @action(detail=False, methods=["get"]) def catalog(self, request): return Response(automation_catalog()) def _accessible_task(self, request, task_id): try: return get_accessible_automation_task( actor=request.user, task_id=task_id, ) except AccessibleTaskNotFound as exc: raise Http404 from exc @action(detail=False, methods=["get"]) def buttons(self, request): task_id = request.query_params.get("task") if not task_id: return Response( {"task": ["Укажите задачу."]}, status=status.HTTP_400_BAD_REQUEST, ) task = self._accessible_task(request, task_id) eligible = eligible_button_automations(self.get_queryset(), task=task) return Response(self.get_serializer(eligible, many=True).data) @action(detail=True, methods=["post"]) def run(self, request, pk=None): automation = self.get_object() task_id = request.data.get("task") if not task_id: return Response( {"task": ["Укажите задачу."]}, status=status.HTTP_400_BAD_REQUEST, ) task = self._accessible_task(request, task_id) try: outcome = run_manual_automation( automation, task=task, actor=request.user, ) except ManualAutomationUnavailable: return Response( {"detail": "Эту автоматизацию нельзя запустить вручную."}, status=status.HTTP_400_BAD_REQUEST, ) if outcome.conflict_message: return Response( {"detail": outcome.conflict_message}, status=status.HTTP_409_CONFLICT, ) return Response(TaskAutomationRunSerializer(outcome.run).data) @action(detail=True, methods=["get"]) def runs(self, request, pk=None): automation = self.get_object() queryset = TaskAutomationRun.objects.filter( automation=automation, ).select_related("automation", "task", "actor")[:100] return Response(TaskAutomationRunSerializer(queryset, many=True).data)