Merge pull request #14794 from martenson/workflow-undelete

implement undeleting a workflow
This commit is contained in:
David López
2022-10-20 10:13:40 +02:00
committed by GitHub
4 changed files with 62 additions and 26 deletions
+5 -2
View File
@@ -42,7 +42,10 @@ from galaxy import (
util,
)
from galaxy.job_execution.actions.post import ActionBox
from galaxy.managers import sharable
from galaxy.managers import (
deletable,
sharable,
)
from galaxy.managers.base import decode_id
from galaxy.managers.context import ProvidesUserContext
from galaxy.managers.executables import artifact_class
@@ -107,7 +110,7 @@ INDEX_SEARCH_FILTERS = {
}
class WorkflowsManager(sharable.SharableModelManager):
class WorkflowsManager(sharable.SharableModelManager, deletable.DeletableManagerMixin):
"""Handle CRUD type operations related to workflows. More interesting
stuff regarding workflow execution, step sorting, etc... can be found in
the galaxy.workflow module.
+24 -22
View File
@@ -457,28 +457,6 @@ class WorkflowsAPIController(
else:
return format_return_as_json(ret_dict, pretty=True)
@expose_api
def delete(self, trans: ProvidesUserContext, id, **kwd):
"""
DELETE /api/workflows/{encoded_workflow_id}
Deletes a specified workflow
Author: rpark
copied from galaxy.web.controllers.workflows.py (delete)
"""
stored_workflow = self.__get_stored_workflow(trans, id, **kwd)
# check to see if user has permissions to selected workflow
if stored_workflow.user != trans.user and not trans.user_is_admin:
raise exceptions.InsufficientPermissionsException()
# Mark a workflow as deleted
stored_workflow.deleted = True
trans.sa_session.flush()
# TODO: Unsure of response message to let api know that a workflow was successfully deleted
return f"Workflow '{stored_workflow.name}' successfully deleted"
@expose_api
def import_new_workflow_deprecated(self, trans: GalaxyWebTransaction, payload, **kwd):
"""
@@ -1423,6 +1401,30 @@ class FastAPIWorkflows:
)
return rval
@router.delete(
"/api/workflows/{workflow_id}",
summary="Add the deleted flag to a workflow.",
)
def delete_workflow(
self,
trans: ProvidesUserContext = DependsOnTrans,
workflow_id: DecodedDatabaseIdField = StoredWorkflowIDPathParam,
):
self.service.delete(trans, workflow_id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
@router.post(
"/api/workflows/{workflow_id}/undelete",
summary="Remove the deleted flag from a workflow.",
)
def undelete_workflow(
self,
trans: ProvidesUserContext = DependsOnTrans,
workflow_id: DecodedDatabaseIdField = StoredWorkflowIDPathParam,
):
self.service.undelete(trans, workflow_id)
return Response(status_code=status.HTTP_204_NO_CONTENT)
# TODO: remove this endpoint after 23.1 release
@router.get(
"/api/invocations/{invocation_id}/biocompute",
@@ -99,6 +99,16 @@ class WorkflowsService(ServiceBase):
return workflows, total_matches
return rval, total_matches
def delete(self, trans, workflow_id):
workflow_to_delete = self._workflows_manager.get_stored_workflow(trans, workflow_id)
self._workflows_manager.check_security(trans, workflow_to_delete)
self._workflows_manager.delete(workflow_to_delete)
def undelete(self, trans, workflow_id):
workflow_to_undelete = self._workflows_manager.get_stored_workflow(trans, workflow_id)
self._workflows_manager.check_security(trans, workflow_to_undelete)
self._workflows_manager.undelete(workflow_to_undelete)
def __get_full_shed_url(self, url):
for shed_url in self._tool_shed_registry.tool_sheds.values():
if url in shed_url:
+23 -2
View File
@@ -20,6 +20,7 @@ import yaml
from requests import (
delete,
get,
post,
put,
)
@@ -372,7 +373,7 @@ class TestWorkflowsApi(BaseWorkflowsApiTestCase, ChangeDatatypeTestCase):
self._assert_user_has_workflow_with_name(workflow_name)
workflow_url = self._api_url(f"workflows/{workflow_id}", use_key=True)
delete_response = delete(workflow_url)
self._assert_status_code_is(delete_response, 200)
self._assert_status_code_is(delete_response, 204)
# Make sure workflow is no longer in index by default.
assert workflow_name not in self._workflow_names()
@@ -383,6 +384,26 @@ class TestWorkflowsApi(BaseWorkflowsApiTestCase, ChangeDatatypeTestCase):
delete_response = delete(workflow_url)
self._assert_status_code_is(delete_response, 403)
def test_undelete(self):
workflow_id = self.workflow_populator.simple_workflow("test_undelete")
workflow_name = "test_undelete"
self._assert_user_has_workflow_with_name(workflow_name)
workflow_delete_url = self._api_url(f"workflows/{workflow_id}", use_key=True)
delete(workflow_delete_url)
workflow_undelete_url = self._api_url(f"workflows/{workflow_id}/undelete", use_key=True)
undelete_response = post(workflow_undelete_url)
self._assert_status_code_is(undelete_response, 204)
assert workflow_name in self._workflow_names()
def test_other_cannot_undelete(self):
workflow_id = self.workflow_populator.simple_workflow("test_other_undelete")
workflow_delete_url = self._api_url(f"workflows/{workflow_id}", use_key=True)
delete(workflow_delete_url)
with self._different_user():
workflow_undelete_url = self._api_url(f"workflows/{workflow_id}/undelete", use_key=True)
undelete_response = post(workflow_undelete_url)
self._assert_status_code_is(undelete_response, 403)
def test_index(self):
index_response = self._get("workflows")
self._assert_status_code_is(index_response, 200)
@@ -394,7 +415,7 @@ class TestWorkflowsApi(BaseWorkflowsApiTestCase, ChangeDatatypeTestCase):
assert [w for w in workflow_index if w["id"] == workflow_id]
workflow_url = self._api_url(f"workflows/{workflow_id}", use_key=True)
delete_response = delete(workflow_url)
self._assert_status_code_is(delete_response, 200)
self._assert_status_code_is(delete_response, 204)
workflow_index = self._get("workflows").json()
assert not [w for w in workflow_index if w["id"] == workflow_id]
workflow_index = self._get("workflows?show_deleted=true").json()