Source code for galaxy.webapps.galaxy.api.lda_datasets

"""
API operations on the library datasets.
"""
import glob
import os
import os.path
import string
import sys
import tempfile
import zipfile
from galaxy import exceptions
from galaxy import util
from galaxy import web
from galaxy.exceptions import ObjectNotFound
from galaxy.managers import folders, roles
from galaxy.tools.actions import upload_common
from galaxy.util.json import dumps
from galaxy.util.streamball import StreamBall
from galaxy.web import _future_expose_api as expose_api
from galaxy.web import _future_expose_api_anonymous as expose_api_anonymous
from galaxy.web.base.controller import BaseAPIController, UsesVisualizationMixin
from paste.httpexceptions import HTTPBadRequest, HTTPInternalServerError
from sqlalchemy.orm.exc import MultipleResultsFound
from sqlalchemy.orm.exc import NoResultFound


import logging
log = logging.getLogger( __name__ )


[docs]class LibraryDatasetsController( BaseAPIController, UsesVisualizationMixin ): def __init__( self, app ): super( LibraryDatasetsController, self ).__init__( app ) self.folder_manager = folders.FolderManager() self.role_manager = roles.RoleManager( app ) @expose_api_anonymous
[docs] def show( self, trans, id, **kwd ): """ show( self, trans, id, **kwd ) * GET /api/libraries/datasets/{encoded_dataset_id}: Displays information about the dataset identified by the encoded ID. :param id: the encoded id of the dataset to query :type id: an encoded id string :returns: detailed dataset information from base controller :rtype: dictionary .. seealso:: :attr:`galaxy.web.base.controller.UsesLibraryMixinItems.get_library_dataset` """ try: library_dataset = self.get_library_dataset( trans, id=id, check_ownership=False, check_accessible=True ) except Exception: raise exceptions.ObjectNotFound( 'Requested library_dataset was not found.' ) current_user_roles = trans.get_current_user_roles() # Build the full path for breadcrumb purposes. full_path = self._build_path( trans, library_dataset.folder ) dataset_item = ( trans.security.encode_id( library_dataset.id ), library_dataset.name ) full_path.insert(0, dataset_item) full_path = full_path[ ::-1 ] # Find expired versions of the library dataset expired_ldda_versions = [] for expired_ldda in library_dataset.expired_datasets: expired_ldda_versions.append( ( trans.security.encode_id( expired_ldda.id ), expired_ldda.name ) ) rval = trans.security.encode_all_ids( library_dataset.to_dict() ) if len(expired_ldda_versions) > 0: rval[ 'has_versions' ] = True rval[ 'expired_versions' ] = expired_ldda_versions rval[ 'deleted' ] = library_dataset.deleted rval[ 'folder_id' ] = 'F' + rval[ 'folder_id' ] rval[ 'full_path' ] = full_path rval[ 'file_size' ] = util.nice_size( int( library_dataset.library_dataset_dataset_association.get_size() ) ) rval[ 'date_uploaded' ] = library_dataset.library_dataset_dataset_association.create_time.strftime( "%Y-%m-%d %I:%M %p" ) rval[ 'can_user_modify' ] = trans.app.security_agent.can_modify_library_item( current_user_roles, library_dataset) or trans.user_is_admin() rval[ 'is_unrestricted' ] = trans.app.security_agent.dataset_is_public( library_dataset.library_dataset_dataset_association.dataset ) # Manage dataset permission is always attached to the dataset itself, not the the ld or ldda to maintain consistency rval[ 'can_user_manage' ] = trans.app.security_agent.can_manage_dataset( current_user_roles, library_dataset.library_dataset_dataset_association.dataset) or trans.user_is_admin() return rval
@expose_api_anonymous
[docs] def show_version( self, trans, encoded_dataset_id, encoded_ldda_id, **kwd ): """ show_version( self, trans, encoded_dataset_id, encoded_ldda_id, **kwd ): * GET /api/libraries/datasets/:encoded_dataset_id/versions/:encoded_ldda_id Displays information about specific version of the library_dataset (i.e. ldda). :param encoded_dataset_id: the encoded id of the dataset to query :type encoded_dataset_id: an encoded id string :param encoded_ldda_id: the encoded id of the ldda to query :type encoded_ldda_id: an encoded id string :rtype: dictionary :returns: dict of ldda's details """ try: library_dataset = self.get_library_dataset( trans, id=encoded_dataset_id, check_ownership=False, check_accessible=True ) except Exception: raise exceptions.ObjectNotFound( 'Requested library_dataset was not found.' ) try: ldda = self.get_library_dataset_dataset_association( trans, id=encoded_ldda_id, check_ownership=False, check_accessible=False ) except Exception, e: raise exceptions.ObjectNotFound( 'Requested version of library dataset was not found.' + str(e) ) if ldda not in library_dataset.expired_datasets: raise exceptions.ObjectNotFound( 'Given library dataset does not have the requested version.' ) rval = trans.security.encode_all_ids( ldda.to_dict() ) return rval
@expose_api
[docs] def show_roles( self, trans, encoded_dataset_id, **kwd ): """ show_roles( self, trans, id, **kwd ): * GET /api/libraries/datasets/{encoded_dataset_id}/permissions Displays information about current or available roles for a given dataset permission. :param encoded_dataset_id: the encoded id of the dataset to query :type encoded_dataset_id: an encoded id string :param scope: either 'current' or 'available' :type scope: string :rtype: dictionary :returns: either dict of current roles for all permission types or dict of available roles to choose from (is the same for any permission type) """ current_user_roles = trans.get_current_user_roles() try: library_dataset = self.get_library_dataset( trans, id=encoded_dataset_id, check_ownership=False, check_accessible=False ) except Exception, e: raise exceptions.ObjectNotFound( 'Requested dataset was not found.' + str(e) ) dataset = library_dataset.library_dataset_dataset_association.dataset # User has to have manage permissions permission in order to see the roles. can_manage = trans.app.security_agent.can_manage_dataset( current_user_roles, dataset ) or trans.user_is_admin() if not can_manage: raise exceptions.InsufficientPermissionsException( 'You do not have proper permission to access permissions.' ) scope = kwd.get( 'scope', None ) if scope == 'current' or scope is None: return self._get_current_roles( trans, library_dataset ) # Return roles that are available to select. elif scope == 'available': page = kwd.get( 'page', None ) if page is not None: page = int( page ) else: page = 1 page_limit = kwd.get( 'page_limit', None ) if page_limit is not None: page_limit = int( page_limit ) else: page_limit = 10 query = kwd.get( 'q', None ) roles, total_roles = trans.app.security_agent.get_valid_roles( trans, dataset, query, page, page_limit ) return_roles = [] for role in roles: return_roles.append( dict( id=role.name, name=role.name, type=role.type ) ) return dict( roles=return_roles, page=page, page_limit=page_limit, total=total_roles ) else: raise exceptions.RequestParameterInvalidException( "The value of 'scope' parameter is invalid. Alllowed values: current, available" )
def _get_current_roles( self, trans, library_dataset): """ Find all roles currently connected to relevant permissions on the library dataset and the underlying dataset. :param library_dataset: the model object :type library_dataset: LibraryDataset :rtype: dictionary :returns: dict of current roles for all available permission types """ dataset = library_dataset.library_dataset_dataset_association.dataset # Omit duplicated roles by converting to set access_roles = set( dataset.get_access_roles( trans ) ) modify_roles = set( trans.app.security_agent.get_roles_for_action( library_dataset, trans.app.security_agent.permitted_actions.LIBRARY_MODIFY ) ) manage_roles = set( dataset.get_manage_permissions_roles( trans ) ) access_dataset_role_list = [ access_role.name for access_role in access_roles ] manage_dataset_role_list = [ manage_role.name for manage_role in manage_roles ] modify_item_role_list = [ modify_role.name for modify_role in modify_roles ] return dict( access_dataset_roles=access_dataset_role_list, modify_item_roles=modify_item_role_list, manage_dataset_roles=manage_dataset_role_list ) @expose_api
[docs] def update_permissions( self, trans, encoded_dataset_id, **kwd ): """ def update( self, trans, encoded_dataset_id, **kwd ): *POST /api/libraries/datasets/{encoded_dataset_id}/permissions :param encoded_dataset_id: the encoded id of the dataset to update permissions of :type encoded_dataset_id: an encoded id string :param action: (required) describes what action should be performed available actions: make_private, remove_restrictions, set_permissions :type action: string :param access_ids[]: list of Role.name defining roles that should have access permission on the dataset :type access_ids[]: string or list :param manage_ids[]: list of Role.name defining roles that should have manage permission on the dataset :type manage_ids[]: string or list :param modify_ids[]: list of Role.name defining roles that should have modify permission on the library dataset item :type modify_ids[]: string or list :rtype: dictionary :returns: dict of current roles for all available permission types :raises: RequestParameterInvalidException, ObjectNotFound, InsufficientPermissionsException, InternalServerError RequestParameterMissingException """ try: library_dataset = self.get_library_dataset( trans, id=encoded_dataset_id, check_ownership=False, check_accessible=False ) except Exception, e: raise exceptions.ObjectNotFound( 'Requested dataset was not found.' + str(e) ) dataset = library_dataset.library_dataset_dataset_association.dataset current_user_roles = trans.get_current_user_roles() can_manage = trans.app.security_agent.can_manage_dataset( current_user_roles, dataset ) or trans.user_is_admin() if not can_manage: raise exceptions.InsufficientPermissionsException( 'You do not have proper permissions to manage permissions on this dataset.' ) new_access_roles_ids = kwd.get( 'access_ids[]', None ) new_manage_roles_ids = kwd.get( 'manage_ids[]', None ) new_modify_roles_ids = kwd.get( 'modify_ids[]', None ) action = kwd.get( 'action', None ) if action is None: raise exceptions.RequestParameterMissingException( 'The mandatory parameter "action" is missing.' ) elif action == 'remove_restrictions': trans.app.security_agent.make_dataset_public( dataset ) if not trans.app.security_agent.dataset_is_public( dataset ): raise exceptions.InternalServerError( 'An error occured while making dataset public.' ) elif action == 'make_private': trans.app.security_agent.make_dataset_public( dataset ) private_role = trans.app.security_agent.get_private_user_role( trans.user ) dp = trans.app.model.DatasetPermissions( trans.app.security_agent.permitted_actions.DATASET_ACCESS.action, dataset, private_role ) trans.sa_session.add( dp ) trans.sa_session.flush() if not trans.app.security_agent.dataset_is_private_to_user( trans, library_dataset ): raise exceptions.InternalServerError( 'An error occured while making dataset private.' ) elif action == 'set_permissions': # ACCESS DATASET ROLES valid_access_roles = [] invalid_access_roles_names = [] if new_access_roles_ids is None: trans.app.security_agent.make_dataset_public( dataset ) else: # Check whether we receive only one role, then it is not a list so we make it into one. if isinstance(new_access_roles_ids, basestring): new_access_roles_ids = [ new_access_roles_ids ] for role_id in new_access_roles_ids: role = self._load_role( trans, role_id ) # Check whether role is in the set of allowed roles valid_roles, total_roles = trans.app.security_agent.get_valid_roles( trans, dataset ) if role in valid_roles: valid_access_roles.append( role ) else: invalid_access_roles_names.append( role_id ) if len( invalid_access_roles_names ) > 0: log.warning( "The following roles could not be added to the dataset access permission: " + str( invalid_access_roles_names ) ) access_permission = dict( access=valid_access_roles ) trans.app.security_agent.set_dataset_permission( dataset, access_permission ) # MANAGE DATASET ROLES valid_manage_roles = [] invalid_manage_roles_names = [] new_manage_roles_ids = util.listify( new_manage_roles_ids ) # Load all access roles to check active_access_roles = dataset.get_access_roles( trans ) for role_id in new_manage_roles_ids: role = self._load_role( trans, role_id ) # Check whether role is in the set of access roles if role in active_access_roles: valid_manage_roles.append( role ) else: invalid_manage_roles_names.append( role_id ) if len( invalid_manage_roles_names ) > 0: log.warning( "The following roles could not be added to the dataset manage permission: " + str( invalid_manage_roles_names ) ) manage_permission = { trans.app.security_agent.permitted_actions.DATASET_MANAGE_PERMISSIONS: valid_manage_roles } trans.app.security_agent.set_dataset_permission( dataset, manage_permission ) # MODIFY LIBRARY ITEM ROLES valid_modify_roles = [] invalid_modify_roles_names = [] new_modify_roles_ids = util.listify( new_modify_roles_ids ) # Load all access roles to check active_access_roles = dataset.get_access_roles( trans ) for role_id in new_modify_roles_ids: role = self._load_role( trans, role_id ) # Check whether role is in the set of access roles if role in active_access_roles: valid_modify_roles.append( role ) else: invalid_modify_roles_names.append( role_id ) if len( invalid_modify_roles_names ) > 0: log.warning( "The following roles could not be added to the dataset modify permission: " + str( invalid_modify_roles_names ) ) modify_permission = { trans.app.security_agent.permitted_actions.LIBRARY_MODIFY: valid_modify_roles } trans.app.security_agent.set_library_item_permission( library_dataset, modify_permission ) else: raise exceptions.RequestParameterInvalidException( 'The mandatory parameter "action" has an invalid value. ' 'Allowed values are: "remove_restrictions", "make_private", "set_permissions"' ) return self._get_current_roles( trans, library_dataset )
def _load_role( self, trans, role_name ): """ Method loads the role from the DB based on the given role name. :param role_name: name of the role to load from the DB :type role_name: string :rtype: Role :returns: the loaded Role object :raises: InconsistentDatabase, RequestParameterInvalidException, InternalServerError """ try: role = trans.sa_session.query( trans.app.model.Role ).filter( trans.model.Role.table.c.name == role_name ).one() except MultipleResultsFound: raise exceptions.InconsistentDatabase( 'Multiple roles found with the same name. Name: ' + str( role_name ) ) except NoResultFound: raise exceptions.RequestParameterInvalidException( 'No role found with the name provided. Name: ' + str( role_name ) ) except Exception, e: raise exceptions.InternalServerError( 'Error loading from the database.' + str(e)) return role @expose_api
[docs] def delete( self, trans, encoded_dataset_id, **kwd ): """ delete( self, trans, encoded_dataset_id, **kwd ): * DELETE /api/libraries/datasets/{encoded_dataset_id} Marks the dataset deleted or undeleted based on the value of the undelete flag. If the flag is not present it is considered False and the item is marked deleted. :param encoded_dataset_id: the encoded id of the dataset to change :type encoded_dataset_id: an encoded id string :returns: dict containing information about the dataset :rtype: dictionary """ undelete = util.string_as_bool( kwd.get( 'undelete', False ) ) try: dataset = self.get_library_dataset( trans, id=encoded_dataset_id, check_ownership=False, check_accessible=False ) except Exception, e: raise exceptions.ObjectNotFound( 'Requested dataset was not found.' + str(e) ) current_user_roles = trans.get_current_user_roles() allowed = trans.app.security_agent.can_modify_library_item( current_user_roles, dataset ) if ( not allowed ) and ( not trans.user_is_admin() ): raise exceptions.InsufficientPermissionsException( 'You do not have proper permissions to delete this dataset.') if undelete: dataset.deleted = False else: dataset.deleted = True trans.sa_session.add( dataset ) trans.sa_session.flush() rval = trans.security.encode_all_ids( dataset.to_dict() ) rval[ 'update_time' ] = dataset.update_time.strftime( "%Y-%m-%d %I:%M %p" ) rval[ 'deleted' ] = dataset.deleted rval[ 'folder_id' ] = 'F' + rval[ 'folder_id' ] return rval
@expose_api
[docs] def load( self, trans, **kwd ): """ load( self, trans, **kwd ): * POST /api/libraries/datasets Load dataset from the given source into the library. Source can be: user directory - root folder specified in galaxy.ini as "$user_library_import_dir" example path: path/to/galaxy/$user_library_import_dir/user@example.com/{user can browse everything here} the folder with the user login has to be created beforehand (admin)import directory - root folder specified in galaxy ini as "$library_import_dir" example path: path/to/galaxy/$library_import_dir/{admin can browse everything here} (admin)any absolute or relative path - option allowed with "allow_library_path_paste" in galaxy.ini :param encoded_folder_id: the encoded id of the folder to import dataset(s) to :type encoded_folder_id: an encoded id string :param source: source the datasets should be loaded form :type source: str :param link_data: flag whether to link the dataset to data or copy it to Galaxy, defaults to copy while linking is set to True all symlinks will be resolved _once_ :type link_data: bool :param preserve_dirs: flag whether to preserve the directory structure when importing dir if False only datasets will be imported :type preserve_dirs: bool :param file_type: file type of the loaded datasets, defaults to 'auto' (autodetect) :type file_type: str :param dbkey: dbkey of the loaded genome, defaults to '?' (unknown) :type dbkey: str :returns: dict containing information about the created upload job :rtype: dictionary """ kwd[ 'space_to_tab' ] = 'False' kwd[ 'to_posix_lines' ] = 'True' kwd[ 'dbkey' ] = kwd.get( 'dbkey', '?' ) kwd[ 'file_type' ] = kwd.get( 'file_type', 'auto' ) kwd[' link_data_only' ] = 'link_to_files' if util.string_as_bool( kwd.get( 'link_data', False ) ) else 'copy_files' encoded_folder_id = kwd.get( 'encoded_folder_id', None ) if encoded_folder_id is not None: folder_id = self.folder_manager.cut_and_decode( trans, encoded_folder_id ) else: raise exceptions.RequestParameterMissingException( 'The required atribute encoded_folder_id is missing.' ) path = kwd.get( 'path', None) if path is None: raise exceptions.RequestParameterMissingException( 'The required atribute path is missing.' ) folder = self.folder_manager.get( trans, folder_id ) source = kwd.get( 'source', None ) if source not in [ 'userdir_file', 'userdir_folder', 'importdir_file', 'importdir_folder', 'admin_path' ]: raise exceptions.RequestParameterMissingException( 'You have to specify "source" parameter. Possible values are "userdir_file", "userdir_folder", "admin_path", "importdir_file" and "importdir_folder". ') if source in [ 'importdir_file', 'importdir_folder' ]: if not trans.user_is_admin: raise exceptions.AdminRequiredException( 'Only admins can import from importdir.' ) if not trans.app.config.library_import_dir: raise exceptions.ConfigDoesNotAllowException( 'The configuration of this Galaxy instance does not allow admins to import into library from importdir.' ) import_base_dir = trans.app.config.library_import_dir path = os.path.join( import_base_dir, path ) if source in [ 'userdir_file', 'userdir_folder' ]: user_login = trans.user.email user_base_dir = trans.app.config.user_library_import_dir if user_base_dir is None: raise exceptions.ConfigDoesNotAllowException( 'The configuration of this Galaxy instance does not allow upload from user directories.' ) full_dir = os.path.join( user_base_dir, user_login ) if not path.lower().startswith( full_dir.lower() ): path = os.path.join( full_dir, path ) if not os.path.exists( path ): raise exceptions.RequestParameterInvalidException( 'Given path does not exist on the host.' ) if not self.folder_manager.can_add_item( trans, folder ): raise exceptions.InsufficientPermissionsException( 'You do not have proper permission to add items to the given folder.' ) if source == 'admin_path': if not trans.app.config.allow_library_path_paste: raise exceptions.ConfigDoesNotAllowException( 'The configuration of this Galaxy instance does not allow admins to import into library from path.' ) if not trans.user_is_admin: raise exceptions.AdminRequiredException( 'Only admins can import from path.' ) # Set up the traditional tool state/params tool_id = 'upload1' tool = trans.app.toolbox.get_tool( tool_id ) state = tool.new_state( trans ) tool.update_state( trans, tool.inputs_by_page[ 0 ], state.inputs, kwd ) tool_params = state.inputs dataset_upload_inputs = [] for input in tool.inputs.itervalues(): if input.type == "upload_dataset": dataset_upload_inputs.append( input ) library_bunch = upload_common.handle_library_params( trans, {}, trans.security.encode_id( folder.id ) ) abspath_datasets = [] kwd[ 'filesystem_paths' ] = path if source in [ 'importdir_folder' ]: kwd[ 'filesystem_paths' ] = os.path.join( import_base_dir, path ) params = util.Params( kwd ) # user wants to import one file only if source in [ "userdir_file", "importdir_file" ]: file = os.path.abspath( path ) abspath_datasets.append( trans.webapp.controllers[ 'library_common' ].make_library_uploaded_dataset( trans, 'api', params, os.path.basename( file ), file, 'server_dir', library_bunch ) ) # user wants to import whole folder if source == "userdir_folder": uploaded_datasets_bunch = trans.webapp.controllers[ 'library_common' ].get_path_paste_uploaded_datasets( trans, 'api', params, library_bunch, 200, '' ) uploaded_datasets = uploaded_datasets_bunch[ 0 ] if uploaded_datasets is None: raise exceptions.ObjectNotFound( 'Given folder does not contain any datasets.' ) for ud in uploaded_datasets: ud.path = os.path.abspath( ud.path ) abspath_datasets.append( ud ) # user wants to import from path if source in [ "admin_path", "importdir_folder" ]: # validate the path is within root uploaded_datasets_bunch = trans.webapp.controllers[ 'library_common' ].get_path_paste_uploaded_datasets( trans, 'api', params, library_bunch, 200, '' ) uploaded_datasets = uploaded_datasets_bunch[0] if uploaded_datasets is None: raise exceptions.ObjectNotFound( 'Given folder does not contain any datasets.' ) for ud in uploaded_datasets: ud.path = os.path.abspath( ud.path ) abspath_datasets.append( ud ) json_file_path = upload_common.create_paramfile( trans, abspath_datasets ) data_list = [ ud.data for ud in abspath_datasets ] job, output = upload_common.create_job( trans, tool_params, tool, json_file_path, data_list, folder=folder ) # HACK: Prevent outputs_to_working_directory from overwriting inputs when "linking" job.add_parameter( 'link_data_only', dumps( kwd.get( 'link_data_only', 'copy_files' ) ) ) job.add_parameter( 'uuid', dumps( kwd.get( 'uuid', None ) ) ) trans.sa_session.add( job ) trans.sa_session.flush() job_dict = job.to_dict() job_dict[ 'id' ] = trans.security.encode_id( job_dict[ 'id' ] ) return job_dict
@web.expose # TODO convert to expose_api
[docs] def download( self, trans, format, **kwd ): """ download( self, trans, format, **kwd ) * GET /api/libraries/datasets/download/{format} * POST /api/libraries/datasets/download/{format} Downloads requested datasets (identified by encoded IDs) in requested format. example: ``GET localhost:8080/api/libraries/datasets/download/tbz?ld_ids%255B%255D=a0d84b45643a2678&ld_ids%255B%255D=fe38c84dcd46c828`` .. note:: supported format values are: 'zip', 'tgz', 'tbz', 'uncompressed' :param format: string representing requested archive format :type format: string :param ld_ids[]: an array of encoded ids :type ld_ids[]: an array :rtype: file :returns: either archive with the requested datasets packed inside or a single uncompressed dataset :raises: MessageException, ItemDeletionException, ItemAccessibilityException, HTTPBadRequest, OSError, IOError, ObjectNotFound """ library_datasets = [] datasets_to_download = kwd.get( 'ld_ids%5B%5D', None ) if datasets_to_download is None: datasets_to_download = kwd.get( 'ld_ids', None ) if datasets_to_download is not None: datasets_to_download = util.listify( datasets_to_download ) for dataset_id in datasets_to_download: try: library_dataset = self.get_library_dataset( trans, id=dataset_id, check_ownership=False, check_accessible=True ) library_datasets.append( library_dataset ) except HTTPBadRequest, e: raise exceptions.RequestParameterInvalidException( 'Bad Request.' ) except HTTPInternalServerError, e: raise exceptions.InternalServerError( 'Internal error.' ) except Exception, e: raise exceptions.InternalServerError( 'Unknown error.' ) else: raise exceptions.RequestParameterMissingException( 'Request has to contain a list of dataset ids to download.' ) if format in [ 'zip', 'tgz', 'tbz' ]: # error = False killme = string.punctuation + string.whitespace trantab = string.maketrans( killme, '_' * len( killme ) ) try: outext = 'zip' if format == 'zip': # Can't use mkstemp - the file must not exist first tmpd = tempfile.mkdtemp() util.umask_fix_perms( tmpd, trans.app.config.umask, 0777, self.app.config.gid ) tmpf = os.path.join( tmpd, 'library_download.' + format ) if trans.app.config.upstream_gzip: archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_STORED, True ) else: archive = zipfile.ZipFile( tmpf, 'w', zipfile.ZIP_DEFLATED, True ) archive.add = lambda x, y: archive.write( x, y.encode( 'CP437' ) ) elif format == 'tgz': if trans.app.config.upstream_gzip: archive = StreamBall( 'w|' ) outext = 'tar' else: archive = StreamBall( 'w|gz' ) outext = 'tgz' elif format == 'tbz': archive = StreamBall( 'w|bz2' ) outext = 'tbz2' except ( OSError, zipfile.BadZipfile ): log.exception( "Unable to create archive for download" ) raise exceptions.InternalServerError( "Unable to create archive for download." ) except Exception: log.exception( "Unexpected error %s in create archive for download" % sys.exc_info()[ 0 ] ) raise exceptions.InternalServerError( "Unable to create archive for download." ) composite_extensions = trans.app.datatypes_registry.get_composite_extensions() seen = [] for ld in library_datasets: ldda = ld.library_dataset_dataset_association ext = ldda.extension is_composite = ext in composite_extensions path = "" parent_folder = ldda.library_dataset.folder while parent_folder is not None: # Exclude the now-hidden "root folder" if parent_folder.parent is None: path = os.path.join( parent_folder.library_root[ 0 ].name, path ) break path = os.path.join( parent_folder.name, path ) parent_folder = parent_folder.parent path += ldda.name while path in seen: path += '_' seen.append( path ) zpath = os.path.split(path)[ -1 ] # comes as base_name/fname outfname, zpathext = os.path.splitext( zpath ) if is_composite: # need to add all the components from the extra_files_path to the zip if zpathext == '': zpath = '%s.html' % zpath # fake the real nature of the html file try: if format == 'zip': archive.add( ldda.dataset.file_name, zpath ) # add the primary of a composite set else: archive.add( ldda.dataset.file_name, zpath, check_file=True ) # add the primary of a composite set except IOError: log.exception( "Unable to add composite parent %s to temporary library download archive" % ldda.dataset.file_name ) raise exceptions.InternalServerError( "Unable to create archive for download." ) except ObjectNotFound: log.exception( "Requested dataset %s does not exist on the host." % ldda.dataset.file_name ) raise exceptions.ObjectNotFound( "Requested dataset not found. " ) except Exception, e: log.exception( "Unable to add composite parent %s to temporary library download archive" % ldda.dataset.file_name ) raise exceptions.InternalServerError( "Unable to add composite parent to temporary library download archive. " + str( e ) ) flist = glob.glob(os.path.join(ldda.dataset.extra_files_path, '*.*')) # glob returns full paths for fpath in flist: efp, fname = os.path.split(fpath) if fname > '': fname = fname.translate(trantab) try: if format == 'zip': archive.add( fpath, fname ) else: archive.add( fpath, fname, check_file=True ) except IOError: log.exception( "Unable to add %s to temporary library download archive %s" % ( fname, outfname) ) raise exceptions.InternalServerError( "Unable to create archive for download." ) except ObjectNotFound: log.exception( "Requested dataset %s does not exist on the host." % fpath ) raise exceptions.ObjectNotFound( "Requested dataset not found." ) except Exception, e: log.exception( "Unable to add %s to temporary library download archive %s" % ( fname, outfname ) ) raise exceptions.InternalServerError( "Unable to add dataset to temporary library download archive . " + str( e ) ) else: # simple case try: if format == 'zip': archive.add( ldda.dataset.file_name, path ) else: archive.add( ldda.dataset.file_name, path, check_file=True ) except IOError: log.exception( "Unable to write %s to temporary library download archive" % ldda.dataset.file_name ) raise exceptions.InternalServerError( "Unable to create archive for download" ) except ObjectNotFound: log.exception( "Requested dataset %s does not exist on the host." % ldda.dataset.file_name ) raise exceptions.ObjectNotFound( "Requested dataset not found." ) except Exception, e: log.exception( "Unable to add %s to temporary library download archive %s" % ( fname, outfname ) ) raise exceptions.InternalServerError( "Unknown error. " + str( e ) ) lname = 'selected_dataset' fname = lname.replace( ' ', '_' ) + '_files' if format == 'zip': archive.close() trans.response.set_content_type( "application/octet-stream" ) trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.%s"' % ( fname, outext ) archive = util.streamball.ZipBall( tmpf, tmpd ) archive.wsgi_status = trans.response.wsgi_status() archive.wsgi_headeritems = trans.response.wsgi_headeritems() return archive.stream else: trans.response.set_content_type( "application/x-tar" ) trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s.%s"' % ( fname, outext ) archive.wsgi_status = trans.response.wsgi_status() archive.wsgi_headeritems = trans.response.wsgi_headeritems() return archive.stream elif format == 'uncompressed': if len(library_datasets) != 1: raise exceptions.RequestParameterInvalidException( "You can download only one uncompressed file at once." ) else: single_ld = library_datasets[ 0 ] ldda = single_ld.library_dataset_dataset_association dataset = ldda.dataset fStat = os.stat( dataset.file_name ) trans.response.set_content_type( ldda.get_mime() ) trans.response.headers[ 'Content-Length' ] = int( fStat.st_size ) valid_chars = '.,^_-()[]0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' fname = ldda.name fname = ''.join( c in valid_chars and c or '_' for c in fname )[ 0:150 ] trans.response.headers[ "Content-Disposition" ] = 'attachment; filename="%s"' % fname try: return open( dataset.file_name ) except: raise exceptions.InternalServerError( "This dataset contains no content." ) else: raise exceptions.RequestParameterInvalidException( "Wrong format parameter specified" )
def _build_path( self, trans, folder ): """ Search the path upwards recursively and load the whole route of names and ids for breadcrumb building purposes. :param folder: current folder for navigating up :param type: Galaxy LibraryFolder :returns: list consisting of full path to the library :type: list """ path_to_root = [] # We are almost in root if folder.parent_id is None: path_to_root.append( ( 'F' + trans.security.encode_id( folder.id ), folder.name ) ) else: # We add the current folder and traverse up one folder. path_to_root.append( ( 'F' + trans.security.encode_id( folder.id ), folder.name ) ) upper_folder = trans.sa_session.query( trans.app.model.LibraryFolder ).get( folder.parent_id ) path_to_root.extend( self._build_path( trans, upper_folder ) ) return path_to_root