feat/PRWLR-4177 Add /tasks endpoints and data model (#35)

* feat(Backend): PRWLR-4177 add Task model and migrations

* feat(Tasks): PRWLR-4177 add RLSTask class

* feat(API): PRWLR-4177 add Task serializers

* feat(Backend, DB): PRWLR-4177 refactor db variables and add policy on task runner tasks

* feat(API): PRWLR-4177 add Tasks filters and sort fields

* feat(API, Tasks): PRWLR-4177 add deletion tasks and revoke logic to /tasks

* test(Task): PRWLR-4177 add deletion tasks unit tests

* test(Views): PRWLR-4177 add Tasks views unit tests and update outdated ones

* chore(API): PRWLR-4177 improve drf-spectacular annotations

* chore(API): PRWLR-4177 add PROGRESS task state

* chore(API): PRWLR-4177 update spec

* chore(API): PRWLR-4177 remove force query parameter from DELETE /tasks

* feat(Backend): PRWLR-4177 add APITimeoutError and raise when TaskResult is not created

* feat(Backend): PRWLR-4177 add specific error class for task timeouts
This commit is contained in:
Víctor Fernández Poyatos authored and GitHub committed 2024-09-06 20:47:51 -04:00
1 parent f5462c9b27
commit ec67fc12e0
15 files changed
+1426 -161

No files matched your search

+88 -8
View File
@@ -1,8 +1,10 @@
import json
from drf_spectacular.utils import extend_schema_field
from rest_framework_json_api import serializers
from rest_framework_json_api.serializers import ValidationError
from api.models import StateChoices, Provider, Scan
from api.models import StateChoices, Provider, Scan, Task
from api.rls import Tenant
from api.utils import merge_dicts
@@ -39,17 +41,95 @@ class StateEnumSerializerField(serializers.ChoiceField):
# Tasks
class DelayedTaskSerializer(serializers.Serializer):
id = serializers.CharField()
status = serializers.CharField()
class TaskBase(serializers.Serializer):
state_mapping = {
"PENDING": StateChoices.SCHEDULED,
"STARTED": StateChoices.EXECUTING,
"PROGRESS": StateChoices.EXECUTING,
"SUCCESS": StateChoices.COMPLETED,
"FAILURE": StateChoices.FAILED,
"REVOKED": StateChoices.CANCELLED,
}
class JSONAPIMeta:
resource_name = "Task"
def to_representation(self, obj):
return {"id": obj.id, "status": obj.status}
def map_state(self, task_result_state):
return self.state_mapping.get(task_result_state, StateChoices.AVAILABLE)
@extend_schema_field(
{
"type": "string",
"enum": StateChoices.values,
}
)
def get_state(self, obj):
task_result_state = (
obj.task_runner_task.status if obj.task_runner_task else None
)
return self.map_state(task_result_state)
class DelayedTaskSerializer(TaskBase):
id = serializers.CharField()
state = serializers.SerializerMethodField(read_only=True)
class Meta:
fields = [
"id",
"state",
]
@extend_schema_field(
{
"type": "string",
"enum": StateChoices.values,
}
)
def get_state(self, obj):
task_result_state = obj.status if obj else None
return self.map_state(task_result_state)
class TaskSerializer(RLSSerializer, TaskBase):
state = serializers.SerializerMethodField(read_only=True)
metadata = serializers.SerializerMethodField(read_only=True)
result = serializers.SerializerMethodField(read_only=True)
completed_at = serializers.DateTimeField(
source="task_runner_task.date_done", read_only=True
)
name = serializers.CharField(source="task_runner_task.task_name", read_only=True)
class Meta:
model = Task
fields = [
"id",
"inserted_at",
"completed_at",
"name",
"state",
"result",
"metadata",
]
@extend_schema_field(serializers.JSONField())
def get_metadata(self, obj):
return self.get_json_field(obj, "metadata")
@extend_schema_field(serializers.JSONField())
def get_result(self, obj):
return self.get_json_field(obj, "result")
@staticmethod
def get_json_field(obj, field_name):
"""Helper method to DRY the logic for loading JSON fields from task_runner_task."""
task_result_field = (
getattr(obj.task_runner_task, field_name, None)
if obj.task_runner_task
else None
)
return json.loads(task_result_field) if task_result_field else {}
# Tenants