def __decode_id(self, trans, encoded_id, object_name=None): """ Try to decode the id. :param object_name: Name of the object the id belongs to. (optional) :type object_name: str """ try: return trans.security.decode_id(encoded_id) except TypeError: raise exceptions.MalformedId('Malformed %s id specified, unable to decode.' % object_name if object_name is not None else '') except ValueError: raise exceptions.MalformedId('Wrong %s id specified, unable to decode.' % object_name if object_name is not None else '')
def __decode_id(trans, workflow_id, model_type="workflow"): try: return trans.security.decode_id(workflow_id) except Exception: message = "Malformed %s id ( %s ) specified, unable to decode" % ( model_type, workflow_id) raise exceptions.MalformedId(message)
def error(self, trans, id, **kwd): """ error( trans, id ) * POST /api/jobs/{id}/error submits a bug report via the API. :type id: string :param id: Encoded job id :rtype: dictionary :returns: dictionary containing information regarding where the error report was sent. """ # Get dataset on which this error was triggered try: decoded_dataset_id = self.decode_id(kwd['dataset_id']) except Exception: raise exceptions.MalformedId() dataset = trans.sa_session.query(trans.app.model.HistoryDatasetAssociation).get(decoded_dataset_id) # Get job job = self.__get_job(trans, id) tool = trans.app.toolbox.get_tool(job.tool_id, tool_version=job.tool_version) or None messages = trans.app.error_reports.default_error_plugin.submit_report( dataset, job, tool, user_submission=True, user=trans.user, email=kwd.get('email', trans.user.email), message=kwd.get('message', None) ) return {'messages': messages}
def index( self, trans, library_id, **kwd ): """ index( self, trans, library_id, **kwd ) * GET /api/libraries/{library_id}/contents: Returns a list of library files and folders. .. note:: May be slow! Returns all content traversing recursively through all folders. .. seealso:: :class:`galaxy.webapps.galaxy.api.FolderContentsController.index` for a non-recursive solution :param library_id: the encoded id of the library :type library_id: str :returns: list of dictionaries of the form: * id: the encoded id of the library item * name: the 'library path' or relationship of the library item to the root * type: 'file' or 'folder' * url: the url to get detailed information on the library item :rtype: list :raises: MalformedId, InconsistentDatabase, RequestParameterInvalidException, InternalServerError """ 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: ld.api_path = folder.api_path + '/' + ld.name ld.api_type = 'file' rval.append( ld ) return rval try: decoded_library_id = self.decode_id( library_id ) except Exception: raise exceptions.MalformedId( 'Malformed library id ( %s ) specified, unable to decode.' % library_id ) try: library = trans.sa_session.query( trans.app.model.Library ).filter( trans.app.model.Library.table.c.id == decoded_library_id ).one() except MultipleResultsFound: raise exceptions.InconsistentDatabase( 'Multiple libraries found with the same id.' ) except NoResultFound: raise exceptions.RequestParameterInvalidException( 'No library found with the id provided.' ) except Exception, e: raise exceptions.InternalServerError( 'Error loading from the database.' + str(e))
def __cut_the_prefix(self, encoded_id): if ((len(encoded_id) % 16 == 1) and encoded_id.startswith('F')): return encoded_id[1:] else: raise exceptions.MalformedId( 'Malformed folder id ( %s ) specified, unable to decode.' % str(encoded_id))
def _decode_id(self, trans, id): try: return trans.security.decode_id(id) except: raise exceptions.MalformedId( "Malformed History id ( %s ) specified, unable to decode" % (str(id)), type='error')
def decode_id(app, id): try: # note: use str - occasionally a fully numeric id will be placed in post body and parsed as int via JSON # resulting in error for valid id return app.security.decode_id(str(id)) except (ValueError, TypeError): msg = "Malformed id ( %s ) specified, unable to decode" % (str(id)) raise exceptions.MalformedId(msg, id=str(id))
def cut_the_prefix( self, encoded_folder_id ): """ Remove the prefix from the encoded folder id. """ if ( ( len( encoded_folder_id ) % 16 == 1 ) and encoded_folder_id.startswith( 'F' ) ): cut_id = encoded_folder_id[ 1: ] else: raise exceptions.MalformedId( 'Malformed folder id ( %s ) specified, unable to decode.' % str( encoded_id ) ) return cut_id
def decode_folder_id( self, trans, encoded_folder_id ): """ Decode the folder id given that it has already lost the prefixed 'F'. """ try: decoded_id = trans.security.decode_id( encoded_folder_id ) except ValueError: raise exceptions.MalformedId( "Malformed folder id ( %s ) specified, unable to decode" % ( str( encoded_folder_id ) ) ) return decoded_id
def __get_job(self, trans, id): try: decoded_job_id = trans.security.decode_id(id) except Exception: raise exceptions.MalformedId() query = trans.sa_session.query(trans.app.model.Job).filter( trans.app.model.Job.user == trans.user, trans.app.model.Job.id == decoded_job_id) job = query.first() if job is None: raise exceptions.ObjectNotFound() return job
def __get_job(self, trans, job_id=None, dataset_id=None, **kwd): if job_id is not None: try: decoded_job_id = self.decode_id(job_id) except Exception: raise exceptions.MalformedId() return self.job_manager.get_accessible_job(trans, decoded_job_id) else: hda_ldda = kwd.get("hda_ldda", "hda") # Following checks dataset accessible dataset_instance = self.get_hda_or_ldda(trans, hda_ldda=hda_ldda, dataset_id=dataset_id) return dataset_instance.creating_job
def delete(self, trans, id, **kwd): """ delete( self, trans, id, **kwd ) * DELETE /api/libraries/{id} marks the library with the given ``id`` as `deleted` (or removes the `deleted` mark if the `undelete` param is true) .. note:: Currently, only admin users can un/delete libraries. :param id: the encoded id of the library to un/delete :type id: an encoded id string :param undelete: (optional) flag specifying whether the item should be deleted or undeleted, defaults to false: :type undelete: bool :returns: detailed library information :rtype: dictionary .. seealso:: :attr:`galaxy.model.Library.dict_element_visible_keys` :raises: ItemAccessibilityException, MalformedId, ObjectNotFound """ undelete = util.string_as_bool(kwd.get('undelete', False)) if not trans.user_is_admin(): raise exceptions.ItemAccessibilityException( 'Only administrators can delete and undelete libraries.') try: decoded_id = trans.security.decode_id(id) except Exception: raise exceptions.MalformedId( 'Malformed library id ( %s ) specified, unable to decode.' % id) try: library = trans.sa_session.query( trans.app.model.Library).get(decoded_id) except Exception: library = None if not library: raise exceptions.ObjectNotFound( 'Library with the id provided ( %s ) was not found' % id) if undelete: library.deleted = False else: library.deleted = True trans.sa_session.add(library) trans.sa_session.flush() return library.to_dict(view='element', value_mapper={ 'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id })
def __get_job(self, trans, id): try: decoded_job_id = self.decode_id(id) except Exception: raise exceptions.MalformedId() job = trans.sa_session.query(trans.app.model.Job).filter(trans.app.model.Job.id == decoded_job_id).first() if job is None: raise exceptions.ObjectNotFound() if not trans.user_is_admin() and job.user != trans.user: if not job.output_datasets: raise exceptions.ItemAccessibilityException("Job has no output datasets.") for data_assoc in job.output_datasets: if not self.dataset_manager.is_accessible(data_assoc.dataset.dataset, trans.user): raise exceptions.ItemAccessibilityException("You are not allowed to rerun this job.") return job
def __decode_library_content_id(self, trans, encoded_folder_id): """ Identify whether the id provided is properly encoded LibraryFolder. :param encoded_folder_id: encoded id of Galaxy LibraryFolder :type encoded_folder_id: encoded string :returns: encoded id of Folder (had 'F' prepended) :type: string :raises: MalformedId """ if ((len(encoded_folder_id) % 16 == 1) and encoded_folder_id.startswith('F')): return encoded_folder_id[1:] else: raise exceptions.MalformedId(f'Malformed folder id ( {str(encoded_folder_id)} ) specified, unable to decode.')
def show(self, trans, id, deleted='False', **kwd): """ show( self, trans, id, deleted='False', **kwd ) * GET /api/libraries/{encoded_id}: returns detailed information about a library * GET /api/libraries/deleted/{encoded_id}: returns detailed information about a ``deleted`` library :param id: the encoded id of the library :type id: an encoded id string :param deleted: if True, allow information on a ``deleted`` library :type deleted: boolean :returns: detailed library information :rtype: dictionary .. seealso:: :attr:`galaxy.model.Library.dict_element_visible_keys` :raises: MalformedId, ObjectNotFound """ library_id = id deleted = util.string_as_bool(deleted) try: decoded_library_id = trans.security.decode_id(library_id) except TypeError: raise exceptions.MalformedId( 'Malformed library id ( %s ) specified, unable to decode.' % id) try: library = trans.sa_session.query( trans.app.model.Library).get(decoded_library_id) assert library.deleted == deleted except Exception: library = None if not library or not (trans.user_is_admin() or trans.app.security_agent.can_access_library( trans.get_current_user_roles(), library)): raise exceptions.ObjectNotFound( 'Library with the id provided ( %s ) was not found' % id) return library.to_dict(view='element', value_mapper={ 'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id })
def __get_job(self, trans, id): try: decoded_job_id = self.decode_id(id) except Exception: raise exceptions.MalformedId() job = trans.sa_session.query(trans.app.model.Job).filter( trans.app.model.Job.id == decoded_job_id).first() if job is None: raise exceptions.ObjectNotFound() belongs_to_user = (job.user == trans.user) if job.user else ( job.session_id == trans.get_galaxy_session().id) if not trans.user_is_admin and not belongs_to_user: # Check access granted via output datasets. if not job.output_datasets: raise exceptions.ItemAccessibilityException( "Job has no output datasets.") for data_assoc in job.output_datasets: if not self.dataset_manager.is_accessible( data_assoc.dataset.dataset, trans.user): raise exceptions.ItemAccessibilityException( "You are not allowed to rerun this job.") trans.sa_session.refresh(job) return job
def create(self, trans, encoded_parent_folder_id, **kwd): """ create( self, trans, encoded_parent_folder_id, **kwd ) *POST /api/folders/{encoded_parent_folder_id} Create a new folder object underneath the one specified in the parameters. :param encoded_parent_folder_id: the parent folder's id (required) :type encoded_parent_folder_id: an encoded id string (should be prefixed by 'F') :param name: the name of the new folder (required) :type name: str :param description: the description of the new folder :type description: str :returns: information about newly created folder, notably including ID :rtype: dictionary :raises: RequestParameterMissingException, MalformedId, InternalServerError """ payload = kwd.get('payload', None) if payload is None: raise exceptions.RequestParameterMissingException( "Missing required parameters 'encoded_parent_folder_id' and 'name'." ) name = payload.get('name', None) description = payload.get('description', '') if encoded_parent_folder_id is None: raise exceptions.RequestParameterMissingException( "Missing required parameter 'encoded_parent_folder_id'.") elif name is None: raise exceptions.RequestParameterMissingException( "Missing required parameter 'name'.") # encoded_parent_folder_id should be prefixed by 'F' encoded_parent_folder_id = self.__cut_the_prefix( encoded_parent_folder_id) try: decoded_parent_folder_id = trans.security.decode_id( encoded_parent_folder_id) except ValueError: raise exceptions.MalformedId( "Malformed folder id ( %s ) specified, unable to decode" % (str(id))) try: parent_folder = trans.sa_session.query( trans.app.model.LibraryFolder).filter( trans.app.model.LibraryFolder.table.c.id == decoded_parent_folder_id).one() except MultipleResultsFound: raise exceptions.InconsistentDatabase( 'Multiple folders found with the same id.') except NoResultFound: raise exceptions.RequestParameterInvalidException( 'No folder found with the id provided.') except Exception, e: raise exceptions.InternalServerError( 'Error loading from the database.' + str(e))
def index( self, trans, folder_id, **kwd ): """ GET /api/folders/{encoded_folder_id}/contents Displays a collection (list) of a folder's contents (files and folders). Encoded folder ID is prepended with 'F' if it is a folder as opposed to a data set which does not have it. Full path is provided in response as a separate object providing data for breadcrumb path building. :param folder_id: encoded ID of the folder which contents should be library_dataset_dict :type folder_id: encoded string :param kwd: keyword dictionary with other params :type kwd: dict :returns: dictionary containing all items and metadata :type: dict :raises: MalformedId, InconsistentDatabase, ObjectNotFound, InternalServerError """ deleted = kwd.get( 'include_deleted', 'missing' ) try: deleted = util.asbool( deleted ) except ValueError: deleted = False if ( len( folder_id ) == 17 and folder_id.startswith( 'F' ) ): try: decoded_folder_id = trans.security.decode_id( folder_id[ 1: ] ) except TypeError: raise exceptions.MalformedId( 'Malformed folder id ( %s ) specified, unable to decode.' % str( folder_id ) ) else: raise exceptions.MalformedId( 'Malformed folder id ( %s ) specified, unable to decode.' % str( folder_id ) ) try: folder = trans.sa_session.query( trans.app.model.LibraryFolder ).filter( trans.app.model.LibraryFolder.table.c.id == decoded_folder_id ).one() except MultipleResultsFound: raise exceptions.InconsistentDatabase( 'Multiple folders with same id found.' ) except NoResultFound: raise exceptions.ObjectNotFound( 'Folder with the id provided ( %s ) was not found' % str( folder_id ) ) except Exception: raise exceptions.InternalServerError( 'Error loading from the database.' ) current_user_roles = trans.get_current_user_roles() # Special level of security on top of libraries. if trans.app.security_agent.can_access_library( current_user_roles, folder.parent_library ): pass else: if trans.user: log.warning( "SECURITY: User (id: %s) without proper access rights is trying to load folder with ID of %s" % ( trans.user.id, decoded_folder_id ) ) else: log.warning( "SECURITY: Anonymous user is trying to load restricted folder with ID of %s" % ( decoded_folder_id ) ) raise exceptions.ObjectNotFound( 'Folder with the id provided ( %s ) was not found' % str( folder_id ) ) # if not ( trans.user_is_admin() or trans.app.security_agent.can_access_library_item( current_user_roles, folder, trans.user ) ): # log.debug('folder parent id: ' + str(folder.parent_id)) # if folder.parent_id is None: # try: # library = trans.sa_session.query( trans.app.model.Library ).filter( trans.app.model.Library.table.c.root_folder_id == decoded_folder_id ).one() # except Exception: # raise exceptions.InternalServerError( 'Error loading from the database.' ) # if trans.app.security_agent.library_is_unrestricted( library ): # pass # else: # if trans.user: # log.warning( "SECURITY: User (id: %s) without proper access rights is trying to load folder with ID of %s" % ( trans.user.id, decoded_folder_id ) ) # else: # log.warning( "SECURITY: Anonymous user without proper access rights is trying to load folder with ID of %s" % ( decoded_folder_id ) ) # raise exceptions.ObjectNotFound( 'Folder with the id provided ( %s ) was not found' % str( folder_id ) ) # else: # if trans.user: # log.warning( "SECURITY: User (id: %s) without proper access rights is trying to load folder with ID of %s" % ( trans.user.id, decoded_folder_id ) ) # else: # log.debug('PARENT ID IS NOT NONE') # log.warning( "SECURITY: Anonymous user without proper access rights is trying to load folder with ID of %s" % ( decoded_folder_id ) ) # raise exceptions.ObjectNotFound( 'Folder with the id provided ( %s ) was not found' % str( folder_id ) ) folder_contents = [] update_time = '' create_time = '' # Go through every accessible item (folders, datasets) in the folder and include its meta-data. for content_item in self._load_folder_contents( trans, folder, deleted ): return_item = {} encoded_id = trans.security.encode_id( content_item.id ) update_time = content_item.update_time.strftime( "%Y-%m-%d %I:%M %p" ) create_time = content_item.create_time.strftime( "%Y-%m-%d %I:%M %p" ) if content_item.api_type == 'folder': encoded_id = 'F' + encoded_id # Check whether user can modify current folder can_modify = False if trans.user_is_admin(): can_modify = True elif trans.user: can_modify = trans.app.security_agent.can_modify_library_item( current_user_roles, folder ) return_item.update( dict( can_modify=can_modify ) ) if content_item.api_type == 'file': # Is the dataset public or private? # When both are False the dataset is 'restricted' is_private = False is_unrestricted = False if trans.app.security_agent.dataset_is_public( content_item.library_dataset_dataset_association.dataset ): is_unrestricted = True else: is_unrestricted = False if trans.user: is_private = trans.app.security_agent.dataset_is_private_to_user( trans, content_item ) # Can user manage the permissions on the dataset? can_manage = False if trans.user_is_admin(): can_manage = True elif trans.user: can_manage = trans.app.security_agent.can_manage_dataset( current_user_roles, content_item.library_dataset_dataset_association.dataset ) nice_size = util.nice_size( int( content_item.library_dataset_dataset_association.get_size() ) ) library_dataset_dict = content_item.to_dict() return_item.update( dict( data_type=library_dataset_dict[ 'data_type' ], date_uploaded=library_dataset_dict[ 'date_uploaded' ], is_unrestricted=is_unrestricted, is_private=is_private, can_manage=can_manage, file_size=nice_size ) ) # For every item include the default meta-data return_item.update( dict( id=encoded_id, type=content_item.api_type, name=content_item.name, update_time=update_time, create_time=create_time, deleted=content_item.deleted ) ) folder_contents.append( return_item ) # Return the reversed path so it starts with the library node. full_path = self.build_path( trans, folder )[ ::-1 ] # Check whether user can add items to the current folder can_add_library_item = trans.user_is_admin() or trans.app.security_agent.can_add_library_item( current_user_roles, folder ) # Check whether user can modify current folder can_modify_folder = trans.app.security_agent.can_modify_library_item( current_user_roles, folder ) metadata = dict( full_path=full_path, can_add_library_item=can_add_library_item, can_modify_folder=can_modify_folder ) folder_container = dict( metadata=metadata, folder_contents=folder_contents ) return folder_container
def update(self, trans, id, **kwd): """ * PATCH /api/libraries/{encoded_id} Updates the library defined by an ``encoded_id`` with the data in the payload. .. note:: Currently, only admin users can update libraries. Also the library must not be `deleted`. :param id: the encoded id of the library :type id: an encoded id string :param payload: (required) dictionary structure containing:: 'name': new library's name, cannot be empty 'description': new library's description 'synopsis': new library's synopsis :type payload: dict :returns: detailed library information :rtype: dict :raises: ItemAccessibilityException, MalformedId, ObjectNotFound, RequestParameterInvalidException, RequestParameterMissingException """ if not trans.user_is_admin(): raise exceptions.ItemAccessibilityException( 'Only administrators can update libraries.') try: decoded_id = trans.security.decode_id(id) except Exception: raise exceptions.MalformedId( 'Malformed library id ( %s ) specified, unable to decode.' % id) library = None try: library = trans.sa_session.query( trans.app.model.Library).get(decoded_id) except Exception: library = None if not library: raise exceptions.ObjectNotFound( 'Library with the id provided ( %s ) was not found' % id) if library.deleted: raise exceptions.RequestParameterInvalidException( 'You cannot modify a deleted library. Undelete it first.') payload = kwd.get('payload', None) if payload: name = payload.get('name', None) if name == '': raise exceptions.RequestParameterMissingException( "Parameter 'name' of library is required. You cannot remove it." ) library.name = name if payload.get('description', None) or payload.get( 'description', None) == '': library.description = payload.get('description', None) if payload.get('synopsis', None) or payload.get('synopsis', None) == '': library.synopsis = payload.get('synopsis', None) else: raise exceptions.RequestParameterMissingException( "You did not specify any payload.") trans.sa_session.add(library) trans.sa_session.flush() return library.to_dict(view='element', value_mapper={ 'id': trans.security.encode_id, 'root_folder_id': trans.security.encode_id })
def __decode_id(trans, workflow_id, model_type="workflow"): try: return trans.security.decode_id(workflow_id) except Exception: message = f"Malformed {model_type} id ( {workflow_id} ) specified, unable to decode" raise exceptions.MalformedId(message)