115 lines
4.3 KiB
Python
115 lines
4.3 KiB
Python
"""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)
|