Skip to content
Snippets Groups Projects
Commit 01f54571 authored by Valentin Rigal's avatar Valentin Rigal Committed by Erwan Rouchet
Browse files

Prevent updating element type if it has forbidden manual transcriptions

parent a0a6401f
No related branches found
No related tags found
No related merge requests found
......@@ -401,6 +401,12 @@ class ElementRetrieve(RetrieveUpdateDestroyAPIView):
'tags': ['elements'],
}
def get_object(self):
# Prevent duplicating database request
if not hasattr(self, 'element'):
self.element = super().get_object()
return self.element
def get_queryset(self):
corpora = Corpus.objects.readable(self.request.user)
return Element.objects \
......
......@@ -229,6 +229,7 @@ class ElementSerializer(ElementSlimSerializer):
return instance
def update(self, instance, validated_data):
image = validated_data.pop('image', None)
polygon = validated_data.pop('polygon', None)
if polygon or image:
......@@ -248,6 +249,19 @@ class ElementSerializer(ElementSlimSerializer):
instance.zone, _ = image.zones.get_or_create(polygon=polygon)
new_type = validated_data.get('type')
if new_type:
allowed_transcription = instance.type.allowed_transcription
if (allowed_transcription
# Element type has been updated with different annotation permissions
and new_type.allowed_transcription != allowed_transcription
# And a manual transcription exists
and instance.transcriptions.filter(source__slug='manual', type=allowed_transcription).exists()):
raise ValidationError({'type': [
'The updated type does not allow the element to keep its '
f'manual {allowed_transcription.value} transcriptions'
]})
instance = super().update(instance, validated_data)
return instance
......
......@@ -20,8 +20,10 @@ class TestElementsAPI(FixtureAPITestCase):
cls.volume_type = cls.corpus.types.get(slug='volume')
cls.page_type = cls.corpus.types.get(slug='page')
cls.act_type = cls.corpus.types.get(slug='act')
cls.line_type = cls.corpus.types.get(slug='text_line')
cls.vol = cls.corpus.elements.get(name='Volume 1')
cls.element = Element.objects.get(name='Volume 1, page 2r')
cls.line = cls.corpus.elements.get(name='Text line')
cls.image = ImageServer.objects.local.images.create(
path="kingdom/far/away",
status=S3FileStatus.Checked,
......@@ -30,6 +32,7 @@ class TestElementsAPI(FixtureAPITestCase):
)
cls.private_corpus = Corpus.objects.create(name='private', public=False)
cls.private_elt = cls.private_corpus.elements.create(type=cls.private_corpus.types.create(slug='type'))
cls.manual_source = DataSource.objects.create(type=MLToolType.Recognizer, slug='manual', internal=True)
def setUp(self):
self.page = self.corpus.elements.get(name='Volume 1, page 1r')
......@@ -150,11 +153,12 @@ class TestElementsAPI(FixtureAPITestCase):
def test_patch_element(self):
self.client.force_login(self.user)
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.vol.id)}),
data={'name': 'Untitled (2)'},
format='json',
)
with self.assertNumQueries(10):
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.vol.id)}),
data={'name': 'Untitled (2)'},
format='json',
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.json()['name'], 'Untitled (2)')
self.vol.refresh_from_db()
......@@ -261,6 +265,70 @@ class TestElementsAPI(FixtureAPITestCase):
self.assertEqual(self.vol.zone.polygon.width, 20)
self.assertEqual(self.vol.zone.polygon.height, 10)
def test_element_patch_type_allowed_transcription(self):
"""
The base number of requests is increased by 1 because
of the check on the given type allowed transcriptions
"""
self.client.force_login(self.user)
with self.assertNumQueries(11):
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.vol.id)}),
data={'type': self.line_type.slug, 'name': 'Text line'},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_element_patch_type_with_allowed_transcription(self):
"""
Update an element with a type previously allowing a manual transcription
The base number of requests is increased by 2 because of the checks on the
given type allowed transcriptions and the element manual transcriptions existence
"""
self.client.force_login(self.user)
with self.assertNumQueries(12):
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.line.id)}),
data={'type': self.volume_type.slug, 'name': 'Text line'},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
def test_element_patch_type_no_allowed_transcription(self):
"""
Patching the element type must be forbidden if it has manual transcriptions
"""
self.line.transcriptions.create(text='A line', type=TranscriptionType.Line, source=self.manual_source)
self.client.force_login(self.user)
with self.assertNumQueries(9):
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.line.id)}),
data={'type': self.page_type.slug},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {
'type': ['The updated type does not allow the element to keep its manual line transcriptions']
})
def test_element_patch_type_same_allowed_transcription(self):
"""
Allows patching the element with a type allowing the same manual transcriptions
"""
self.line.transcriptions.create(text='A line', type=TranscriptionType.Line, source=self.manual_source)
self.element.type.allowed_transcription = TranscriptionType.Line
self.element.type.save()
self.client.force_login(self.user)
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.line.id)}),
data={'type': self.page_type.slug},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.json().get('type'), 'page')
def make_create_request(self, name='default', corpus=None, elt_type='volume', **options):
request = {
'path': reverse('api:elements-create'),
......
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