Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • arkindex/backend
1 result
Show changes
Commits on Source (2)
......@@ -1096,13 +1096,17 @@ class WorkerRunList(WorkerACLMixin, ListCreateAPIView):
if not self.has_execution_access(worker):
raise ValidationError({'worker_version_id': ['You do not have an execution access to this version.']})
configuration = serializer.validated_data.pop('configuration_id', None)
if configuration and configuration.worker_id != worker.id:
raise ValidationError({'configuration_id': ['The configuration must be part of the same worker.']})
if process.mode != DataImportMode.Workers:
raise ValidationError({'dataimport': ['Import mode must be Workers']})
if process.workflow_id is not None:
raise ValidationError({'__all__': ["Cannot create a WorkerRun on a DataImport that has already started"]})
serializer.save(dataimport=process)
serializer.save(dataimport=process, configuration=configuration)
@extend_schema(tags=['imports'])
......@@ -1154,6 +1158,13 @@ class WorkerRunDetails(CorpusACLMixin, RetrieveUpdateDestroyAPIView):
instance.dataimport.worker_runs.filter(parents__contains=[instance.id]).update(parents=ArrayRemove('parents', instance.id))
return super().perform_destroy(instance)
def perform_update(self, serializer):
worker = serializer.instance.version.worker
configuration = serializer.validated_data.get('configuration_id', None)
if configuration and configuration.worker_id != worker.id:
raise ValidationError({'configuration_id': ['The configuration must be part of the same worker.']})
super().perform_update(serializer)
@extend_schema_view(post=extend_schema(
operation_id='CreateImportTranskribus',
......
......@@ -4,7 +4,14 @@ from django.conf import settings
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from arkindex.dataimport.models import ActivityState, DataFile, DataImport, DataImportMode, WorkerRun
from arkindex.dataimport.models import (
ActivityState,
DataFile,
DataImport,
DataImportMode,
WorkerConfiguration,
WorkerRun,
)
from arkindex.dataimport.serializers.git import RevisionSerializer
from arkindex.dataimport.serializers.workers import WorkerLightSerializer
from arkindex.documents.models import Corpus, Element, ElementType
......@@ -322,8 +329,7 @@ class WorkerRunSerializer(serializers.ModelSerializer):
worker_version_id = serializers.UUIDField(source='version_id')
# Serialize worker with its basic informations
worker = WorkerLightSerializer(source='version.worker', read_only=True)
# A DictField will require valid dicts, but without a child= argument, it will allow any value
configuration = serializers.DictField(source='old_configuration', allow_empty=True, default={})
configuration_id = serializers.PrimaryKeyRelatedField(queryset=WorkerConfiguration.objects.all(), required=False, allow_null=True)
class Meta:
model = WorkerRun
......@@ -334,7 +340,7 @@ class WorkerRunSerializer(serializers.ModelSerializer):
'worker_version_id',
'dataimport_id',
'worker',
'configuration',
'configuration_id',
)
......
......@@ -36,6 +36,9 @@ class TestWorkerRuns(FixtureAPITestCase):
cls.worker_1 = cls.version_1.worker
cls.repo = cls.worker_1.repository
cls.run_1 = cls.dataimport_1.worker_runs.create(version=cls.version_1, parents=[])
cls.configuration_1 = cls.worker_1.configurations.create(name="My config", configuration={"key": "value"})
worker_version = WorkerVersion.objects.exclude(worker=cls.version_1.worker).first()
cls.configuration_2 = worker_version.worker.configurations.create(name="Config")
cls.dataimport_2 = cls.corpus.imports.create(creator=cls.user, mode=DataImportMode.Workers)
# Add an execution access right on the worker
cls.worker_1.memberships.create(user=cls.user, level=Role.Contributor.value)
......@@ -73,7 +76,7 @@ class TestWorkerRuns(FixtureAPITestCase):
'type': self.worker_1.type,
'slug': self.worker_1.slug,
},
'configuration': {},
'configuration_id': None,
}])
def test_runs_list_filter_dataimport(self):
......@@ -177,7 +180,7 @@ class TestWorkerRuns(FixtureAPITestCase):
'type': self.worker_1.type,
'slug': self.worker_1.slug,
},
'configuration': {},
'configuration_id': None,
})
def test_runs_post_via_repository_right(self):
......@@ -207,18 +210,13 @@ class TestWorkerRuns(FixtureAPITestCase):
def test_create_run_configuration(self):
self.client.force_login(self.user)
with self.assertNumQueries(14):
with self.assertNumQueries(15):
response = self.client.post(
reverse('api:worker-run-list', kwargs={'pk': str(self.dataimport_2.id)}),
data={
'worker_version_id': str(self.version_1.id),
'parents': [],
'configuration': {
'a': 'b',
'c': {
'd': 42
}
}
'configuration_id': str(self.configuration_1.id)
},
format='json'
)
......@@ -237,35 +235,17 @@ class TestWorkerRuns(FixtureAPITestCase):
'type': self.worker_1.type,
'slug': self.worker_1.slug,
},
'configuration': {
'a': 'b',
'c': {
'd': 42
}
}
'configuration_id': str(self.configuration_1.id)
})
def test_create_run_configuration_object(self):
def test_create_run_invalid_configuration(self):
self.client.force_login(self.user)
parameters = [
(1, 'Expected a dictionary of items but got type "int".'),
([], 'Expected a dictionary of items but got type "list".'),
('a', 'Expected a dictionary of items but got type "str".'),
(None, 'This field may not be null.'),
]
for configuration, message in parameters:
with self.subTest(configuration=configuration), self.assertNumQueries(2):
response = self.client.post(
reverse('api:worker-run-list', kwargs={'pk': str(self.dataimport_2.id)}),
data={
'worker_version_id': str(self.version_1.id),
'parents': [],
'configuration': configuration,
},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {'configuration': [message]})
response = self.client.post(
reverse('api:worker-run-list', kwargs={'pk': str(self.dataimport_2.id)}),
data={'worker_version_id': str(self.version_1.id), 'parents': [], 'configuration_id': str(self.configuration_2.id)}, format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {'configuration_id': ['The configuration must be part of the same worker.']})
def test_retrieve_run_requires_login(self):
response = self.client.get(reverse('api:worker-run-details', kwargs={'pk': str(self.run_1.id)}))
......@@ -307,7 +287,7 @@ class TestWorkerRuns(FixtureAPITestCase):
'type': self.worker_1.type,
'slug': self.worker_1.slug,
},
'configuration': {},
'configuration_id': None,
})
def test_update_run_requires_login(self):
......@@ -430,53 +410,36 @@ class TestWorkerRuns(FixtureAPITestCase):
'type': self.worker_1.type,
'slug': self.worker_1.slug,
},
'configuration': {},
'configuration_id': None,
})
self.run_1.refresh_from_db()
self.assertNotEqual(self.run_1.version_id, dla_version.id)
def test_update_run_configuration(self):
self.client.force_login(self.user)
self.assertDictEqual(self.run_1.old_configuration, {})
with self.assertNumQueries(8):
self.assertEqual(self.run_1.configuration, None)
with self.assertNumQueries(9):
response = self.client.patch(
reverse('api:worker-run-details', kwargs={'pk': self.run_1.id}),
data={
'configuration': {
'a': 'b',
'c': {
'd': 42
}
}
'configuration_id': str(self.configuration_1.id)
},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.run_1.refresh_from_db()
self.assertDictEqual(self.run_1.old_configuration, {
'a': 'b',
'c': {
'd': 42
}
})
self.assertEqual(self.run_1.configuration.id, self.configuration_1.id)
def test_update_run_configuration_object(self):
def test_update_run_invalid_configuration(self):
self.client.force_login(self.user)
parameters = [
(1, 'Expected a dictionary of items but got type "int".'),
([], 'Expected a dictionary of items but got type "list".'),
('a', 'Expected a dictionary of items but got type "str".'),
(None, 'This field may not be null.'),
]
for configuration, message in parameters:
with self.subTest(configuration=configuration), self.assertNumQueries(6):
response = self.client.patch(
reverse('api:worker-run-details', kwargs={'pk': self.run_1.id}),
data={'configuration': configuration},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {'configuration': [message]})
self.assertEqual(self.run_1.configuration, None)
response = self.client.patch(
reverse('api:worker-run-details', kwargs={'pk': self.run_1.id}),
data={'configuration_id': str(self.configuration_2.id)},
format='json'
)
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
self.assertDictEqual(response.json(), {'configuration_id': ['The configuration must be part of the same worker.']})
def test_update_run_dataimport_already_started(self):
"""
......@@ -533,7 +496,7 @@ class TestWorkerRuns(FixtureAPITestCase):
'type': self.worker_1.type,
'slug': self.worker_1.slug,
},
'configuration': {},
'configuration_id': None,
})
def test_delete_run_requires_login(self):
......