From 281fc11968c9827476b8e19212dd4c7714dfe977 Mon Sep 17 00:00:00 2001 From: Erwan Rouchet <rouchet@teklia.com> Date: Fri, 20 Nov 2020 11:50:12 +0100 Subject: [PATCH] Add ListCorpusWorkerVersions endpoint --- arkindex/dataimport/api.py | 23 ++++++++- arkindex/dataimport/serializers/workers.py | 2 + arkindex/dataimport/tests/test_workers.py | 57 ++++++++++++++++++++++ arkindex/project/api_v1.py | 2 + 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/arkindex/dataimport/api.py b/arkindex/dataimport/api.py index bff4120c4d..c2e78e385d 100644 --- a/arkindex/dataimport/api.py +++ b/arkindex/dataimport/api.py @@ -4,7 +4,7 @@ from uuid import UUID from django.conf import settings from django.core.exceptions import PermissionDenied from django.db import transaction -from django.db.models import F, Max, Q +from django.db.models import Count, F, Max, Q from django.http.response import Http404 from django.shortcuts import get_object_or_404 from rest_framework import status @@ -743,6 +743,27 @@ class WorkerVersionList(ListCreateAPIView): return Response(WorkerVersionSerializer(version).data, status=reponse_status) +class CorpusWorkerVersionList(CorpusACLMixin, ListAPIView): + """ + List worker versions used by elements of a given corpus. + """ + permission_classes = (IsVerified, ) + pagination_class = None + serializer_class = WorkerVersionSerializer + openapi_overrides = { + 'operationId': 'ListCorpusWorkerVersions', + 'tags': ['ml'], + } + + def get_queryset(self): + return WorkerVersion.objects \ + .filter(elements__corpus_id=self.kwargs['pk']) \ + .select_related('revision__repo', 'worker__repository') \ + .prefetch_related('revision__refs', 'revision__versions') \ + .order_by('-revision__created') \ + .annotate(element_count=Count('id')) + + class WorkerVersionRetrieve(CorpusACLMixin, RetrieveUpdateAPIView): """ Retrieve a specific worker version diff --git a/arkindex/dataimport/serializers/workers.py b/arkindex/dataimport/serializers/workers.py index 8033ca88c2..4f3031a56b 100644 --- a/arkindex/dataimport/serializers/workers.py +++ b/arkindex/dataimport/serializers/workers.py @@ -34,6 +34,7 @@ class WorkerVersionSerializer(serializers.ModelSerializer): # ModelSerializer does not yet support Django 3.1's JSONField # https://github.com/encode/django-rest-framework/pull/7467 configuration = serializers.JSONField() + element_count = serializers.IntegerField(read_only=True) class Meta: model = WorkerVersion @@ -46,6 +47,7 @@ class WorkerVersionSerializer(serializers.ModelSerializer): 'docker_image_name', 'state', 'worker', + 'element_count', ) read_only_fields = ('docker_image_name',) # Avoid loading all revisions and all Ponos artifacts when opening this endpoint in a browser diff --git a/arkindex/dataimport/tests/test_workers.py b/arkindex/dataimport/tests/test_workers.py index 47754685d4..5f21c58a96 100644 --- a/arkindex/dataimport/tests/test_workers.py +++ b/arkindex/dataimport/tests/test_workers.py @@ -1,3 +1,5 @@ +from unittest import expectedFailure + from django.urls import reverse from rest_framework import status @@ -489,3 +491,58 @@ class TestWorkersWorkerVersions(FixtureAPITestCase): self.version_1.configuration = {'docker': {'command': 'mysupercommand'}} self.assertEqual(self.version_1.docker_command, 'mysupercommand') self.version_1.configuration = {"test": "test1"} + + def test_corpus_worker_version_requires_login(self): + with self.assertNumQueries(0): + response = self.client.get(reverse('api:corpus-versions', kwargs={'pk': self.corpus.id})) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + @expectedFailure + def test_corpus_worker_version_requires_verified(self): + """ + This test fails due to a bug in the IsVerified permission class. + https://gitlab.com/arkindex/backend/-/issues/554 + """ + self.user.verified_email = False + self.user.save() + self.client.force_login(self.user) + with self.assertNumQueries(2): + response = self.client.get(reverse('api:corpus-versions', kwargs={'pk': self.corpus.id})) + self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) + + def test_corpus_worker_version_list(self): + self.client.force_login(self.user) + + self.corpus.elements.filter(type__slug='word').update(worker_version=self.version_1) + + with self.assertNumQueries(5): + response = self.client.get(reverse('api:corpus-versions', kwargs={'pk': self.corpus.id})) + self.assertEqual(response.status_code, status.HTTP_200_OK) + + self.assertListEqual(response.json(), [ + { + 'id': str(self.version_1.id), + 'configuration': {'test': 42}, + 'revision': { + 'id': str(self.version_1.revision_id), + 'state': 'available', + 'hash': '1337', + 'author': 'Test user', + 'message': 'My w0rk3r', + 'created': '2020-02-02T01:23:45.678000Z', + 'commit_url': 'http://my_repo.fake/workers/worker/commit/1337', + 'refs': [] + }, + 'docker_image': str(self.version_1.docker_image_id), + 'docker_image_iid': None, + 'docker_image_name': self.version_1.docker_image_name, + 'state': 'available', + 'worker': { + 'id': str(self.worker_1.id), + 'name': 'Recognizer', + 'slug': 'reco', + 'type': 'recognizer' + }, + 'element_count': 9 + } + ]) diff --git a/arkindex/project/api_v1.py b/arkindex/project/api_v1.py index be8ade7bc3..1dd403b540 100644 --- a/arkindex/project/api_v1.py +++ b/arkindex/project/api_v1.py @@ -6,6 +6,7 @@ from rest_framework.schemas import get_schema_view from arkindex.dataimport.api import ( AvailableRepositoriesList, + CorpusWorkerVersionList, CorpusWorkflow, DataFileCreate, DataFileList, @@ -139,6 +140,7 @@ api = [ path('corpus/<uuid:pk>/roles/', CorpusRoles.as_view(), name='corpus-roles'), path('corpus/<uuid:pk>/ml-stats/', CorpusMLStats.as_view(), name='corpus-ml-stats'), path('corpus/<uuid:pk>/allowed-metadata/', CorpusAllowedMetaData.as_view(), name='corpus-allowed-metadata'), + path('corpus/<uuid:pk>/versions/', CorpusWorkerVersionList.as_view(), name='corpus-versions'), # Moderation path('ml-classes/', MLClassList.as_view(), name='mlclass-list'), -- GitLab