diff --git a/backoffice/backoffice/workflows/admin.py b/backoffice/backoffice/workflows/admin.py index bc5c3d64..d870fd85 100644 --- a/backoffice/backoffice/workflows/admin.py +++ b/backoffice/backoffice/workflows/admin.py @@ -3,7 +3,7 @@ from django_json_widget.widgets import JSONEditorWidget from backoffice.management.permissions import IsAdminOrCuratorUser -from backoffice.workflows.models import Decision, Workflow +from backoffice.workflows.models import Decision, Workflow, WorkflowTicket class WorkflowsAdminSite(admin.AdminSite): @@ -78,6 +78,17 @@ def action_value(self, obj): return obj.action +class WorkflowTicketsInline(admin.StackedInline): + model = WorkflowTicket + extra = 0 + can_delete = False + show_change_link = True + readonly_fields = ["ticket_id", "ticket_type", "_updated_at"] + + def has_change_permission(self, request, obj=None): + return False + + @admin.register(Workflow) class WorkflowAdmin(BaseModelAdmin): """ @@ -104,7 +115,7 @@ class WorkflowAdmin(BaseModelAdmin): "_updated_at", ] - inlines = [WorkflowsDecisionsInline] + inlines = [WorkflowsDecisionsInline, WorkflowTicketsInline] @admin.register(Decision) @@ -124,3 +135,15 @@ class DecisionAdmin(BaseModelAdmin): @admin.display(description="action") def action_value(self, obj): return obj.action + + +@admin.register(WorkflowTicket) +class WorkflowTicketAdmin(BaseModelAdmin): + """ + Admin class for WorkflowTicket model. Define get, update and delete permissions. + """ + + ordering = ("-_updated_at",) + search_fields = ["id", "ticket_id"] + list_display = ("id", "ticket_id", "ticket_type", "workflow_id") + list_filter = ["workflow_id", "ticket_type"] diff --git a/backoffice/backoffice/workflows/api/serializers.py b/backoffice/backoffice/workflows/api/serializers.py index bf7bf9f5..b7c2b60f 100644 --- a/backoffice/backoffice/workflows/api/serializers.py +++ b/backoffice/backoffice/workflows/api/serializers.py @@ -11,7 +11,7 @@ class WorkflowTicketSerializer(serializers.ModelSerializer): ticket_url = serializers.SerializerMethodField() - workflow_id = serializers.PrimaryKeyRelatedField(queryset=Workflow.objects.all()) + workflow = serializers.PrimaryKeyRelatedField(queryset=Workflow.objects.all()) class Meta: model = WorkflowTicket diff --git a/backoffice/backoffice/workflows/api/views.py b/backoffice/backoffice/workflows/api/views.py index 0fe41ca5..285c635b 100644 --- a/backoffice/backoffice/workflows/api/views.py +++ b/backoffice/backoffice/workflows/api/views.py @@ -26,6 +26,7 @@ from backoffice.workflows.api import utils from backoffice.workflows.api.serializers import ( AuthorResolutionSerializer, + DecisionSerializer, WorkflowAuthorSerializer, WorkflowDocumentSerializer, WorkflowSerializer, @@ -58,8 +59,9 @@ def perform_destroy(self, instance): super().perform_destroy(instance) -class WorkflowTicketViewSet(viewsets.ViewSet): +class WorkflowTicketViewSet(viewsets.ModelViewSet): serializer_class = WorkflowTicketSerializer + queryset = WorkflowTicket.objects.all() def retrieve(self, request, *args, **kwargs): workflow_id = kwargs.get("pk") @@ -67,13 +69,13 @@ def retrieve(self, request, *args, **kwargs): if not workflow_id or not ticket_type: return Response( - {"error": "Both workflow_id and ticket_type are required."}, + {"error": "Both workflow and ticket_type are required."}, status=status.HTTP_400_BAD_REQUEST, ) try: workflow_ticket = WorkflowTicket.objects.get( - workflow_id=workflow_id, ticket_type=ticket_type + workflow=workflow_id, ticket_type=ticket_type ) serializer = self.serializer_class(workflow_ticket) return Response(serializer.data) @@ -92,6 +94,7 @@ def create(self, request, *args, **kwargs): class DecisionViewSet(viewsets.ModelViewSet): + serializer_class = DecisionSerializer queryset = Decision.objects.all() def create(self, request, *args, **kwargs): diff --git a/backoffice/backoffice/workflows/migrations/0011_rename_workflow_id_workflowticket_workflow_and_more.py b/backoffice/backoffice/workflows/migrations/0011_rename_workflow_id_workflowticket_workflow_and_more.py new file mode 100644 index 00000000..4b89b717 --- /dev/null +++ b/backoffice/backoffice/workflows/migrations/0011_rename_workflow_id_workflowticket_workflow_and_more.py @@ -0,0 +1,31 @@ +# Generated by Django 4.2.6 on 2024-08-28 11:59 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("workflows", "0010_alter_decision_workflow_and_more"), + ] + + operations = [ + migrations.RenameField( + model_name="workflowticket", + old_name="workflow_id", + new_name="workflow", + ), + migrations.AddField( + model_name="workflowticket", + name="_created_at", + field=models.DateTimeField( + auto_now_add=True, default=django.utils.timezone.now + ), + preserve_default=False, + ), + migrations.AddField( + model_name="workflowticket", + name="_updated_at", + field=models.DateTimeField(auto_now=True), + ), + ] diff --git a/backoffice/backoffice/workflows/models.py b/backoffice/backoffice/workflows/models.py index d4fb3704..3dfb7cb3 100644 --- a/backoffice/backoffice/workflows/models.py +++ b/backoffice/backoffice/workflows/models.py @@ -36,7 +36,7 @@ class Workflow(models.Model): class WorkflowTicket(models.Model): - workflow_id = models.ForeignKey( + workflow = models.ForeignKey( Workflow, related_name="tickets", on_delete=models.CASCADE ) ticket_id = models.CharField( @@ -45,6 +45,8 @@ class WorkflowTicket(models.Model): ticket_type = models.CharField( max_length=30, choices=TICKET_TYPES, default=DEFAULT_TICKET_TYPE ) + _created_at = models.DateTimeField(auto_now_add=True) + _updated_at = models.DateTimeField(auto_now=True) class Decision(models.Model): diff --git a/backoffice/backoffice/workflows/tests/test_views.py b/backoffice/backoffice/workflows/tests/test_views.py index 0f6ff9a5..79ef1f0f 100644 --- a/backoffice/backoffice/workflows/tests/test_views.py +++ b/backoffice/backoffice/workflows/tests/test_views.py @@ -93,7 +93,7 @@ def test_list_anonymous(self): def test_tickets(self): WorkflowTicket.objects.create( - workflow_id=self.workflow, ticket_id="123", ticket_type="author_create_user" + workflow=self.workflow, ticket_id="123", ticket_type="author_create_user" ) workflow_data = WorkflowSerializer(self.workflow).data @@ -242,7 +242,7 @@ def setUp(self): data={}, status="running", core=True, is_update=False ) self.workflow_ticket = WorkflowTicket.objects.create( - workflow_id=self.workflow, ticket_id="123", ticket_type="author_create_user" + workflow=self.workflow, ticket_id="123", ticket_type="author_create_user" ) def test_get_missing_params(self): @@ -254,9 +254,7 @@ def test_get_missing_params(self): ) assert response.status_code == 400 - assert response.data == { - "error": "Both workflow_id and ticket_type are required." - } + assert response.data == {"error": "Both workflow and ticket_type are required."} def test_get_ticket_not_found(self): query_params = {"ticket_type": "test"} @@ -294,7 +292,7 @@ def test_create_missing_params(self): assert response.status_code == 400 assert response.json() == { - "workflow_id": ["This field is required."], + "workflow": ["This field is required."], "ticket_id": ["This field is required."], } @@ -302,7 +300,7 @@ def test_create_happy_flow(self): self.api_client.force_authenticate(user=self.curator) data = { - "workflow_id": self.workflow.id, + "workflow": self.workflow.id, "ticket_id": "dc94caad1b4f71502d06117a3b4bcb25", "ticket_type": "author_create_user", } @@ -312,7 +310,7 @@ def test_create_happy_flow(self): assert response.status_code == 201 - assert "workflow_id" in response.data + assert "workflow" in response.data assert "ticket_id" in response.data assert "ticket_type" in response.data