From ba54ca6537fc5c3c5d64a8cf60ba2e2d61d6a578 Mon Sep 17 00:00:00 2001 From: Jorrit Schaap <schaap@astron.nl> Date: Tue, 23 Mar 2021 18:35:22 +0100 Subject: [PATCH] TMSS-601: replace 'output-boolean by real IOType --- .../tmss/tmssapp/migrations/0001_initial.py | 25 ++++++++++++++----- .../src/tmss/tmssapp/models/specification.py | 11 +++++++- SAS/TMSS/backend/src/tmss/tmssapp/populate.py | 14 +++++------ .../tmss/tmssapp/serializers/specification.py | 5 ++++ SAS/TMSS/backend/src/tmss/tmssapp/tasks.py | 4 +-- .../tmss/tmssapp/viewsets/specification.py | 5 ++++ SAS/TMSS/backend/src/tmss/urls.py | 1 + .../test/tmss_test_data_django_models.py | 2 +- SAS/TMSS/backend/test/tmss_test_data_rest.py | 12 ++++----- 9 files changed, 56 insertions(+), 23 deletions(-) diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py index a89b16fc3d5..2fffaacce28 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.9 on 2021-03-22 10:34 +# Generated by Django 3.0.9 on 2021-03-23 17:08 from django.conf import settings import django.contrib.postgres.fields @@ -360,6 +360,15 @@ class Migration(migrations.Migration): 'abstract': False, }, ), + migrations.CreateModel( + name='IOType', + fields=[ + ('value', models.CharField(max_length=128, primary_key=True, serialize=False, unique=True)), + ], + options={ + 'abstract': False, + }, + ), migrations.CreateModel( name='PeriodCategory', fields=[ @@ -464,13 +473,13 @@ class Migration(migrations.Migration): name='ReservationStrategyTemplate', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('tags',django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)), + ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)), ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), ('name', models.CharField(help_text='Human-readable name of this object.', max_length=128)), ('description', models.CharField(blank=True, default='', help_text='A longer description of this object.', max_length=255)), ('version', models.CharField(help_text='Version of this template (with respect to other templates of the same name).', max_length=128)), - ('template', django.contrib.postgres.fields.jsonb.JSONField(help_text='JSON-data compliant with the JSON-schema in the scheduling_unit_template. This observation strategy template like a predefined recipe with all the correct settings, and defines which parameters the user can alter.')), + ('template', django.contrib.postgres.fields.jsonb.JSONField(help_text='JSON-data compliant with the JSON-schema in the reservation_template. This reservation strategy template like a predefined recipe with all the correct settings, and defines which parameters the user can alter.')), ], options={ 'abstract': False, @@ -790,7 +799,6 @@ class Migration(migrations.Migration): ('tags', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=128), blank=True, default=list, help_text='User-defined search keywords for object.', size=8)), ('created_at', models.DateTimeField(auto_now_add=True, help_text='Moment of object creation.')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Moment of last object update.')), - ('output', models.BooleanField(help_text='True if this connector describes an output, False if this connector describes an input')), ], options={ 'abstract': False, @@ -1011,6 +1019,11 @@ class Migration(migrations.Migration): name='datatype', field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Datatype'), ), + migrations.AddField( + model_name='taskconnectortype', + name='iotype', + field=models.ForeignKey(help_text='Is this connector an input or output', on_delete=django.db.models.deletion.PROTECT, to='tmssapp.IOType'), + ), migrations.AddField( model_name='taskconnectortype', name='role', @@ -1235,12 +1248,12 @@ class Migration(migrations.Migration): migrations.AddField( model_name='projectquotaarchivelocation', name='project_quota', - field=models.ForeignKey(help_text='Project to which this quota belongs.', on_delete=django.db.models.deletion.PROTECT, related_name='project_quota', to='tmssapp.ProjectQuota'), + field=models.ForeignKey(help_text='The ProjectQuota for this archive location', on_delete=django.db.models.deletion.PROTECT, related_name='project_quota_archive_location', to='tmssapp.ProjectQuota'), ), migrations.AddField( model_name='projectquota', name='project', - field=models.ForeignKey(help_text='Project to which this quota belongs.', on_delete=django.db.models.deletion.PROTECT, related_name='quota', to='tmssapp.Project'), + field=models.ForeignKey(help_text='Project to wich this quota belongs.', on_delete=django.db.models.deletion.PROTECT, related_name='quota', to='tmssapp.Project'), ), migrations.AddField( model_name='projectquota', diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py index 2ebdaf12e1b..be5b44b7cbf 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py @@ -55,6 +55,15 @@ class Role(AbstractChoice): ANY = "any" +class IOType(AbstractChoice): + """Defines the model and predefined list of possible IOType's for TaskConnectorType. + The items in the Choises class below are automagically populated into the database via a data migration.""" + class Choices(Enum): + INPUT = "input" + OUTPUT = "output" + # maybe we can add an IN_PLACE="in_place" option in the future, but for now it's not needed. + + class Datatype(AbstractChoice): """Defines the model and predefined list of possible Datatype's for TaskConnectorType. The items in the Choises class below are automagically populated into the database via a data migration.""" @@ -163,7 +172,7 @@ class TaskConnectorType(BasicCommon): datatype = ForeignKey('Datatype', null=False, on_delete=PROTECT) dataformats = ManyToManyField('Dataformat', blank=True) task_template = ForeignKey("TaskTemplate", related_name='output_connector_types', null=False, on_delete=CASCADE) - output = BooleanField(null=False, help_text="True if this connector describes an output, False if this connector describes an input") + iotype = ForeignKey('IOType', null=False, on_delete=PROTECT, help_text="Is this connector an input or output") # diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/populate.py b/SAS/TMSS/backend/src/tmss/tmssapp/populate.py index 43d73566a0f..4d274999457 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/populate.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/populate.py @@ -40,7 +40,7 @@ def populate_choices(apps, schema_editor): each 'choice'type in Role, Datatype, Dataformat, CopyReason :return: None ''' - choice_classes = [Role, Datatype, Dataformat, CopyReason, + choice_classes = [Role, IOType, Datatype, Dataformat, CopyReason, SubtaskState, SubtaskType, StationType, Algorithm, SchedulingRelationPlacement, Flag, ProjectCategory, PeriodCategory, Quantity, TaskType, ProjectRole] @@ -359,35 +359,35 @@ def populate_connectors(): TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.CORRELATOR.value), datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), task_template=TaskTemplate.objects.get(name='calibrator observation'), - output=True) + iotype=IOType.objects.get(value=IOType.Choices.OUTPUT.value)) # target observation TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.CORRELATOR.value), datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), task_template=TaskTemplate.objects.get(name='target observation'), - output=True) + iotype=IOType.objects.get(value=IOType.Choices.OUTPUT.value)) # preprocessing pipeline TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value), datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), task_template=TaskTemplate.objects.get(name='preprocessing pipeline'), - output=False) + iotype=IOType.objects.get(value=IOType.Choices.INPUT.value)) TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value), datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), task_template=TaskTemplate.objects.get(name='preprocessing pipeline'), - output=True) + iotype=IOType.objects.get(value=IOType.Choices.OUTPUT.value)) # ingest TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value), datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), task_template=TaskTemplate.objects.get(name='ingest'), - output=False) + iotype=IOType.objects.get(value=IOType.Choices.INPUT.value)) TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.ANY.value), datatype=Datatype.objects.get(value=Datatype.Choices.TIME_SERIES.value), task_template=TaskTemplate.objects.get(name='ingest'), - output=False) + iotype=IOType.objects.get(value=IOType.Choices.INPUT.value)) def populate_permissions(): diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py index 47086104958..8e219472088 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py @@ -102,6 +102,11 @@ class RoleSerializer(serializers.ModelSerializer): model = models.Role fields = '__all__' +class IOTypeSerializer(serializers.ModelSerializer): + class Meta: + model = models.IOType + fields = '__all__' + class SchedulingRelationPlacementSerializer(serializers.ModelSerializer): class Meta: model = models.SchedulingRelationPlacement diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py b/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py index 0752147c4e5..e6d9c06ebe4 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/tasks.py @@ -179,8 +179,8 @@ def create_task_drafts_from_scheduling_unit_draft(scheduling_unit_draft: models. producer_task_draft = scheduling_unit_draft.task_drafts.get(name=task_relation_definition["producer"]) consumer_task_draft = scheduling_unit_draft.task_drafts.get(name=task_relation_definition["consumer"]) dataformat = models.Dataformat.objects.get(value=task_relation_definition["dataformat"]) - input_role = models.TaskConnectorType.objects.get(task_template=consumer_task_draft.specifications_template, role=task_relation_definition["input"]["role"], datatype=task_relation_definition["input"]["datatype"], output=False) - output_role = models.TaskConnectorType.objects.get(task_template=producer_task_draft.specifications_template, role=task_relation_definition["output"]["role"], datatype=task_relation_definition["output"]["datatype"], output=True) + input_role = models.TaskConnectorType.objects.get(task_template=consumer_task_draft.specifications_template, role=task_relation_definition["input"]["role"], datatype=task_relation_definition["input"]["datatype"], iotype=models.IOType.objects.get(value=models.IOType.Choices.INPUT.value)) + output_role = models.TaskConnectorType.objects.get(task_template=producer_task_draft.specifications_template, role=task_relation_definition["output"]["role"], datatype=task_relation_definition["output"]["datatype"], iotype=models.IOType.objects.get(value=models.IOType.Choices.OUTPUT.value)) selection_template = models.TaskRelationSelectionTemplate.objects.get(name=task_relation_definition["selection_template"]) try: diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py index d53ace784b0..620742eaa77 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/specification.py @@ -280,6 +280,11 @@ class RoleViewSet(LOFARViewSet): serializer_class = serializers.RoleSerializer +class IOTypeViewSet(LOFARViewSet): + queryset = models.IOType.objects.all() + serializer_class = serializers.IOTypeSerializer + + class SchedulingRelationPlacement(LOFARViewSet): queryset = models.SchedulingRelationPlacement.objects.all() serializer_class = serializers.SchedulingRelationPlacementSerializer diff --git a/SAS/TMSS/backend/src/tmss/urls.py b/SAS/TMSS/backend/src/tmss/urls.py index 66e58162725..afe222f05f2 100644 --- a/SAS/TMSS/backend/src/tmss/urls.py +++ b/SAS/TMSS/backend/src/tmss/urls.py @@ -117,6 +117,7 @@ router.register(r'tags', viewsets.TagsViewSet) # choices router.register(r'role', viewsets.RoleViewSet) +router.register(r'iotype', viewsets.IOTypeViewSet) router.register(r'datatype', viewsets.DatatypeViewSet) router.register(r'dataformat', viewsets.DataformatViewSet) router.register(r'copy_reason', viewsets.CopyReasonViewSet) diff --git a/SAS/TMSS/backend/test/tmss_test_data_django_models.py b/SAS/TMSS/backend/test/tmss_test_data_django_models.py index 2a6c110bc7f..08c549f734f 100644 --- a/SAS/TMSS/backend/test/tmss_test_data_django_models.py +++ b/SAS/TMSS/backend/test/tmss_test_data_django_models.py @@ -107,7 +107,7 @@ def TaskConnectorType_test_data() -> dict: return {"role": models.Role.objects.get(value='calibrator'), "datatype": models.Datatype.objects.get(value='instrument model'), "task_template": models.TaskTemplate.objects.create(**TaskTemplate_test_data()), - "output": True, + "iotype": models.IOType.objects.get(value=models.IOType.Choices.OUTPUT.value), "tags": []} def Cycle_test_data() -> dict: diff --git a/SAS/TMSS/backend/test/tmss_test_data_rest.py b/SAS/TMSS/backend/test/tmss_test_data_rest.py index 340b365afe6..759885c6f84 100644 --- a/SAS/TMSS/backend/test/tmss_test_data_rest.py +++ b/SAS/TMSS/backend/test/tmss_test_data_rest.py @@ -221,7 +221,7 @@ class TMSSRESTTestDataCreator(): return self._task_relation_selection_template_url - def TaskConnectorType(self, role="correlator", output=True, task_template_url=None): + def TaskConnectorType(self, role="correlator", iotype="output", task_template_url=None): if task_template_url is None: task_template_url = self.cached_task_template_url @@ -229,7 +229,7 @@ class TMSSRESTTestDataCreator(): "datatype": self.django_api_url + '/datatype/image', "dataformats": [self.django_api_url + '/dataformat/Beamformed'], "task_template": task_template_url, - "output": output, + "iotype": self.django_api_url + '/iotype/%s'%iotype, "tags": []} @@ -431,10 +431,10 @@ class TMSSRESTTestDataCreator(): selection_doc = self.get_response_as_json_object(template_url+'/default') if input_role_url is None: - input_role_url = self.post_data_and_get_url(self.TaskConnectorType(output=False), '/task_connector_type/') + input_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="input"), '/task_connector_type/') if output_role_url is None: - output_role_url = self.post_data_and_get_url(self.TaskConnectorType(output=True), '/task_connector_type/') + output_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="output"), '/task_connector_type/') return {"tags": [], "selection_doc": selection_doc, @@ -530,10 +530,10 @@ class TMSSRESTTestDataCreator(): selection_doc = self.get_response_as_json_object(template_url+'/default') if input_role_url is None: - input_role_url = self.post_data_and_get_url(self.TaskConnectorType(output=False), '/task_connector_type/') + input_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="input"), '/task_connector_type/') if output_role_url is None: - output_role_url = self.post_data_and_get_url(self.TaskConnectorType(output=True), '/task_connector_type/') + output_role_url = self.post_data_and_get_url(self.TaskConnectorType(iotype="output"), '/task_connector_type/') # test data return {"tags": [], -- GitLab