From 7a574436137a298d64597e791147756e63a9abe3 Mon Sep 17 00:00:00 2001 From: Arash Date: Thu, 26 Sep 2024 11:29:06 +0200 Subject: [PATCH] Refactor library content routes and controllers --- client/src/api/schema/schema.ts | 36 +++++++++++------ lib/galaxy/actions/library.py | 6 ++- lib/galaxy/schema/library_contents.py | 19 +++++---- .../webapps/galaxy/api/library_contents.py | 4 +- .../galaxy/services/library_contents.py | 40 +++++++------------ 5 files changed, 55 insertions(+), 50 deletions(-) diff --git a/client/src/api/schema/schema.ts b/client/src/api/schema/schema.ts index 2914e057011c..1ba29e901647 100644 --- a/client/src/api/schema/schema.ts +++ b/client/src/api/schema/schema.ts @@ -12920,8 +12920,8 @@ export interface components { */ upload_option: components["schemas"]["UploadOption"] | null; }; - /** LibraryContentsCreateDatasetListResponse */ - LibraryContentsCreateDatasetListResponse: components["schemas"]["LibraryContentsCreateDatasetResponse"][]; + /** LibraryContentsCreateDatasetCollectionResponse */ + LibraryContentsCreateDatasetCollectionResponse: components["schemas"]["LibraryContentsCreateDatasetResponse"][]; /** LibraryContentsCreateDatasetResponse */ LibraryContentsCreateDatasetResponse: { /** Created From Basename */ @@ -12948,8 +12948,13 @@ export interface components { misc_blurb: string | null; /** Misc Info */ misc_info: string | null; - /** Model Class */ - model_class: string; + /** + * Model class + * @description The name of the database model class. + * @constant + * @enum {string} + */ + model_class: "LibraryDatasetDatasetAssociation"; /** Name */ name: string; /** Parent Library Id */ @@ -13192,7 +13197,13 @@ export interface components { misc_blurb: string | null; /** Misc Info */ misc_info: string | null; - model_class: components["schemas"]["ModelClass"]; + /** + * Model class + * @description The name of the database model class. + * @constant + * @enum {string} + */ + model_class: "LibraryDataset"; /** Name */ name: string; /** @@ -13231,7 +13242,13 @@ export interface components { item_count: number; /** Library Path */ library_path: string[]; - model_class: components["schemas"]["ModelClass"]; + /** + * Model class + * @description The name of the database model class. + * @constant + * @enum {string} + */ + model_class: "LibraryFolder"; /** Name */ name: string; /** Parent Id */ @@ -13807,11 +13824,6 @@ export interface components { */ time: string; }; - /** - * ModelClass - * @enum {string} - */ - ModelClass: "LibraryDataset" | "LibraryFolder"; /** * ModelStoreFormat * @description Available types of model stores for export. @@ -27943,7 +27955,7 @@ export interface operations { "application/json": | components["schemas"]["LibraryContentsCreateFolderListResponse"] | components["schemas"]["LibraryContentsCreateFileListResponse"] - | components["schemas"]["LibraryContentsCreateDatasetListResponse"] + | components["schemas"]["LibraryContentsCreateDatasetCollectionResponse"] | components["schemas"]["LibraryContentsCreateDatasetResponse"]; }; }; diff --git a/lib/galaxy/actions/library.py b/lib/galaxy/actions/library.py index 570f69bb4754..bad496686aba 100644 --- a/lib/galaxy/actions/library.py +++ b/lib/galaxy/actions/library.py @@ -135,9 +135,11 @@ def _upload_dataset(self, trans, folder_id: int, payload): trans, payload, full_dir, import_dir_desc, library_bunch ) elif payload.upload_option == "upload_paths": - uploaded_datasets, _, _ = self._get_path_paste_uploaded_datasets( + uploaded_datasets, response_code, message = self._get_path_paste_uploaded_datasets( trans, payload.model_dump(), library_bunch, 200, None ) + if response_code != 200: + raise exceptions.RequestParameterInvalidException(message) if payload.upload_option == "upload_file" and not uploaded_datasets: raise exceptions.RequestParameterInvalidException("Select a file, enter a URL or enter text") json_file_path = upload_common.create_paramfile(trans, uploaded_datasets) @@ -311,7 +313,7 @@ def _upload_library_dataset(self, trans, payload, library_id): ) if error: raise exceptions.RequestParameterInvalidException(message) - created_outputs_dict = self._upload_dataset(trans, folder_id=folder.id, payload=payload) + created_outputs_dict = self._upload_dataset(trans, folder.id, payload) return self._create_response(trans, payload, created_outputs_dict, library_id) def _create_folder(self, trans, payload, library_id): diff --git a/lib/galaxy/schema/library_contents.py b/lib/galaxy/schema/library_contents.py index da66a61e6cb2..1af206f857a3 100644 --- a/lib/galaxy/schema/library_contents.py +++ b/lib/galaxy/schema/library_contents.py @@ -12,12 +12,17 @@ Field, RootModel, ) +from typing_extensions import ( + Annotated, + Literal, +) from galaxy.schema.fields import ( DecodedDatabaseIdField, EncodedDatabaseIdField, EncodedLibraryFolderDatabaseIdField, LibraryFolderDatabaseIdField, + ModelClassField, ) from galaxy.schema.schema import ( Model, @@ -42,11 +47,6 @@ class LinkDataOnly(str, Enum): link_to_files = "link_to_files" -class ModelClass(str, Enum): - LibraryDataset = "LibraryDataset" - LibraryFolder = "LibraryFolder" - - class LibraryContentsCreatePayload(Model): create_type: CreateType = Field( ..., @@ -190,7 +190,6 @@ class LibraryContentsIndexListResponse(RootModel): class LibraryContentsShowResponse(Model): - model_class: ModelClass name: str genome_build: Optional[str] update_time: str @@ -198,6 +197,7 @@ class LibraryContentsShowResponse(Model): class LibraryContentsShowFolderResponse(LibraryContentsShowResponse): + model_class: Annotated[Literal["LibraryFolder"], ModelClassField(Literal["LibraryFolder"])] id: EncodedLibraryFolderDatabaseIdField parent_id: Optional[EncodedLibraryFolderDatabaseIdField] description: str @@ -207,6 +207,7 @@ class LibraryContentsShowFolderResponse(LibraryContentsShowResponse): class LibraryContentsShowDatasetResponse(LibraryContentsShowResponse): + model_class: Annotated[Literal["LibraryDataset"], ModelClassField(Literal["LibraryDataset"])] id: EncodedDatabaseIdField ldda_id: EncodedDatabaseIdField folder_id: EncodedLibraryFolderDatabaseIdField @@ -256,7 +257,9 @@ class LibraryContentsCreateDatasetResponse(Model): # functions that are shared by LibraryFolderContentsService too id: str hda_ldda: str - model_class: str + model_class: Annotated[ + Literal["LibraryDatasetDatasetAssociation"], ModelClassField(Literal["LibraryDatasetDatasetAssociation"]) + ] name: str deleted: bool visible: bool @@ -278,7 +281,7 @@ class LibraryContentsCreateDatasetResponse(Model): model_config = ConfigDict(extra="allow") -class LibraryContentsCreateDatasetListResponse(RootModel): +class LibraryContentsCreateDatasetCollectionResponse(RootModel): root: List[LibraryContentsCreateDatasetResponse] diff --git a/lib/galaxy/webapps/galaxy/api/library_contents.py b/lib/galaxy/webapps/galaxy/api/library_contents.py index e719520a8508..451cb42bc6f5 100644 --- a/lib/galaxy/webapps/galaxy/api/library_contents.py +++ b/lib/galaxy/webapps/galaxy/api/library_contents.py @@ -17,7 +17,7 @@ from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.library_contents import ( LibraryContentsCollectionCreatePayload, - LibraryContentsCreateDatasetListResponse, + LibraryContentsCreateDatasetCollectionResponse, LibraryContentsCreateDatasetResponse, LibraryContentsCreateFileListResponse, LibraryContentsCreateFolderListResponse, @@ -97,7 +97,7 @@ def create( ) -> Union[ LibraryContentsCreateFolderListResponse, LibraryContentsCreateFileListResponse, - LibraryContentsCreateDatasetListResponse, + LibraryContentsCreateDatasetCollectionResponse, LibraryContentsCreateDatasetResponse, ]: """ diff --git a/lib/galaxy/webapps/galaxy/services/library_contents.py b/lib/galaxy/webapps/galaxy/services/library_contents.py index 48246e1b7be4..bf8f79ca4181 100644 --- a/lib/galaxy/webapps/galaxy/services/library_contents.py +++ b/lib/galaxy/webapps/galaxy/services/library_contents.py @@ -29,7 +29,7 @@ from galaxy.schema.fields import DecodedDatabaseIdField from galaxy.schema.library_contents import ( LibraryContentsCollectionCreatePayload, - LibraryContentsCreateDatasetListResponse, + LibraryContentsCreateDatasetCollectionResponse, LibraryContentsCreateDatasetResponse, LibraryContentsCreateFileListResponse, LibraryContentsCreateFolderListResponse, @@ -96,14 +96,13 @@ def index( # appending all other items in the library recursively for content in self._traverse(trans, library.root_folder, current_user_roles): url = self._url_for(trans, library_id, content.id, content.api_type) - response_class: Union[ - Type[LibraryContentsIndexFolderResponse], Type[LibraryContentsIndexDatasetResponse] - ] = ( - LibraryContentsIndexFolderResponse - if content.api_type == "folder" - else LibraryContentsIndexDatasetResponse - ) - rval.append(response_class(id=content.id, type=content.api_type, name=content.api_path, url=url)) + response_model: Union[LibraryContentsIndexFolderResponse, LibraryContentsIndexDatasetResponse] + common_args = dict(id=content.id, type=content.api_type, name=content.api_path, url=url) + if content.api_type == "folder": + response_model = LibraryContentsIndexFolderResponse(**common_args) + else: + response_model = LibraryContentsIndexDatasetResponse(**common_args) + rval.append(response_model) return LibraryContentsIndexListResponse(root=rval) def show( @@ -116,20 +115,15 @@ def show( ]: """Returns information about library file or folder.""" class_name, content_id = self._decode_library_content_id(id) - rval: Union[ - LibraryContentsShowFolderResponse, - LibraryContentsShowDatasetResponse, - ] if class_name == "LibraryFolder": content = self.get_library_folder(trans, content_id, check_ownership=False, check_accessible=True) - rval = LibraryContentsShowFolderResponse(**content.to_dict(view="element")) + return LibraryContentsShowFolderResponse(**content.to_dict(view="element")) else: content = self.get_library_dataset(trans, content_id, check_ownership=False, check_accessible=True) rval_dict = content.to_dict(view="element") tag_manager = tags.GalaxyTagHandler(trans.sa_session) rval_dict["tags"] = tag_manager.get_tags_list(content.library_dataset_dataset_association.tags) - rval = LibraryContentsShowDatasetResponse(**rval_dict) - return rval + return LibraryContentsShowDatasetResponse(**rval_dict) def create( self, @@ -141,7 +135,7 @@ def create( ) -> Union[ LibraryContentsCreateFolderListResponse, LibraryContentsCreateFileListResponse, - LibraryContentsCreateDatasetListResponse, + LibraryContentsCreateDatasetCollectionResponse, LibraryContentsCreateDatasetResponse, ]: """Create a new library file or folder.""" @@ -163,7 +157,7 @@ def create( rval = self._copy_hdca_to_library_folder( trans, self.hda_manager, payload.from_hdca_id, payload.folder_id, payload.ldda_message ) - return LibraryContentsCreateDatasetListResponse(root=rval) + return LibraryContentsCreateDatasetCollectionResponse(root=rval) # Now create the desired content object, either file or folder. if payload.create_type == "file": @@ -174,7 +168,7 @@ def create( return LibraryContentsCreateFolderListResponse(root=rval) elif payload.create_type == "collection": rval = self._create_collection(trans, payload, parent) - return LibraryContentsCreateDatasetListResponse(root=rval) + return LibraryContentsCreateDatasetCollectionResponse(root=rval) else: raise exceptions.RequestParameterInvalidException("Invalid create_type specified.") @@ -262,13 +256,7 @@ def _decode_library_content_id( f"Malformed library content id ( {str(content_id)} ) specified, unable to decode." ) - def _url_for( - self, - trans: ProvidesUserContext, - library_id: DecodedDatabaseIdField, - id: int, - type: str, - ) -> Optional[str]: + def _url_for(self, trans: ProvidesUserContext, library_id: DecodedDatabaseIdField, id, type): encoded_id = trans.security.encode_id(id) if type == "folder": encoded_id = f"F{encoded_id}"