Unverified Commit ba3c58d8 authored by Marius van den Beek's avatar Marius van den Beek Committed by GitHub
Browse files

Merge pull request #18517 from mvdbeek/fix_deleted_ipnut_submission_collection

[24.1] Prevent job submission if input collection element is deleted
parents af6e28d0 0be837ed
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -6499,6 +6499,23 @@ class DatasetCollection(Base, Dictifiable, UsesAnnotations, Serializable):
        q = q.order_by(*order_by_columns)
        return q

    @property
    def elements_deleted(self):
        if not hasattr(self, "_elements_deleted"):
            if session := object_session(self):
                stmt = self._build_nested_collection_attributes_stmt(
                    hda_attributes=("deleted",), dataset_attributes=("deleted",)
                )
                stmt = stmt.exists().where(or_(HistoryDatasetAssociation.deleted == true(), Dataset.deleted == true()))
                self._elements_deleted = session.execute(select(stmt)).scalar()
            else:
                self._elements_deleted = False
                for dataset_instance in self.dataset_instances:
                    if dataset_instance.deleted or dataset_instance.dataset.deleted:
                        self._elements_deleted = True
                        break
        return self._elements_deleted

    @property
    def dataset_states_and_extensions_summary(self):
        if not hasattr(self, "_dataset_states_and_extensions_summary"):
+40 −13
Original line number Diff line number Diff line
@@ -2189,19 +2189,37 @@ class DataToolParameter(BaseDataToolParameter):
        dataset_matcher_factory = get_dataset_matcher_factory(trans)
        dataset_matcher = dataset_matcher_factory.dataset_matcher(self, other_values)
        for v in rval:
            if v:
                if hasattr(v, "deleted") and v.deleted:
            if isinstance(v, DatasetCollectionElement):
                if hda := v.hda:
                    v = hda
                elif ldda := v.ldda:
                    v = ldda
                elif collection := v.child_collection:
                    v = collection
                elif not v.collection and v.collection.populated_optimized:
                    raise ParameterValueError("the selected collection has not been populated.", self.name)
                else:
                    raise ParameterValueError("Collection element in unexpected state", self.name)
            if isinstance(v, DatasetInstance):
                if v.deleted:
                    raise ParameterValueError("the previously selected dataset has been deleted.", self.name)
                elif hasattr(v, "dataset") and v.dataset.state in [Dataset.states.ERROR, Dataset.states.DISCARDED]:
                elif v.dataset and v.dataset.state in [Dataset.states.ERROR, Dataset.states.DISCARDED]:
                    raise ParameterValueError(
                        "the previously selected dataset has entered an unusable state", self.name
                    )
                elif hasattr(v, "dataset"):
                    if isinstance(v, DatasetCollectionElement):
                        v = v.hda
                match = dataset_matcher.hda_match(v)
                if match and match.implicit_conversion:
                    v.implicit_conversion = True  # type:ignore[union-attr]
            elif isinstance(v, HistoryDatasetCollectionAssociation):
                if v.deleted:
                    raise ParameterValueError("the previously selected dataset collection has been deleted.", self.name)
                v = v.collection
            if isinstance(v, DatasetCollection):
                if v.elements_deleted:
                    raise ParameterValueError(
                        "the previously selected dataset collection has elements that are deleted.", self.name
                    )

        if not self.multiple:
            if len(rval) > 1:
                raise ParameterValueError("more than one dataset supplied to single input dataset parameter", self.name)
@@ -2498,10 +2516,19 @@ class DataCollectionToolParameter(BaseDataToolParameter):
                rval = session.get(HistoryDatasetCollectionAssociation, int(value[len("hdca:") :]))
            else:
                rval = session.get(HistoryDatasetCollectionAssociation, int(value))
        if rval and isinstance(rval, HistoryDatasetCollectionAssociation):
        if rval:
            if isinstance(rval, HistoryDatasetCollectionAssociation):
                if rval.deleted:
                    raise ParameterValueError("the previously selected dataset collection has been deleted", self.name)
            # TODO: Handle error states, implement error states ...
                if rval.collection.elements_deleted:
                    raise ParameterValueError(
                        "the previously selected dataset collection has elements that are deleted.", self.name
                    )
            if isinstance(rval, DatasetCollectionElement):
                if (child_collection := rval.child_collection) and child_collection.elements_deleted:
                    raise ParameterValueError(
                        "the previously selected dataset collection has elements that are deleted.", self.name
                    )
        return rval

    def to_text(self, value):
+17 −0
Original line number Diff line number Diff line
@@ -576,6 +576,23 @@ steps:
        if output_dataset_paths_exist:
            wait_on(paths_deleted, "path deletion")

    def test_submission_on_collection_with_deleted_element(self, history_id):
        hdca = self.dataset_collection_populator.create_list_of_list_in_history(history_id=history_id, wait=True).json()
        hda_id = hdca["elements"][0]["object"]["elements"][0]["object"]["id"]
        self.dataset_populator.delete_dataset(history_id=history_id, content_id=hda_id)
        response = self.dataset_populator.run_tool_raw(
            "is_of_type",
            inputs={
                "collection": {"batch": True, "values": [{"src": "hdca", "id": hdca["id"], "map_over_type": "list"}]},
            },
            history_id=history_id,
        )
        assert response.status_code == 400
        assert (
            response.json()["err_msg"]
            == "parameter 'collection': the previously selected dataset collection has elements that are deleted."
        )

    @pytest.mark.require_new_history
    @skip_without_tool("create_2")
    def test_purging_output_cleaned_after_ok_run(self, history_id):