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 5d19ced6b7659cc33e41585611baf168cc7aeac1..021f8b2920bda008745595e13601416bf908377e 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/migrations/0001_initial.py @@ -661,6 +661,7 @@ class Migration(migrations.Migration): ('actual_on_sky_stop_time', models.DateTimeField(help_text='The time the observation actually stopped recording (NULLable).', null=True)), ('primary', models.BooleanField(db_index=True, default=False, help_text='TRUE if this is the one-and-only primary subtask in a parent TaskBlueprint.')), ('specifications_doc', django.contrib.postgres.fields.jsonb.JSONField(help_text='Final specifications, as input for the controller.')), + ('error_reason', models.CharField(null=True, max_length=200, help_text='Reason why the Subtask went to error.')), ('raw_feedback', models.CharField(help_text='The raw feedback for this Subtask', max_length=1048576, null=True)), ], options={ diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py index 7b3200b15cc433f0feaa38cb77c72c8927bcd279..f0a92108015c5d6de0e65b7f415b876ecd25bc63 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/scheduling.py @@ -152,6 +152,7 @@ class Subtask(BasicCommon, ProjectPropertyMixin, TemplateSchemaMixin): cluster = ForeignKey('Cluster', null=True, on_delete=PROTECT, help_text='Where the Subtask is scheduled to run (NULLable).') # resource_claim = ForeignKey("ResourceClaim", null=False, on_delete=PROTECT) # todo <-- how is this external reference supposed to work? created_or_updated_by_user = ForeignKey(User, null=True, editable=False, on_delete=PROTECT, help_text='The user who created / updated the subtask.') + error_reason = CharField(null=True, max_length=200, help_text='Reason why the Subtask went to error.') raw_feedback = CharField(null=True, max_length=1048576, help_text='The raw feedback for this Subtask') global_identifier = OneToOneField('SIPidentifier', null=False, editable=False, on_delete=PROTECT, help_text='The global unique identifier for LTA SIP.') path_to_project = 'task_blueprint__scheduling_unit_blueprint__draft__scheduling_set__project' diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py index 72c0cf92be4ea0be4c810804f9cb2443e757667c..7b3bd8137bbe768885043358b579af238f0b4ca3 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py @@ -6,6 +6,7 @@ import logging logger = logging.getLogger(__name__) from rest_framework import serializers +from rest_framework.exceptions import ValidationError from .. import models from .widgets import JSONEditorField from .common import FloatDurationField, RelationalHyperlinkedModelSerializer, AbstractTemplateSerializer, DynamicRelationalHyperlinkedModelSerializer @@ -74,6 +75,10 @@ class SubtaskSerializer(DynamicRelationalHyperlinkedModelSerializer): input_dataproducts = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='dataproduct-detail') output_dataproducts = serializers.HyperlinkedRelatedField(many=True, read_only=True, view_name='dataproduct-detail') + def validate_error_reason(self, value): # Make the error_reason field editable only once + if self.instance and self.instance.error_reason != None: + raise ValidationError("You may not edit error_reason") + return value class Meta: model = models.Subtask diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py index eecfea0ab5133fbca074cb3d41f43eeb8a915e8f..b5e57bce8769778c014a29961ddbfe334577d112 100644 --- a/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py +++ b/SAS/TMSS/backend/src/tmss/tmssapp/viewsets/scheduling.py @@ -127,6 +127,7 @@ class SubTaskFilter(property_filters.PropertyFilterSet): id_max = filters.NumberFilter(field_name='id', lookup_expr='lte') state = filters.ModelMultipleChoiceFilter(field_name='state', queryset=models.SubtaskState.objects.all()) name = filters.CharFilter(field_name='task_blueprint__scheduling_unit_blueprint__name', lookup_expr='icontains') # todo: correct name? + error_reason = filters.CharFilter(field_name='error_reason', lookup_expr='icontains') on_sky_start_time__lt = property_filters.PropertyIsoDateTimeFilter(field_name='on_sky_start_time', lookup_expr='lt') on_sky_start_time__gt = property_filters.PropertyIsoDateTimeFilter(field_name='on_sky_start_time', lookup_expr='gt') on_sky_stop_time__lt = property_filters.PropertyIsoDateTimeFilter(field_name='on_sky_stop_time', lookup_expr='lt')