trans.response.status = status return output else: rval = [] for k, v in output.items(): if ex_meta_payload is not None: """ If there is extended metadata, store it, attach it to the dataset, and index it """ ex_meta = ExtendedMetadata(ex_meta_payload) trans.sa_session.add(ex_meta) v.extended_metadata = ex_meta trans.sa_session.add(v) trans.sa_session.flush() for path, value in self._scan_json_block(ex_meta_payload): meta_i = ExtendedMetadataIndex(ex_meta, path, value) trans.sa_session.add(meta_i) trans.sa_session.flush() if type(v) == trans.app.model.LibraryDatasetDatasetAssociation: v = v.library_dataset encoded_id = trans.security.encode_id(v.id) if create_type == 'folder': encoded_id = 'F' + encoded_id rval.append( dict(id=encoded_id, name=v.name, url=url_for('library_content', library_id=library_id, id=encoded_id))) return rval
def create(self, trans, library_id, payload, **kwd): """ create( self, trans, library_id, payload, **kwd ) * POST /api/libraries/{library_id}/contents: create a new library file or folder To copy an HDA into a library send ``create_type`` of 'file' and the HDA's encoded id in ``from_hda_id`` (and optionally ``ldda_message``). To copy an HDCA into a library send ``create_type`` of 'file' and the HDCA's encoded id in ``from_hdca_id`` (and optionally ``ldda_message``). :type library_id: str :param library_id: the encoded id of the library where to create the new item :type payload: dict :param payload: dictionary structure containing: * folder_id: the encoded id of the parent folder of the new item * create_type: the type of item to create ('file', 'folder' or 'collection') * from_hda_id: (optional, only if create_type is 'file') the encoded id of an accessible HDA to copy into the library * ldda_message: (optional) the new message attribute of the LDDA created * extended_metadata: (optional) sub-dictionary containing any extended metadata to associate with the item * upload_option: (optional) one of 'upload_file' (default), 'upload_directory' or 'upload_paths' * server_dir: (optional, only if upload_option is 'upload_directory') relative path of the subdirectory of Galaxy ``library_import_dir`` to upload. All and only the files (i.e. no subdirectories) contained in the specified directory will be uploaded. * filesystem_paths: (optional, only if upload_option is 'upload_paths' and the user is an admin) file paths on the Galaxy server to upload to the library, one file per line * link_data_only: (optional, only when upload_option is 'upload_directory' or 'upload_paths') either 'copy_files' (default) or 'link_to_files'. Setting to 'link_to_files' symlinks instead of copying the files * name: (optional, only if create_type is 'folder') name of the folder to create * description: (optional, only if create_type is 'folder') description of the folder to create * tag_using_filename: (optional) create tags on datasets using the file's original name :returns: a dictionary describing the new item unless ``from_hdca_id`` is supplied, in that case a list of such dictionaries is returned. :rtype: object """ if 'create_type' not in payload: trans.response.status = 400 return "Missing required 'create_type' parameter." else: create_type = payload.pop('create_type') if create_type not in ('file', 'folder', 'collection'): trans.response.status = 400 return "Invalid value for 'create_type' parameter ( %s ) specified." % create_type if 'folder_id' not in payload: trans.response.status = 400 return "Missing required 'folder_id' parameter." else: folder_id = payload.pop('folder_id') class_name, folder_id = self.__decode_library_content_id(folder_id) try: # security is checked in the downstream controller parent = self.get_library_folder(trans, folder_id, check_ownership=False, check_accessible=False) except Exception as e: return str(e) # The rest of the security happens in the library_common controller. real_folder_id = trans.security.encode_id(parent.id) # are we copying an HDA to the library folder? # we'll need the id and any message to attach, then branch to that private function from_hda_id, from_hdca_id, ldda_message = (payload.pop( 'from_hda_id', None), payload.pop('from_hdca_id', None), payload.pop('ldda_message', '')) if create_type == 'file': if from_hda_id: return self._copy_hda_to_library_folder( trans, self.hda_manager, self.decode_id(from_hda_id), real_folder_id, ldda_message) if from_hdca_id: return self._copy_hdca_to_library_folder( trans, self.hda_manager, self.decode_id(from_hdca_id), real_folder_id, ldda_message) # check for extended metadata, store it and pop it out of the param # otherwise sanitize_param will have a fit ex_meta_payload = payload.pop('extended_metadata', None) # Now create the desired content object, either file or folder. if create_type == 'file': status, output = trans.webapp.controllers[ 'library_common'].upload_library_dataset( trans, 'api', library_id, real_folder_id, **payload) elif create_type == 'folder': status, output = trans.webapp.controllers[ 'library_common'].create_folder(trans, 'api', real_folder_id, library_id, **payload) elif create_type == 'collection': # Not delegating to library_common, so need to check access to parent # folder here. self.check_user_can_add_to_library_item(trans, parent, check_accessible=True) create_params = api_payload_to_create_params(payload) create_params['parent'] = parent service = trans.app.dataset_collections_service dataset_collection_instance = service.create(**create_params) return [ dictify_dataset_collection_instance( dataset_collection_instance, security=trans.security, parent=parent) ] if status != 200: trans.response.status = status return output else: rval = [] for v in output.values(): if ex_meta_payload is not None: # If there is extended metadata, store it, attach it to the dataset, and index it ex_meta = ExtendedMetadata(ex_meta_payload) trans.sa_session.add(ex_meta) v.extended_metadata = ex_meta trans.sa_session.add(v) trans.sa_session.flush() for path, value in self._scan_json_block(ex_meta_payload): meta_i = ExtendedMetadataIndex(ex_meta, path, value) trans.sa_session.add(meta_i) trans.sa_session.flush() if type(v) == trans.app.model.LibraryDatasetDatasetAssociation: v = v.library_dataset encoded_id = trans.security.encode_id(v.id) if create_type == 'folder': encoded_id = 'F' + encoded_id rval.append( dict(id=encoded_id, name=v.name, url=url_for('library_content', library_id=library_id, id=encoded_id))) return rval
class LibraryContentsController( BaseAPIController, UsesLibraryMixin, UsesLibraryMixinItems ): @web.expose_api # TODO: Add parameter to only get top level of datasets/subfolders. def index( self, trans, library_id, **kwd ): """ GET /api/libraries/{encoded_library_id}/contents Displays a collection (list) of library contents (files and folders). """ rval = [] current_user_roles = trans.get_current_user_roles() def traverse( folder ): admin = trans.user_is_admin() rval = [] for subfolder in folder.active_folders: if not admin: can_access, folder_ids = trans.app.security_agent.check_folder_contents( trans.user, current_user_roles, subfolder ) if (admin or can_access) and not subfolder.deleted: subfolder.api_path = folder.api_path + '/' + subfolder.name subfolder.api_type = 'folder' rval.append( subfolder ) rval.extend( traverse( subfolder ) ) for ld in folder.datasets: if not admin: can_access = trans.app.security_agent.can_access_dataset( current_user_roles, ld.library_dataset_dataset_association.dataset ) if (admin or can_access) and not ld.deleted: log.debug( "type(folder): %s" % type( folder ) ) log.debug( "type(api_path): %s; folder.api_path: %s" % ( type(folder.api_path), folder.api_path ) ) #log.debug( "attributes of folder: %s" % str(dir(folder)) ) ld.api_path = folder.api_path + '/' + ld.name ld.api_type = 'file' rval.append( ld ) return rval try: decoded_library_id = trans.security.decode_id( library_id ) except TypeError: trans.response.status = 400 return "Malformed library id ( %s ) specified, unable to decode." % str( library_id ) try: library = trans.sa_session.query( trans.app.model.Library ).get( decoded_library_id ) except: library = None if not library or not ( trans.user_is_admin() or trans.app.security_agent.can_access_library( current_user_roles, library ) ): trans.response.status = 400 return "Invalid library id ( %s ) specified." % str( library_id ) log.debug( "Root folder type: %s" % type( library.root_folder ) ) encoded_id = 'F' + trans.security.encode_id( library.root_folder.id ) rval.append( dict( id = encoded_id, type = 'folder', name = '/', url = url_for( 'library_content', library_id=library_id, id=encoded_id ) ) ) log.debug( "Root folder attributes: %s" % str(dir(library.root_folder)) ) library.root_folder.api_path = '' for content in traverse( library.root_folder ): encoded_id = trans.security.encode_id( content.id ) if content.api_type == 'folder': encoded_id = 'F' + encoded_id rval.append( dict( id = encoded_id, type = content.api_type, name = content.api_path, url = url_for( 'library_content', library_id=library_id, id=encoded_id, ) ) ) return rval @web.expose_api def show( self, trans, id, library_id, **kwd ): """ GET /api/libraries/{encoded_library_id}/contents/{encoded_content_id} Displays information about a library content (file or folder). """ class_name, content_id = self.__decode_library_content_id( trans, id ) if class_name == 'LibraryFolder': content = self.get_library_folder( trans, content_id, check_ownership=False, check_accessible=True ) else: content = self.get_library_dataset( trans, content_id, check_ownership=False, check_accessible=True ) return self.encode_all_ids( trans, content.get_api_value( view='element' ) ) @web.expose_api def create( self, trans, library_id, payload, **kwd ): """ POST /api/libraries/{encoded_library_id}/contents Creates a new library content item (file or folder). """ create_type = None if 'create_type' not in payload: trans.response.status = 400 return "Missing required 'create_type' parameter." else: create_type = payload.pop( 'create_type' ) if create_type not in ( 'file', 'folder' ): trans.response.status = 400 return "Invalid value for 'create_type' parameter ( %s ) specified." % create_type if 'folder_id' not in payload: trans.response.status = 400 return "Missing requred 'folder_id' parameter." else: folder_id = payload.pop( 'folder_id' ) class_name, folder_id = self.__decode_library_content_id( trans, folder_id ) try: # security is checked in the downstream controller parent = self.get_library_folder( trans, folder_id, check_ownership=False, check_accessible=False ) except Exception, e: return str( e ) # The rest of the security happens in the library_common controller. real_folder_id = trans.security.encode_id( parent.id ) #check for extended metadata, store it and pop it out of the param #otherwise sanitize_param will have a fit ex_meta_payload = None if 'extended_metadata' in payload: ex_meta_payload = payload.pop('extended_metadata') # Now create the desired content object, either file or folder. if create_type == 'file': status, output = trans.webapp.controllers['library_common'].upload_library_dataset( trans, 'api', library_id, real_folder_id, **payload ) elif create_type == 'folder': status, output = trans.webapp.controllers['library_common'].create_folder( trans, 'api', real_folder_id, library_id, **payload ) if status != 200: trans.response.status = status return output else: rval = [] for k, v in output.items(): if ex_meta_payload is not None: """ If there is extended metadata, store it, attach it to the dataset, and index it """ ex_meta = ExtendedMetadata(ex_meta_payload) trans.sa_session.add( ex_meta ) v.extended_metadata = ex_meta trans.sa_session.add(v) trans.sa_session.flush() for path, value in self._scan_json_block(ex_meta_payload): meta_i = ExtendedMetadataIndex(ex_meta, path, value) trans.sa_session.add(meta_i) trans.sa_session.flush() if type( v ) == trans.app.model.LibraryDatasetDatasetAssociation: v = v.library_dataset encoded_id = trans.security.encode_id( v.id ) if create_type == 'folder': encoded_id = 'F' + encoded_id rval.append( dict( id = encoded_id, name = v.name, url = url_for( 'library_content', library_id=library_id, id=encoded_id ) ) ) return rval