Exemple #1
0
    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 '')
Exemple #2
0
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))
Exemple #5
0
    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')
Exemple #7
0
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))
Exemple #8
0
 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
Exemple #9
0
 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
Exemple #10
0
 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
Exemple #11
0
 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
Exemple #12
0
    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
                               })
Exemple #13
0
 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
Exemple #14
0
    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.')
Exemple #15
0
    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
                               })
Exemple #16
0
 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
Exemple #17
0
    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
Exemple #19
0
    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
                               })
Exemple #20
0
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)