Skip to content
Snippets Groups Projects
Commit 14334375 authored by Bastien Abadie's avatar Bastien Abadie
Browse files

Merge branch 'destroy-mlclass' into 'master'

Add DestroyMLClass endpoint

Closes #768

See merge request !1368
parents 5073ed0d f761750b
No related branches found
No related tags found
1 merge request!1368Add DestroyMLClass endpoint
......@@ -6,7 +6,13 @@ from django.db.models import Count, Q
from drf_spectacular.utils import PolymorphicProxySerializer, extend_schema, extend_schema_view
from rest_framework import permissions, status
from rest_framework.exceptions import PermissionDenied, ValidationError
from rest_framework.generics import CreateAPIView, GenericAPIView, ListCreateAPIView, RetrieveUpdateDestroyAPIView
from rest_framework.generics import (
CreateAPIView,
DestroyAPIView,
GenericAPIView,
ListCreateAPIView,
RetrieveUpdateDestroyAPIView,
)
from rest_framework.response import Response
from arkindex.documents.models import (
......@@ -365,6 +371,23 @@ class CorpusMLClassList(CorpusACLMixin, ListCreateAPIView):
return context
@extend_schema(tags=['classifications'], responses=None)
class MLClassDestroy(CorpusACLMixin, DestroyAPIView):
"""
Delete an ML class if it is not used by any classification.
"""
queryset = MLClass.objects.none()
permission_classes = (IsVerified, )
lookup_url_kwarg = 'mlclass'
def get_queryset(self):
return MLClass.objects.filter(corpus=self.get_corpus(self.kwargs['corpus'], role=Role.Contributor))
def check_object_permissions(self, request, obj):
if obj.classifications.count() != 0:
raise ValidationError(['This ML class is used by some classifications on this corpus.'])
@extend_schema(tags=['classifications'])
class ClassificationCreate(CreateAPIView):
"""
......
......@@ -5,6 +5,7 @@ from rest_framework import status
from arkindex.dataimport.models import WorkerVersion
from arkindex.documents.models import Classification, ClassificationState, Corpus, Element, MLClass
from arkindex.project.tests import FixtureAPITestCase
from arkindex.users.models import Role
class TestClasses(FixtureAPITestCase):
......@@ -214,6 +215,39 @@ class TestClasses(FixtureAPITestCase):
'non_field_errors': ['The fields name, corpus must make a unique set.']
})
def test_destroy(self):
self.client.force_login(self.superuser)
self.text.classifications.all().delete()
response = self.client.delete(reverse('api:ml-class-destroy', kwargs={'corpus': self.corpus.id, 'mlclass': self.text.id}))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
with self.assertRaises(MLClass.DoesNotExist):
self.text.refresh_from_db()
def test_destroy_non_empty(self):
self.client.force_login(self.superuser)
self.assertTrue(self.text.classifications.exists())
response = self.client.delete(reverse('api:ml-class-destroy', kwargs={'corpus': self.corpus.id, 'mlclass': self.text.id}))
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertListEqual(response.json(), ['This ML class is used by some classifications on this corpus.'])
def test_destroy_requires_login(self):
response = self.client.delete(reverse('api:ml-class-destroy', kwargs={'corpus': self.corpus.id, 'mlclass': self.text.id}))
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_destroy_requires_verified(self):
self.user.verified_email = False
self.user.save()
self.client.force_login(self.user)
response = self.client.delete(reverse('api:ml-class-destroy', kwargs={'corpus': self.corpus.id, 'mlclass': self.text.id}))
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
def test_destroy_requires_contributor(self):
self.user.rights.update(level=Role.Guest.value)
self.client.force_login(self.user)
response = self.client.delete(reverse('api:ml-class-destroy', kwargs={'corpus': self.corpus.id, 'mlclass': self.text.id}))
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertDictEqual(response.json(), {'detail': 'You do not have contributor access to this corpus.'})
def test_list_elements_db_queries(self):
with self.assertNumQueries(5):
response = self.client.get(
......
......@@ -74,6 +74,7 @@ from arkindex.documents.api.ml import (
CorpusMLClassList,
ElementTranscriptionsBulk,
ManageClassificationsSelection,
MLClassDestroy,
TranscriptionBulk,
TranscriptionCreate,
TranscriptionEdit,
......@@ -136,6 +137,7 @@ api = [
# `corpus` and not `pk` so that OpenAPI uses a `corpus` parameter
path('corpus/<uuid:corpus>/elements/', CorpusElements.as_view(), name='corpus-elements'),
path('corpus/<uuid:pk>/classes/', CorpusMLClassList.as_view(), name='corpus-classes'),
path('corpus/<uuid:corpus>/classes/<uuid:mlclass>/', MLClassDestroy.as_view(), name='ml-class-destroy'),
path('corpus/<uuid:pk>/entities/', CorpusEntities.as_view(), name='corpus-entities'),
path('corpus/<uuid:pk>/roles/', CorpusRoles.as_view(), name='corpus-roles'),
path('corpus/<uuid:pk>/allowed-metadata/', CorpusAllowedMetaData.as_view(), name='corpus-allowed-metadata'),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment