Skip to content
Snippets Groups Projects
Verified Commit 046fbc2a authored by Erwan Rouchet's avatar Erwan Rouchet
Browse files

Add image field on element update APIs

parent ee891c6f
No related branches found
No related tags found
1 merge request!686Add image field on element update APIs
......@@ -212,11 +212,24 @@ class ElementSerializer(ElementSlimSerializer):
metadata = serializers.SerializerMethodField()
classifications = ClassificationSerializer(many=True, read_only=True)
polygon = PolygonField(required=False)
image = serializers.PrimaryKeyRelatedField(
queryset=Image.objects.all(),
required=False,
write_only=True,
help_text='Link this element to an image by UUID via a polygon. '
'When the image is updated, if there was an image before and the polygon is not updated, '
'the previous polygon is reused. Otherwise, a polygon filling the new image is used.'
)
polygon = PolygonField(
required=False,
write_only=True,
help_text='Set the polygon linking this element to the image. '
'`image` must be set when this field is set and there was no image or polygon defined before.',
)
class Meta:
model = Element
fields = ElementSlimSerializer.Meta.fields + ('metadata', 'classifications', 'polygon')
fields = ElementSlimSerializer.Meta.fields + ('metadata', 'classifications', 'image', 'polygon')
read_only_fields = ElementSlimSerializer.Meta.read_only_fields + ('metadata', 'classifications')
def create(self, *args, **kwargs):
......@@ -225,16 +238,25 @@ 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:
if not instance.zone:
raise ValidationError({
'polygon': ['Zone not found']
})
zone, _ = instance.zone.image.zones.get_or_create(
polygon=polygon,
)
instance.zone = zone
if polygon or image:
if not image:
if not instance.zone:
# A polygon was set but there is no image
raise ValidationError({
'image': ['Image is required when defining a polygon on an element without an existing zone'],
})
image = instance.zone.image
if not polygon:
if instance.zone:
polygon = instance.zone.polygon
else:
polygon = Polygon.from_coords(0, 0, image.width, image.height)
instance.zone, _ = image.zones.get_or_create(polygon=polygon)
instance = super().update(instance, validated_data)
instance.events.create(type=EventType.Edit)
return instance
......
......@@ -190,6 +190,7 @@ class TestElementsAPI(FixtureAPITestCase):
def test_patch_element_polygon(self):
self.client.force_login(self.user)
self.assertIsNotNone(self.element.zone)
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.element.id)}),
data={
......@@ -206,9 +207,10 @@ class TestElementsAPI(FixtureAPITestCase):
self.assertEqual(self.element.zone.polygon.width, 20)
self.assertEqual(self.element.zone.polygon.height, 10)
def test_patch_element_polygon_wrong_zone(self):
def test_patch_element_polygon_without_image(self):
self.client.force_login(self.user)
self.assertIsNone(self.vol.zone)
self.vol.zone = None
self.vol.save()
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.vol.id)}),
data={
......@@ -217,7 +219,44 @@ class TestElementsAPI(FixtureAPITestCase):
format='json',
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertEqual(response.json()['polygon'], ['Zone not found'])
self.assertDictEqual(response.json(), {
'image': ['Image is required when defining a polygon on an element without an existing zone']
})
def test_patch_element_image_preserve_polygon(self):
self.client.force_login(self.user)
self.assertNotEqual(self.element.zone.image, self.image)
expected_polygon = self.element.zone.polygon.copy()
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.element.id)}),
data={
'image': str(self.image.id),
},
format='json',
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.element.refresh_from_db()
self.assertEqual(self.element.zone.image, self.image)
self.assertEqual(self.element.zone.polygon, expected_polygon)
def test_patch_element_new_zone(self):
self.client.force_login(self.user)
self.assertIsNone(self.vol.zone)
response = self.client.patch(
reverse('api:element-retrieve', kwargs={'pk': str(self.vol.id)}),
data={
'image': str(self.image.id),
'polygon': [[10, 20], [10, 30], [30, 30], [30, 20], [10, 20]],
},
format='json',
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.vol.refresh_from_db()
self.assertEqual(self.vol.zone.image, self.image)
self.assertEqual(self.vol.zone.polygon.x, 10)
self.assertEqual(self.vol.zone.polygon.y, 20)
self.assertEqual(self.vol.zone.polygon.width, 20)
self.assertEqual(self.vol.zone.polygon.height, 10)
def make_create_request(self, name='default', corpus=None, elt_type='volume', **options):
request = {
......
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