from rest_framework import viewsets, status from rest_framework.decorators import action from rest_framework.response import Response from .models import CrawlTask, CrawlRun from .serializers import CrawlTaskSerializer, CrawlRunSerializer class CrawlTaskViewSet(viewsets.ModelViewSet): """ ViewSet for CrawlTask models. Supports CRUD and custom trigger/runs actions. """ queryset = CrawlTask.objects.all().order_by('-created_at') serializer_class = CrawlTaskSerializer @action(detail=True, methods=['post'], url_path='trigger') def trigger(self, request, pk=None): task = self.get_object() # Create a new CrawlRun with status RUNNING run = CrawlRun.objects.create( crawl_task=task, status='RUNNING' ) # Check if tasks can be imported. try: from crawler.tasks import run_crawl_pipeline # run asynchronously run_crawl_pipeline.delay(str(run.id), force=True) is_queued = True except ImportError: # Fallback if tasks.py doesn't exist yet or run_crawl_pipeline is not defined is_queued = False return Response({ "status": "queued" if is_queued else "queued_stub", "run_id": str(run.id) }, status=status.HTTP_202_ACCEPTED) @action(detail=True, methods=['get'], url_path='runs') def runs(self, request, pk=None): task = self.get_object() runs = task.runs.all().order_by('-started_at') page = self.paginate_queryset(runs) if page is not None: serializer = CrawlRunSerializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = CrawlRunSerializer(runs, many=True) return Response(serializer.data) from django.utils import timezone class CrawlRunViewSet(viewsets.ModelViewSet): """ ViewSet for CrawlRun models. Supports CRUD (including DELETE) and stopping active runs. """ queryset = CrawlRun.objects.all().order_by('-started_at') serializer_class = CrawlRunSerializer @action(detail=True, methods=['post'], url_path='stop') def stop_run(self, request, pk=None): run = self.get_object() if run.status == 'RUNNING': run.status = 'FAILED' run.finished_at = timezone.now() run.error_log = "اجرا توسط کاربر متوقف شد." run.save() return Response({"status": "stopped", "run_id": str(run.id)}, status=status.HTTP_200_OK) return Response({"status": "not_running", "run_id": str(run.id)}, status=status.HTTP_400_BAD_REQUEST)