From 44a67b55072f6a7008fe4f4c8b94d2eb998100b4 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Wed, 19 Oct 2022 14:29:37 -0700 Subject: [PATCH 1/4] refactor invocations api into separate fastapi class --- lib/galaxy/webapps/galaxy/api/workflows.py | 54 ++++++++++++---------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 38f2486a4ee..7ea842fb76c 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -1239,7 +1239,6 @@ SkipStepCountsQueryParam: bool = Query( @router.cbv class FastAPIWorkflows: service: WorkflowsService = depends(WorkflowsService) - invocations_service: InvocationsService = depends(InvocationsService) @router.get( "/api/workflows", @@ -1368,6 +1367,35 @@ class FastAPIWorkflows: self.service.shareable_service.set_slug(trans, id, payload) return Response(status_code=status.HTTP_204_NO_CONTENT) + @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) + + +@router.cbv +class FastAPIInvocations: + invocations_service: InvocationsService = depends(InvocationsService) + @router.post( "/api/invocations/{invocation_id}/prepare_store_download", summary="Prepare a workflow invocation export-style download.", @@ -1401,30 +1429,6 @@ 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", From 9f1680a81e543afcdef643462480fb7a79a1b213 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Fri, 21 Oct 2022 11:37:27 -0700 Subject: [PATCH 2/4] refactor workflow versions API into fastapi --- lib/galaxy/webapps/galaxy/api/workflows.py | 36 +++++++++---------- lib/galaxy/webapps/galaxy/buildapp.py | 7 ---- .../webapps/galaxy/services/workflows.py | 9 +++++ 3 files changed, 25 insertions(+), 27 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 7ea842fb76c..132679d9a6a 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -267,26 +267,6 @@ class WorkflowsAPIController( break return self.workflow_contents_manager.workflow_to_dict(trans, stored_workflow, style=style, version=version) - @expose_api - def show_versions(self, trans: GalaxyWebTransaction, workflow_id, **kwds): - """ - GET /api/workflows/{encoded_workflow_id}/versions - - :param instance: true if fetch by Workflow ID instead of StoredWorkflow id, false - by default. - :type instance: boolean - - Lists all versions of this workflow. - """ - instance = util.string_as_bool(kwds.get("instance", "false")) - stored_workflow = self.workflow_manager.get_stored_accessible_workflow( - trans, workflow_id, by_stored_id=not instance - ) - return [ - {"version": i, "update_time": w.update_time.isoformat(), "steps": len(w.steps)} - for i, w in enumerate(reversed(stored_workflow.workflows)) - ] - @expose_api def create(self, trans: GalaxyWebTransaction, payload=None, **kwd): """ @@ -1205,6 +1185,10 @@ OffsetQueryParam: Optional[int] = Query( title="Number of workflows to skip in sorted query (to enable pagination).", ) +InstanceQueryParam: Optional[bool] = Query( + default=False, title="True when fetching by Workflow ID, False when fetching by StoredWorkflow ID." +) + query_tags = [ IndexQueryTag("name", "The stored workflow's name.", "n"), IndexQueryTag( @@ -1391,6 +1375,18 @@ class FastAPIWorkflows: self.service.undelete(trans, workflow_id) return Response(status_code=status.HTTP_204_NO_CONTENT) + @router.get( + "/api/workflows/{workflow_id}/versions", + summary="List all versions of a workflow.", + ) + def show_versions( + self, + trans: ProvidesUserContext = DependsOnTrans, + workflow_id: DecodedDatabaseIdField = StoredWorkflowIDPathParam, + instance: Optional[bool] = InstanceQueryParam, + ): + return self.service.get_versions(trans, workflow_id, instance) + @router.cbv class FastAPIInvocations: diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index ec91cd6cdf0..5b499f2db4d 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -634,13 +634,6 @@ def populate_api_routes(webapp, app): action="workflow_dict", conditions=dict(method=["GET"]), ) - webapp.mapper.connect( - "show_versions", - "/api/workflows/{workflow_id}/versions", - controller="workflows", - action="show_versions", - conditions=dict(method=["GET"]), - ) # Preserve the following download route for now for dependent applications -- deprecate at some point webapp.mapper.connect( "workflow_dict", diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index c96f654de33..3a33a19c413 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -109,6 +109,15 @@ class WorkflowsService(ServiceBase): self._workflows_manager.check_security(trans, workflow_to_undelete) self._workflows_manager.undelete(workflow_to_undelete) + def get_versions(self, trans, workflow_id, instance): + stored_workflow = self._workflows_manager.get_stored_accessible_workflow( + trans, workflow_id, by_stored_id=not instance + ) + return [ + {"version": i, "update_time": w.update_time.isoformat(), "steps": len(w.steps)} + for i, w in enumerate(reversed(stored_workflow.workflows)) + ] + def __get_full_shed_url(self, url): for shed_url in self._tool_shed_registry.tool_sheds.values(): if url in shed_url: From 3555042f896283e9953405d541a4035585311813 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Fri, 21 Oct 2022 16:13:51 -0700 Subject: [PATCH 3/4] port workflows/menu to fastapi --- lib/galaxy/webapps/galaxy/api/workflows.py | 80 ++++++------------- lib/galaxy/webapps/galaxy/buildapp.py | 3 - .../webapps/galaxy/services/workflows.py | 21 ++++- 3 files changed, 45 insertions(+), 59 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/api/workflows.py b/lib/galaxy/webapps/galaxy/api/workflows.py index 132679d9a6a..2c424480ed6 100644 --- a/lib/galaxy/webapps/galaxy/api/workflows.py +++ b/lib/galaxy/webapps/galaxy/api/workflows.py @@ -137,17 +137,6 @@ class WorkflowsAPIController( self.workflow_contents_manager = app.workflow_contents_manager self.tool_recommendations = recommendations.ToolRecommendations() - @expose_api - def get_workflow_menu(self, trans: ProvidesUserContext, **kwd): - """ - Get workflows present in the tools panel - GET /api/workflows/menu - """ - user = trans.user - ids_in_menu = [x.stored_workflow_id for x in user.stored_workflow_menu_entries] - workflows = self.get_workflows_list(trans, **kwd) - return {"ids_in_menu": ids_in_menu, "workflows": workflows} - @expose_api def set_workflow_menu(self, trans: GalaxyWebTransaction, payload=None, **kwd): """ @@ -187,50 +176,6 @@ class WorkflowsAPIController( trans.set_message(message) return {"message": message, "status": "done"} - def get_workflows_list( - self, - trans: ProvidesUserContext, - missing_tools=False, - show_published=None, - show_shared=None, - show_hidden=False, - show_deleted=False, - **kwd, - ): - """ - Displays a collection of workflows. - - :param show_published: Optional boolean to include published workflows - If unspecified this behavior depends on whether the request - is coming from an authenticated session. The default is true - for annonymous API requests and false otherwise. - :type show_published: boolean - :param show_hidden: if True, show hidden workflows - :type show_hidden: boolean - :param show_deleted: if True, show deleted workflows - :type show_deleted: boolean - :param show_shared: Optional boolean to include shared workflows. - If unspecified this behavior depends on show_deleted/show_hidden. - Defaulting to false if show_hidden or show_deleted is true or else - false. - :param missing_tools: if True, include a list of missing tools per workflow - :type missing_tools: boolean - """ - show_published = util.string_as_bool_or_none(show_published) - show_hidden = util.string_as_bool(show_hidden) - show_deleted = util.string_as_bool(show_deleted) - missing_tools = util.string_as_bool(missing_tools) - show_shared = util.string_as_bool_or_none(show_shared) - payload = WorkflowIndexPayload( - show_published=show_published, - show_hidden=show_hidden, - show_deleted=show_deleted, - show_shared=show_shared, - missing_tools=missing_tools, - ) - workflows, _ = self.service.index(trans, payload) - return workflows - @expose_api_anonymous_and_sessionless def show(self, trans: GalaxyWebTransaction, id, **kwd): """ @@ -1387,6 +1332,31 @@ class FastAPIWorkflows: ): return self.service.get_versions(trans, workflow_id, instance) + @router.get( + "/api/workflows/menu", + summary="Get workflows present in the tools panel.", + ) + def get_workflow_menu( + self, + trans: ProvidesUserContext = DependsOnTrans, + show_deleted: Optional[bool] = DeletedQueryParam, + show_hidden: Optional[bool] = HiddenQueryParam, + missing_tools: Optional[bool] = MissingToolsQueryParam, + show_published: Optional[bool] = ShowPublishedQueryParam, + show_shared: Optional[bool] = ShowSharedQueryParam, + ): + payload = WorkflowIndexPayload( + show_published=show_published, + show_hidden=show_hidden, + show_deleted=show_deleted, + show_shared=show_shared, + missing_tools=missing_tools, + ) + return self.service.get_workflow_menu( + trans, + payload=payload, + ) + @router.cbv class FastAPIInvocations: diff --git a/lib/galaxy/webapps/galaxy/buildapp.py b/lib/galaxy/webapps/galaxy/buildapp.py index 5b499f2db4d..16dc3c2f59f 100644 --- a/lib/galaxy/webapps/galaxy/buildapp.py +++ b/lib/galaxy/webapps/galaxy/buildapp.py @@ -586,9 +586,6 @@ def populate_api_routes(webapp, app): webapp.mapper.resource("visualization", "visualizations", path_prefix="/api") webapp.mapper.resource("plugins", "plugins", path_prefix="/api") webapp.mapper.connect("/api/workflows/build_module", action="build_module", controller="workflows") - webapp.mapper.connect( - "/api/workflows/menu", action="get_workflow_menu", controller="workflows", conditions=dict(method=["GET"]) - ) webapp.mapper.connect( "/api/workflows/menu", action="set_workflow_menu", controller="workflows", conditions=dict(method=["PUT"]) ) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 3a33a19c413..676f96a8dc4 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -7,7 +7,10 @@ from typing import ( Tuple, ) -from galaxy import web +from galaxy import ( + util, + web, +) from galaxy.managers.context import ProvidesUserContext from galaxy.managers.workflows import ( WorkflowContentsManager, @@ -118,6 +121,22 @@ class WorkflowsService(ServiceBase): for i, w in enumerate(reversed(stored_workflow.workflows)) ] + def get_workflow_menu(self, trans, payload): + ids_in_menu = [x.stored_workflow_id for x in trans.user.stored_workflow_menu_entries] + workflows = self._get_workflows_list( + trans, + payload, + ) + return {"ids_in_menu": ids_in_menu, "workflows": workflows} + + def _get_workflows_list( + self, + trans: ProvidesUserContext, + payload, + ): + workflows, _ = self.index(trans, payload) + return workflows + def __get_full_shed_url(self, url): for shed_url in self._tool_shed_registry.tool_sheds.values(): if url in shed_url: From eafdebbbeace471aa943ae38b52d80eb4efc8387 Mon Sep 17 00:00:00 2001 From: Martin Cech Date: Fri, 21 Oct 2022 16:47:27 -0700 Subject: [PATCH 4/4] remove unused import --- lib/galaxy/webapps/galaxy/services/workflows.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/galaxy/webapps/galaxy/services/workflows.py b/lib/galaxy/webapps/galaxy/services/workflows.py index 676f96a8dc4..f714b4cef90 100644 --- a/lib/galaxy/webapps/galaxy/services/workflows.py +++ b/lib/galaxy/webapps/galaxy/services/workflows.py @@ -7,10 +7,7 @@ from typing import ( Tuple, ) -from galaxy import ( - util, - web, -) +from galaxy import web from galaxy.managers.context import ProvidesUserContext from galaxy.managers.workflows import ( WorkflowContentsManager,