diff --git a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py index 819a8a25ed762d1782e9a434b629f414e727d742..16eef90707c65e80f5a37a9a43e0a54d1e40fe29 100644 --- a/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py +++ b/SAS/TMSS/src/tmss/tmssapp/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.12 on 2020-05-27 09:15 +# Generated by Django 2.2.12 on 2020-06-15 13:58 from django.conf import settings import django.contrib.postgres.fields @@ -244,7 +244,7 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='DefaultTaskTemplate', + name='DefaultTaskRelationSelectionTemplate', 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)), @@ -257,7 +257,7 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='DefaultTaskRelationSelectionTemplate', + name='DefaultTaskTemplate', 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)), @@ -562,7 +562,7 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='TaskConnector', + name='TaskConnectorType', 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)), @@ -615,7 +615,7 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='TaskTemplate', + name='TaskRelationSelectionTemplate', 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)), @@ -625,11 +625,10 @@ class Migration(migrations.Migration): ('description', models.CharField(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)), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), - ('validation_code_js', models.CharField(help_text='JavaScript code for additional (complex) validation.', max_length=128)), ], ), migrations.CreateModel( - name='TaskRelationSelectionTemplate', + name='TaskTemplate', 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)), @@ -639,20 +638,21 @@ class Migration(migrations.Migration): ('description', models.CharField(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)), ('schema', django.contrib.postgres.fields.jsonb.JSONField(help_text='Schema for the configurable parameters needed to use this template.')), + ('validation_code_js', models.CharField(help_text='JavaScript code for additional (complex) validation.', max_length=128)), ], ), - migrations.AddConstraint( - model_name='taskrelationselectiontemplate', - constraint=models.UniqueConstraint(fields=('name', 'version'), name='TaskRelationSelectionTemplate_unique_name_version'), - ), migrations.AddConstraint( model_name='tasktemplate', constraint=models.UniqueConstraint(fields=('name', 'version'), name='TaskTemplate_unique_name_version'), ), + migrations.AddConstraint( + model_name='taskrelationselectiontemplate', + constraint=models.UniqueConstraint(fields=('name', 'version'), name='TaskRelationSelectionTemplate_unique_name_version'), + ), migrations.AddField( model_name='taskrelationdraft', name='consumer', - field=models.ForeignKey(help_text='Task Draft that has the input connector.', on_delete=django.db.models.deletion.CASCADE, related_name='consumed_by', to='tmssapp.TaskDraft'), + field=models.ForeignKey(help_text='Task Draft that has the input connector.', on_delete=django.db.models.deletion.CASCADE, related_name='produced_by', to='tmssapp.TaskDraft'), ), migrations.AddField( model_name='taskrelationdraft', @@ -661,18 +661,18 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='taskrelationdraft', - name='input', - field=models.ForeignKey(help_text='Input connector of consumer.', on_delete=django.db.models.deletion.CASCADE, related_name='inputs_task_relation_draft', to='tmssapp.TaskConnector'), + name='input_role', + field=models.ForeignKey(help_text='Input connector type (what kind of data can be taken as input).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationdraft_input_roles', to='tmssapp.TaskConnectorType'), ), migrations.AddField( model_name='taskrelationdraft', - name='output', - field=models.ForeignKey(help_text='Output connector of producer.', on_delete=django.db.models.deletion.CASCADE, related_name='outputs_task_relation_draft', to='tmssapp.TaskConnector'), + name='output_role', + field=models.ForeignKey(help_text='Output connector type (what kind of data can be created as output).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationdraft_output_roles', to='tmssapp.TaskConnectorType'), ), migrations.AddField( model_name='taskrelationdraft', name='producer', - field=models.ForeignKey(help_text='Task Draft that has the output connector. NOTE: The producer does typically, but not necessarily, belong to the same Scheduling Unit (or even the same Project) as the consumer.', on_delete=django.db.models.deletion.CASCADE, related_name='produced_by', to='tmssapp.TaskDraft'), + field=models.ForeignKey(help_text='Task Draft that has the output connector. NOTE: The producer does typically, but not necessarily, belong to the same Scheduling Unit (or even the same Project) as the consumer.', on_delete=django.db.models.deletion.CASCADE, related_name='consumed_by', to='tmssapp.TaskDraft'), ), migrations.AddField( model_name='taskrelationdraft', @@ -682,7 +682,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='taskrelationblueprint', name='consumer', - field=models.ForeignKey(help_text='Task Blueprint that has the input connector.', on_delete=django.db.models.deletion.CASCADE, related_name='consumed_by', to='tmssapp.TaskBlueprint'), + field=models.ForeignKey(help_text='Task Blueprint that has the input connector.', on_delete=django.db.models.deletion.CASCADE, related_name='produced_by', to='tmssapp.TaskBlueprint'), ), migrations.AddField( model_name='taskrelationblueprint', @@ -696,18 +696,18 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name='taskrelationblueprint', - name='input', - field=models.ForeignKey(help_text='Input connector of consumer.', on_delete=django.db.models.deletion.CASCADE, related_name='inputs_task_relation_blueprint', to='tmssapp.TaskConnector'), + name='input_role', + field=models.ForeignKey(help_text='Input connector type (what kind of data can be taken as input).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationblueprint_input_roles', to='tmssapp.TaskConnectorType'), ), migrations.AddField( model_name='taskrelationblueprint', - name='output', - field=models.ForeignKey(help_text='Output connector of producer.', on_delete=django.db.models.deletion.CASCADE, related_name='outputs_task_relation_blueprint', to='tmssapp.TaskConnector'), + name='output_role', + field=models.ForeignKey(help_text='Output connector type (what kind of data can be created as output).', on_delete=django.db.models.deletion.CASCADE, related_name='taskrelationblueprint_output_roles', to='tmssapp.TaskConnectorType'), ), migrations.AddField( model_name='taskrelationblueprint', name='producer', - field=models.ForeignKey(help_text='Task Blueprint that has the output connector.', on_delete=django.db.models.deletion.CASCADE, related_name='produced_by', to='tmssapp.TaskBlueprint'), + field=models.ForeignKey(help_text='Task Blueprint that has the output connector.', on_delete=django.db.models.deletion.CASCADE, related_name='consumed_by', to='tmssapp.TaskBlueprint'), ), migrations.AddField( model_name='taskrelationblueprint', @@ -735,27 +735,27 @@ class Migration(migrations.Migration): field=models.ForeignKey(help_text='Schema used for requirements_doc.', on_delete=django.db.models.deletion.CASCADE, to='tmssapp.TaskTemplate'), ), migrations.AddField( - model_name='taskconnector', + model_name='taskconnectortype', name='dataformats', field=models.ManyToManyField(blank=True, to='tmssapp.Dataformat'), ), migrations.AddField( - model_name='taskconnector', + model_name='taskconnectortype', name='datatype', field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Datatype'), ), migrations.AddField( - model_name='taskconnector', + model_name='taskconnectortype', name='input_of', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inputs', to='tmssapp.TaskTemplate'), + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inpput_connector_types', to='tmssapp.TaskTemplate'), ), migrations.AddField( - model_name='taskconnector', + model_name='taskconnectortype', name='output_of', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='outputs', to='tmssapp.TaskTemplate'), + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='output_connector_types', to='tmssapp.TaskTemplate'), ), migrations.AddField( - model_name='taskconnector', + model_name='taskconnectortype', name='role', field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Role'), ), @@ -767,7 +767,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='taskblueprint', name='scheduling_unit_blueprint', - field=models.ForeignKey(help_text='Scheduling Unit Blueprint to which this task belongs.', on_delete=django.db.models.deletion.CASCADE, to='tmssapp.SchedulingUnitBlueprint'), + field=models.ForeignKey(help_text='Scheduling Unit Blueprint to which this task belongs.', on_delete=django.db.models.deletion.CASCADE, related_name='task_blueprints', to='tmssapp.SchedulingUnitBlueprint'), ), migrations.AddField( model_name='taskblueprint', @@ -942,14 +942,14 @@ class Migration(migrations.Migration): field=models.ForeignKey(help_text='Cluster hosting this filesystem.', on_delete=django.db.models.deletion.PROTECT, to='tmssapp.Cluster'), ), migrations.AddField( - model_name='defaulttaskrelationselectiontemplate', + model_name='defaulttasktemplate', name='template', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.TaskRelationSelectionTemplate'), + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.TaskTemplate'), ), migrations.AddField( - model_name='defaulttasktemplate', + model_name='defaulttaskrelationselectiontemplate', name='template', - field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.TaskTemplate'), + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='tmssapp.TaskRelationSelectionTemplate'), ), migrations.AddField( model_name='defaultsubtasktemplate', @@ -1038,8 +1038,8 @@ class Migration(migrations.Migration): index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_256437_gin'), ), migrations.AddIndex( - model_name='taskconnector', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_a12728_gin'), + model_name='taskconnectortype', + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_tas_tags_19ff09_gin'), ), migrations.AddConstraint( model_name='subtasktemplate', @@ -1061,14 +1061,14 @@ class Migration(migrations.Migration): model_name='subtask', index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_sub_tags_d2fc43_gin'), ), - migrations.AddIndex( - model_name='defaulttaskrelationselectiontemplate', - index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_b652d9_gin'), - ), migrations.AddIndex( model_name='defaulttasktemplate', index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_c88200_gin'), ), + migrations.AddIndex( + model_name='defaulttaskrelationselectiontemplate', + index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_3bee7d_gin'), + ), migrations.AddIndex( model_name='defaultsubtasktemplate', index=django.contrib.postgres.indexes.GinIndex(fields=['tags'], name='tmssapp_def_tags_e9c73d_gin'), diff --git a/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py b/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py index f67a46eef6c84937207e7005ebec7145d1ce3eff..0a0607d514b73c5f92fa2324084cac5bde2da77b 100644 --- a/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py +++ b/SAS/TMSS/src/tmss/tmssapp/models/scheduling.py @@ -207,7 +207,7 @@ class Subtask(BasicCommon): if self.state.value == SubtaskState.Choices.SCHEDULED.value and self.__original_state.value == SubtaskState.Choices.SCHEDULING.value: if self.start_time is None: - if self.predecessors.all().count() is 0: + if self.predecessors.all().count() == 0: raise SubtaskSchedulingException("Cannot schedule subtask id=%s when start time is 'None'." % (self.pk, )) else: self.start_time = datetime.utcnow() diff --git a/SAS/TMSS/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/src/tmss/tmssapp/models/specification.py index 9e49ea172ef87ef7dac9ad730a07a20320eba95a..7b3329f3f8de955f55f5517a992a63794087b1e9 100644 --- a/SAS/TMSS/src/tmss/tmssapp/models/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/models/specification.py @@ -90,7 +90,7 @@ class AbstractChoice(Model): class Role(AbstractChoice): - """Defines the model and predefined list of possible Role's for TaskConnector. + """Defines the model and predefined list of possible Role's for TaskConnectorType. The items in the Choises class below are automagically populated into the database via a data migration.""" class Choices(Enum): CORRELATOR = "correlator" @@ -103,7 +103,7 @@ class Role(AbstractChoice): class Datatype(AbstractChoice): - """Defines the model and predefined list of possible Datatype's for TaskConnector. + """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.""" class Choices(Enum): VISIBILITIES = "visibilities" @@ -133,12 +133,12 @@ class CopyReason(AbstractChoice): # concrete models -class TaskConnector(BasicCommon): +class TaskConnectorType(BasicCommon): role = ForeignKey('Role', null=False, on_delete=PROTECT) datatype = ForeignKey('Datatype', null=False, on_delete=PROTECT) dataformats = ManyToManyField('Dataformat', blank=True) - output_of = ForeignKey("TaskTemplate", related_name='outputs', on_delete=CASCADE) - input_of = ForeignKey("TaskTemplate", related_name='inputs', on_delete=CASCADE) + output_of = ForeignKey("TaskTemplate", related_name='output_connector_types', on_delete=CASCADE) + input_of = ForeignKey("TaskTemplate", related_name='inpput_connector_types', on_delete=CASCADE) # @@ -352,6 +352,7 @@ class TaskBlueprint(NamedCommon): class TaskRelationDraft(BasicCommon): selection_doc = JSONField(help_text='Filter for selecting dataproducts from the output role.') + selection_template = ForeignKey('TaskRelationSelectionTemplate', on_delete=CASCADE, help_text='Schema used for selection_doc.') # todo: 'schema'? dataformat = ForeignKey('Dataformat', null=False, on_delete=PROTECT, help_text='Selected data format to use. One of (MS, HDF5).') # caveat: it might look like producer has an incorrect related_name='consumed_by'. But it really is correct, denends on the way you look at it @@ -359,9 +360,8 @@ class TaskRelationDraft(BasicCommon): # caveat: it might look like consumer has an incorrect related_name='produced_by'. But it really is correct, denends on the way you look at it consumer = ForeignKey('TaskDraft', related_name='produced_by', on_delete=CASCADE, help_text='Task Draft that has the input connector.') - input = ForeignKey('TaskConnector', related_name='inputs_task_relation_draft', on_delete=CASCADE, help_text='Input connector of consumer.') - output = ForeignKey('TaskConnector', related_name='outputs_task_relation_draft', on_delete=CASCADE, help_text='Output connector of producer.') - selection_template = ForeignKey('TaskRelationSelectionTemplate', on_delete=CASCADE, help_text='Schema used for selection_doc.') # todo: 'schema'? + input_role = ForeignKey('TaskConnectorType', related_name='taskrelationdraft_input_roles', on_delete=CASCADE, help_text='Input connector type (what kind of data can be taken as input).') + output_role = ForeignKey('TaskConnectorType', related_name='taskrelationdraft_output_roles', on_delete=CASCADE, help_text='Output connector type (what kind of data can be created as output).') def save(self, force_insert=False, force_update=False, using=None, update_fields=None): if self.selection_doc and self.selection_template_id and self.selection_template.schema: @@ -379,8 +379,8 @@ class TaskRelationBlueprint(BasicCommon): # caveat: it might look like consumer has an incorrect related_name='produced_by'. But it really is correct, denends on the way you look at it consumer = ForeignKey('TaskBlueprint', related_name='produced_by', on_delete=CASCADE, help_text='Task Blueprint that has the input connector.') - input = ForeignKey('TaskConnector', related_name='inputs_task_relation_blueprint', on_delete=CASCADE, help_text='Input connector of consumer.') - output = ForeignKey('TaskConnector', related_name='outputs_task_relation_blueprint', on_delete=CASCADE, help_text='Output connector of producer.') + input_role = ForeignKey('TaskConnectorType', related_name='taskrelationblueprint_input_roles', on_delete=CASCADE, help_text='Input connector type (what kind of data can be taken as input).') + output_role = ForeignKey('TaskConnectorType', related_name='taskrelationblueprint_output_roles', on_delete=CASCADE, help_text='Output connector type (what kind of data can be created as output).') draft = ForeignKey('TaskRelationDraft', on_delete=CASCADE, related_name='related_task_relation_blueprint', help_text='Task Relation Draft which this work request instantiates.') selection_template = ForeignKey('TaskRelationSelectionTemplate', on_delete=CASCADE, help_text='Schema used for selection_doc.') # todo: 'schema'? diff --git a/SAS/TMSS/src/tmss/tmssapp/populate.py b/SAS/TMSS/src/tmss/tmssapp/populate.py index 31b8c5923fce6868720c5ba9359c08c042cac53a..991150faa93e0505872139c716fa286647bf0310 100644 --- a/SAS/TMSS/src/tmss/tmssapp/populate.py +++ b/SAS/TMSS/src/tmss/tmssapp/populate.py @@ -76,14 +76,14 @@ def _populate_task_draft_example(): pipeline_task_draft = models.TaskDraft.objects.create(**task_draft_data) # connect them - connector = models.TaskConnector.objects.first() # TODO: get the correct connector instead of the first + connector_type = models.TaskConnectorType.objects.first() # TODO: get the correct connector instead of the first task_relation_data = {"tags": [], "selection_doc": {}, "dataformat": models.Dataformat.objects.get(value='MeasurementSet'), "producer": obs_task_draft, "consumer": pipeline_task_draft, - "input": connector, - "output": connector, + "input_role": connector_type, + "output_role": connector_type, "selection_template": models.TaskRelationSelectionTemplate.objects.get(name="All")} models.TaskRelationDraft.objects.create(**task_relation_data) @@ -1366,14 +1366,14 @@ def _populate_pipelinecontrol_schema(): def _populate_connectors(): - # the TaskConnector's define how the Task[Draft/Blueprint] *can* be connected. - TaskConnector.objects.create(role=Role.objects.get(value=Role.Choices.CALIBRATOR.value), - datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), - output_of=TaskTemplate.objects.get(name='correlator schema'), - input_of=TaskTemplate.objects.get(name='preprocessing schema')) - - TaskConnector.objects.create(role=Role.objects.get(value=Role.Choices.TARGET.value), - datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), - output_of=TaskTemplate.objects.get(name='correlator schema'), - input_of=TaskTemplate.objects.get(name='preprocessing schema')) + # the TaskConnectorType's define how the Task[Draft/Blueprint] *can* be connected. + TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.CALIBRATOR.value), + datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), + output_of=TaskTemplate.objects.get(name='correlator schema'), + input_of=TaskTemplate.objects.get(name='preprocessing schema')) + + TaskConnectorType.objects.create(role=Role.objects.get(value=Role.Choices.TARGET.value), + datatype=Datatype.objects.get(value=Datatype.Choices.VISIBILITIES.value), + output_of=TaskTemplate.objects.get(name='correlator schema'), + input_of=TaskTemplate.objects.get(name='preprocessing schema')) diff --git a/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py b/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py index 4d1ae4d3b271419fcddc417a1025045c6afca4c4..a860e368eaaf64928b155a5e83a2f1e8fc759be6 100644 --- a/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/serializers/specification.py @@ -163,9 +163,9 @@ class CopyReasonSerializer(serializers.ModelSerializer): fields = '__all__' -class TaskConnectorSerializer(RelationalHyperlinkedModelSerializer): +class TaskConnectorTypeSerializer(RelationalHyperlinkedModelSerializer): class Meta: - model = models.TaskConnector + model = models.TaskConnectorType fields = '__all__' diff --git a/SAS/TMSS/src/tmss/tmssapp/tasks.py b/SAS/TMSS/src/tmss/tmssapp/tasks.py index d905e7774b12a1ac56977c5e72f6412aee455535..6e69a877e05873b48fd146466678637bdbe76373 100644 --- a/SAS/TMSS/src/tmss/tmssapp/tasks.py +++ b/SAS/TMSS/src/tmss/tmssapp/tasks.py @@ -61,32 +61,25 @@ def create_task_blueprint_from_task_draft(task_draft: models.TaskDraft) -> model # so, when converting two TaskDrafts (for example an observation and a pipeline), then for the conversion # of the first TaskDraft->TaskBlueprint no relation is setup, # and for the second TaskDraft->TaskBlueprint conversion we have both endpoints available, so we can connect them. - for consumer in task_draft.consumed_by.all(): - producing_task_blueprint = consumer.producer.task_blueprints.first() - if producing_task_blueprint is not None: - relation = models.TaskRelationBlueprint.objects.create(draft=consumer, - input=consumer.input, - output=consumer.output, - producer=task_blueprint, - consumer=producing_task_blueprint, - selection_doc=consumer.selection_doc, - selection_template=consumer.selection_template, - dataformat=consumer.dataformat) - logger.info("create_task_blueprint_from_task_draft(task_draft.id=%s) connected task_blueprint id=%s to task_blueprint id=%s via task_relation_blueprint id=%s", - task_draft.pk, task_blueprint.pk, producing_task_blueprint.pk, relation.pk) - for producer in task_draft.produced_by.all(): - consuming_task_blueprint = producer.consumer.task_blueprints.first() - if consuming_task_blueprint is not None: - relation = models.TaskRelationBlueprint.objects.create(draft=producer, - input=producer.input, - output=producer.output, - producer=consuming_task_blueprint, - consumer=task_blueprint, - selection_doc=producer.selection_doc, - selection_template=producer.selection_template, - dataformat=producer.dataformat) - logger.info("create_task_blueprint_from_task_draft(task_draft.id=%s) connected task_blueprint id=%s to task_blueprint id=%s via task_relation_blueprint id=%s", - task_draft.pk, consuming_task_blueprint.pk, task_blueprint.pk, relation.pk) + task_draft_relations = list(task_draft.consumed_by.all()) + list(task_draft.produced_by.all()) + for task_relation_draft in task_draft_relations: + for producing_task_blueprint in task_relation_draft.producer.task_blueprints.all(): + for consuming_task_blueprint in task_relation_draft.consumer.task_blueprints.all(): + try: + # do nothing if task_relation_blueprint already exists... + models.TaskRelationBlueprint.objects.get(producer_id=producing_task_blueprint.id, consumer_id=consuming_task_blueprint.id) + except models.TaskRelationBlueprint.DoesNotExist: + # ...'else' create it. + task_relation_blueprint = models.TaskRelationBlueprint.objects.create(draft=task_relation_draft, + input_role=task_relation_draft.input_role, + output_role=task_relation_draft.output_role, + producer=producing_task_blueprint, + consumer=consuming_task_blueprint, + selection_doc=task_relation_draft.selection_doc, + selection_template=task_relation_draft.selection_template, + dataformat=task_relation_draft.dataformat) + logger.info("create_task_blueprint_from_task_draft(task_draft.id=%s) connected task_blueprint id=%s to task_blueprint id=%s via task_relation_blueprint id=%s", + task_draft.pk, task_blueprint.pk, producing_task_blueprint.pk, task_relation_blueprint.pk) return task_blueprint diff --git a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py index 4516d434acbf9e031a0c6daad5d01a019668cea2..a5e519730502a9d7687adf4ed3774fa976c3b365 100644 --- a/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py +++ b/SAS/TMSS/src/tmss/tmssapp/viewsets/specification.py @@ -120,9 +120,9 @@ class ResourceUnitViewSet(LOFARViewSet): queryset = models.ResourceUnit.objects.all() serializer_class = serializers.ResourceUnitSerializer -class TaskConnectorViewSet(LOFARViewSet): - queryset = models.TaskConnector.objects.all() - serializer_class = serializers.TaskConnectorSerializer +class TaskConnectorTypeViewSet(LOFARViewSet): + queryset = models.TaskConnectorType.objects.all() + serializer_class = serializers.TaskConnectorTypeSerializer @permission_classes((DjangoModelPermissions,)) # example override of default permissions per viewset | todo: review for production diff --git a/SAS/TMSS/src/tmss/urls.py b/SAS/TMSS/src/tmss/urls.py index d63bd5467b95e70743af60527169c458d92fe8e7..feb1c41cb6035b490f8db9090ba593e22013ee11 100644 --- a/SAS/TMSS/src/tmss/urls.py +++ b/SAS/TMSS/src/tmss/urls.py @@ -91,7 +91,7 @@ router.register(r'generator_template', viewsets.GeneratorTemplateViewSet) router.register(r'scheduling_unit_template', viewsets.SchedulingUnitTemplateViewSet) router.register(r'task_template', viewsets.TaskTemplateViewSet) router.register(r'task_relation_selection_template', viewsets.TaskRelationSelectionTemplateViewSet) -router.register(r'task_connector', viewsets.TaskConnectorViewSet) +router.register(r'task_connector_type', viewsets.TaskConnectorTypeViewSet) router.register(r'default_generator_template', viewsets.DefaultGeneratorTemplateViewSet) router.register(r'default_scheduling_unit_template', viewsets.DefaultSchedulingUnitTemplateViewSet) router.register(r'default_task_template', viewsets.DefaultTaskTemplateViewSet)