Skip to content
This repository has been archived by the owner on Nov 21, 2024. It is now read-only.

Commit

Permalink
author-consolidation: fixed aggreggations, added swagger documentatio…
Browse files Browse the repository at this point in the history
…n, updated partialupdate but needs testing
  • Loading branch information
DonHaul committed Aug 2, 2024
1 parent f86a8fb commit 6016924
Show file tree
Hide file tree
Showing 10 changed files with 250 additions and 92 deletions.
50 changes: 49 additions & 1 deletion backoffice/backoffice/workflows/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django_elasticsearch_dsl_drf.serializers import DocumentSerializer
from drf_spectacular.utils import OpenApiExample, extend_schema_serializer
from rest_framework import serializers

from backoffice.workflows.constants import ResolutionDags
from backoffice.workflows.constants import ResolutionDags, StatusChoices, WorkflowType
from backoffice.workflows.documents import WorkflowDocument
from backoffice.workflows.models import Workflow, WorkflowTicket

Expand All @@ -24,6 +25,53 @@ class Meta:
fields = "__all__"


@extend_schema_serializer(
exclude_fields=[
"_created_at",
"_updated_at",
], # Exclude internal fields from schema
examples=[
OpenApiExample(
"Author Workflow Serializer",
summary="Author Workflow Serializer no data",
description="Author Workflow Serializer",
value={
"workflow_type": WorkflowType.AUTHOR_CREATE,
"status": StatusChoices.RUNNING,
"core": False,
"is_update": False,
"data": {},
},
),
],
)
class WorkflowAuthorSerializer(WorkflowSerializer):
def validate_workflow_type(self, value):
allowed_workflow_types = [
WorkflowType.AUTHOR_CREATE,
WorkflowType.AUTHOR_UPDATE,
]
if value not in allowed_workflow_types:
raise serializers.ValidationError(
f"The field `workflow_type` should be on of {allowed_workflow_types}"
)
return value


@extend_schema_serializer(
examples=[
OpenApiExample(
"Accept",
description="Author Workflow Serializer",
value={"value": "accept", "create_ticket": False},
),
OpenApiExample(
"Reject",
description="Author Workflow Serializer",
value={"value": "reject", "create_ticket": False},
),
],
)
class AuthorResolutionSerializer(serializers.Serializer):
value = serializers.ChoiceField(choices=ResolutionDags)
create_ticket = serializers.BooleanField(default=False)
125 changes: 109 additions & 16 deletions backoffice/backoffice/workflows/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,13 @@
OrderingFilterBackend,
)
from django_elasticsearch_dsl_drf.viewsets import BaseDocumentViewSet
from drf_spectacular.utils import (
OpenApiExample,
OpenApiParameter,
OpenApiTypes,
extend_schema,
extend_schema_view,
)
from opensearch_dsl import TermsFacet
from rest_framework import status, viewsets
from rest_framework.decorators import action
Expand All @@ -18,11 +25,17 @@
from backoffice.workflows import airflow_utils
from backoffice.workflows.api.serializers import (
AuthorResolutionSerializer,
WorkflowAuthorSerializer,
WorkflowDocumentSerializer,
WorkflowSerializer,
WorkflowTicketSerializer,
)
from backoffice.workflows.constants import WORKFLOW_DAGS, ResolutionDags
from backoffice.workflows.constants import (
WORKFLOW_DAGS,
ResolutionDags,
StatusChoices,
WorkflowType,
)
from backoffice.workflows.documents import WorkflowDocument
from backoffice.workflows.models import Workflow, WorkflowTicket

Expand All @@ -40,19 +53,6 @@ def get_queryset(self):
return self.queryset


class WorkflowPartialUpdateViewSet(viewsets.ViewSet):
def partial_update(self, request, pk=None):
workflow_instance = get_object_or_404(Workflow, pk=pk)
serializer = WorkflowSerializer(
workflow_instance, data=request.data, partial=True
)

if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


class WorkflowTicketViewSet(viewsets.ViewSet):
def retrieve(self, request, *args, **kwargs):
workflow_id = kwargs.get("pk")
Expand Down Expand Up @@ -101,8 +101,13 @@ def create(self, request, *args, **kwargs):


class AuthorWorkflowViewSet(viewsets.ViewSet):
serializer_class = WorkflowSerializer
serializer_class = WorkflowAuthorSerializer

@extend_schema(
summary="Create a New Author",
description="Creates a new author, launches the required airflow dags.",
request=serializer_class,
)
def create(self, request):
logger.info("Creating workflow with data: %s", request.data)
serializer = self.serializer_class(data=request.data)
Expand All @@ -122,6 +127,35 @@ def create(self, request):
workflow.data,
)

@extend_schema(
summary="Partially Updates Author",
description="Updates specific fields of the author.",
examples=[
OpenApiExample(
"Status Update",
value={
"status": StatusChoices.COMPLETED,
},
),
],
)
def partial_update(self, request, pk=None):
logger.info("Updating workflow with data: %s", request.data)
workflow_instance = get_object_or_404(Workflow, pk=pk)
serializer = self.serializer_class(
workflow_instance, data=request.data, partial=True
)

if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@extend_schema(
summary="Accept or Reject Author",
description="Acceps or rejects an author, run associated dags.",
request=AuthorResolutionSerializer,
)
@action(detail=True, methods=["post"])
def resolve(self, request, pk=None):
logger.info("Resolving data: %s", request.data)
Expand All @@ -138,6 +172,24 @@ def resolve(self, request, pk=None):
ResolutionDags[serializer.validated_data["value"]].label, pk, extra_data
)

@extend_schema(
summary="Restart an Author Workflow",
description="Restart an Author Workflow.",
examples=[
OpenApiExample(
"Restart Whole Workflow",
value={},
),
OpenApiExample(
"Restart Failing Task",
value={"restart_current_task": True},
),
OpenApiExample(
"Restart Workflow with Custom Parameters",
value={"params": {}},
),
],
)
@action(detail=True, methods=["post"])
def restart(self, request, pk=None):
workflow = Workflow.objects.get(id=pk)
Expand All @@ -150,6 +202,44 @@ def restart(self, request, pk=None):
)


@extend_schema_view(
list=extend_schema(
summary="Search with opensearch",
description="text",
parameters=[
OpenApiParameter(
name="search",
description="Search for status and workflow_type",
required=False,
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
),
OpenApiParameter(
name="ordering",
description="order by _updated_at",
required=False,
type=OpenApiTypes.STR,
location=OpenApiParameter.QUERY,
),
OpenApiParameter(
name="status",
description="status",
required=False,
type=OpenApiTypes.STR,
enum=StatusChoices.values,
location=OpenApiParameter.QUERY,
),
OpenApiParameter(
name="workflow_type",
description="workflow_type",
required=False,
type=OpenApiTypes.STR,
enum=WorkflowType.values,
location=OpenApiParameter.QUERY,
),
],
),
)
class WorkflowDocumentView(BaseDocumentViewSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand All @@ -171,7 +261,10 @@ def __init__(self, *args, **kwargs):
"is_update",
}

filter_fields = {"status": "status", "workflow_type": "workflow_type"}
filter_fields = {
"status": "status.keyword",
"workflow_type": "workflow_type.keyword",
}

ordering_fields = {"_updated_at": "_updated_at"}

Expand Down
97 changes: 45 additions & 52 deletions backoffice/backoffice/workflows/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ def test_list_anonymous(self):
self.assertEqual(response.status_code, 403)


# @pytest.mark.usefixtures("rebuild_opensearch_index")
class TestWorkflowSearchViewSet(BaseTransactionTestCase):
endpoint = "/api/workflows/search/"
reset_sequences = True
Expand Down Expand Up @@ -109,56 +108,6 @@ def test_list_anonymous(self):
self.assertEqual(response.status_code, 403)


class TestWorkflowPartialUpdateViewSet(BaseTransactionTestCase):
endpoint_base_url = "/api/workflow-update"
reset_sequences = True
fixtures = ["backoffice/fixtures/groups.json"]

def setUp(self):
super().setUp()
self.workflow = Workflow.objects.create(
data={}, status=StatusChoices.APPROVAL, core=True, is_update=False
)

@property
def endpoint(self):
return f"{self.endpoint_base_url}/{self.workflow.id}/"

def test_patch_curator(self):
self.api_client.force_authenticate(user=self.curator)
response = self.api_client.patch(
self.endpoint, format="json", data={"status": "running"}
)

self.assertEqual(response.status_code, 200)
workflow = Workflow.objects.filter(id=self.workflow.id)[0]
assert workflow.status == "running"

def test_patch_admin(self):
self.api_client.force_authenticate(user=self.admin)
response = self.api_client.patch(
self.endpoint,
format="json",
data={"status": "approval", "data": {"test": "test"}},
)

workflow = Workflow.objects.filter(id=self.workflow.id)[0]
self.assertEqual(response.status_code, 200)
self.assertEqual(workflow.status, "approval")
self.assertEqual(
workflow.data,
{
"test": "test",
},
)

def test_patch_anonymous(self):
self.api_client.force_authenticate(user=self.user)
response = self.api_client.get(self.endpoint, format="json")

self.assertEqual(response.status_code, 403)


class TestWorkflowTicketViewSet(BaseTransactionTestCase):
endpoint = "/api/workflow-ticket"
reset_sequences = True
Expand Down Expand Up @@ -365,6 +314,50 @@ def test_restart_with_params(self):
)
self.assertEqual(response.status_code, 200)

def test_patch_curator(self):
self.api_client.force_authenticate(user=self.curator)
url = reverse(
"api:workflows-authors-detail",
kwargs={"pk": self.workflow.id},
)
response = self.api_client.patch(url, format="json", data={"status": "running"})

self.assertEqual(response.status_code, 200)
workflow = Workflow.objects.filter(id=self.workflow.id)[0]
assert workflow.status == "running"

def test_patch_admin(self):
self.api_client.force_authenticate(user=self.admin)
url = reverse(
"api:workflows-authors-detail",
kwargs={"pk": self.workflow.id},
)
response = self.api_client.patch(
url,
format="json",
data={"status": "approval", "data": {"test": "test"}},
)

workflow = Workflow.objects.filter(id=self.workflow.id)[0]
self.assertEqual(response.status_code, 200)
self.assertEqual(workflow.status, "approval")
self.assertEqual(
workflow.data,
{
"test": "test",
},
)

def test_patch_anonymous(self):
self.api_client.force_authenticate(user=self.user)
url = reverse(
"api:workflows-authors-detail",
kwargs={"pk": self.workflow.id},
)
response = self.api_client.get(url, format="json")

self.assertEqual(response.status_code, 403)


class TestWorkflowSearchFilterViewSet(BaseTransactionTestCase):
endpoint = "/api/workflows/search/"
Expand Down Expand Up @@ -427,7 +420,7 @@ def test_search_workflow_type(self):
def test_filter_status(self):
self.api_client.force_authenticate(user=self.admin)

url = reverse("search:workflow-list") + f'?status="={StatusChoices.RUNNING}'
url = reverse("search:workflow-list") + f"?status={StatusChoices.RUNNING}"

response = self.api_client.get(url)

Expand Down
4 changes: 0 additions & 4 deletions backoffice/config/api_router.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from backoffice.users.api.views import UserViewSet
from backoffice.workflows.api.views import (
AuthorWorkflowViewSet,
WorkflowPartialUpdateViewSet,
WorkflowTicketViewSet,
WorkflowViewSet,
)
Expand All @@ -20,9 +19,6 @@
),
)
router.register("workflows", WorkflowViewSet, basename="workflows")
router.register(
"workflow-update", WorkflowPartialUpdateViewSet, basename="workflow-update"
)
(router.register("workflow-ticket", WorkflowTicketViewSet, basename="workflow-ticket"),)
app_name = "api"
urlpatterns = router.urls
Loading

0 comments on commit 6016924

Please sign in to comment.