From dbdb28387239d3dc3fc9972faf7caac58802d1f6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=B6rn=20K=C3=BCnsem=C3=B6ller?=
 <jkuensem@physik.uni-bielefeld.de>
Date: Tue, 27 Apr 2021 17:32:52 +0200
Subject: [PATCH] TMSS-697: Add scheduling contraints to SU blueprint, copy
 from draft on creation, prevent update in non-schedulable state.

---
 .../src/tmss/tmssapp/models/specification.py  | 25 +++++++++++--------
 1 file changed, 15 insertions(+), 10 deletions(-)

diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
index b927f609a14..cbf04a81f2d 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/models/specification.py
@@ -480,6 +480,8 @@ class SchedulingUnitBlueprint(RefreshFromDbInvalidatesCachedPropertiesMixin, Tem
         SCHEDULED = "scheduled"
         SCHEDULABLE = "schedulable"
 
+    # todo: are many of these fields supposed to be immutable in the database?
+    #  Or are we fine to just not allow most users to change them?
     requirements_doc = JSONField(help_text='Scheduling and/or quality requirements for this scheduling unit (IMMUTABLE).')
     do_cancel = BooleanField()
     ingest_permission_required = BooleanField(default=False, help_text='Explicit permission is needed before the task.')
@@ -492,19 +494,22 @@ class SchedulingUnitBlueprint(RefreshFromDbInvalidatesCachedPropertiesMixin, Tem
     piggyback_allowed_aartfaac = BooleanField(help_text='Piggyback key for AARTFAAC.', null=True)
     priority_rank = FloatField(null=False, default=0.0, help_text='Priority of this scheduling unit w.r.t. other scheduling units within the same queue and project.')
     priority_queue = ForeignKey('PriorityQueueType', null=False, on_delete=PROTECT, default="A", help_text='Priority queue of this scheduling unit. Queues provide a strict ordering between scheduling units.')
+    scheduling_constraints_doc = JSONField(help_text='Scheduling Constraints for this run.', null=True)
+    scheduling_constraints_template = ForeignKey('SchedulingConstraintsTemplate', on_delete=CASCADE, null=True, help_text='Schema used for scheduling_constraints_doc.')
 
     def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
         self.annotate_validate_add_defaults_to_doc_using_template('requirements_doc', 'requirements_template')
-       
-        # This code only happens if the objects is not in the database yet. self._state.adding is True creating
-        if self._state.adding and hasattr(self, 'draft'):
-            self.ingest_permission_required = self.draft.ingest_permission_required
-
-        # Propagate scheduling_unit_draft piggyback values as default for scheduling_unit_blueprint
-        if self._state.adding and self.piggyback_allowed_tbb is None and hasattr(self, 'draft'):
-            self.piggyback_allowed_tbb = self.draft.piggyback_allowed_tbb
-        if self._state.adding and self.piggyback_allowed_aartfaac is None and hasattr(self, 'draft'):
-            self.piggyback_allowed_aartfaac = self.draft.piggyback_allowed_aartfaac
+
+        if self._state.adding:
+            # On creation, propagate the following scheduling_unit_draft attributes as default for the new scheduling_unit_blueprint
+            for copy_field in ['ingest_permission_required', 'piggyback_allowed_tbb', 'piggyback_allowed_aartfaac',
+                               'scheduling_constraints_doc', 'scheduling_constraints_template']:
+                if getattr(self, copy_field) is None and hasattr(self, 'draft'):
+                    setattr(self, copy_field, getattr(self.draft, copy_field))
+        else:
+            # On updates, prevent changing the scheduling contraints doc or template
+            if self.status != SchedulingUnitBlueprint.Status.SCHEDULABLE.value and (self.scheduling_constraints_doc or self.scheduling_constraints_doc):
+                raise ProtectedError('The scheduling constraints of SchedulingUnitBlueprint pk=%s status=%s cannot be updated since is is not in schedulable state.' % (self.pk, self.status))
 
         super().save(force_insert, force_update, using, update_fields)
 
-- 
GitLab